graphql 2.2.17 → 2.5.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install_generator.rb +46 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_resolver.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +3 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyzer.rb +90 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +263 -0
- data/lib/graphql/analysis/{ast/query_depth.rb → query_depth.rb} +23 -25
- data/lib/graphql/analysis/visitor.rb +280 -0
- data/lib/graphql/analysis.rb +95 -1
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/current.rb +57 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/subscriptions.rb +96 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +158 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
- data/lib/graphql/dataloader/active_record_source.rb +47 -0
- data/lib/graphql/dataloader/async_dataloader.rb +46 -19
- data/lib/graphql/dataloader/null_dataloader.rb +51 -10
- data/lib/graphql/dataloader/source.rb +20 -9
- data/lib/graphql/dataloader.rb +153 -45
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +23 -25
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +63 -5
- data/lib/graphql/execution/interpreter/runtime.rb +321 -222
- data/lib/graphql/execution/interpreter.rb +23 -30
- data/lib/graphql/execution/lookahead.rb +18 -11
- data/lib/graphql/execution/multiplex.rb +6 -5
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +6 -11
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +20 -17
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/document_from_schema_definition.rb +64 -35
- data/lib/graphql/language/lexer.rb +72 -42
- data/lib/graphql/language/nodes.rb +93 -52
- data/lib/graphql/language/parser.rb +168 -61
- data/lib/graphql/language/printer.rb +31 -15
- data/lib/graphql/language/sanitized_printer.rb +1 -1
- data/lib/graphql/language.rb +61 -1
- data/lib/graphql/pagination/connection.rb +1 -1
- data/lib/graphql/query/context/scoped_context.rb +1 -1
- data/lib/graphql/query/context.rb +46 -47
- data/lib/graphql/query/null_context.rb +3 -5
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query.rb +123 -69
- data/lib/graphql/railtie.rb +7 -0
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +26 -13
- data/lib/graphql/schema/always_visible.rb +7 -2
- data/lib/graphql/schema/argument.rb +57 -8
- data/lib/graphql/schema/build_from_definition.rb +116 -49
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive.rb +54 -2
- data/lib/graphql/schema/enum.rb +107 -24
- data/lib/graphql/schema/enum_value.rb +10 -2
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +134 -45
- data/lib/graphql/schema/field_extension.rb +1 -1
- data/lib/graphql/schema/has_single_input_argument.rb +6 -2
- data/lib/graphql/schema/input_object.rb +122 -64
- data/lib/graphql/schema/interface.rb +23 -5
- data/lib/graphql/schema/introspection_system.rb +6 -17
- data/lib/graphql/schema/late_bound_type.rb +4 -0
- data/lib/graphql/schema/list.rb +3 -3
- data/lib/graphql/schema/loader.rb +3 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
- data/lib/graphql/schema/member/has_arguments.rb +44 -58
- data/lib/graphql/schema/member/has_dataloader.rb +62 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +26 -6
- data/lib/graphql/schema/member/has_interfaces.rb +6 -6
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +25 -8
- data/lib/graphql/schema/printer.rb +1 -0
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
- data/lib/graphql/schema/resolver.rb +29 -23
- data/lib/graphql/schema/scalar.rb +1 -6
- data/lib/graphql/schema/subscription.rb +52 -6
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/required_validator.rb +92 -11
- data/lib/graphql/schema/validator.rb +3 -1
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +445 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +311 -0
- data/lib/graphql/schema/warden.rb +190 -20
- data/lib/graphql/schema.rb +695 -167
- data/lib/graphql/static_validation/all_rules.rb +2 -2
- data/lib/graphql/static_validation/base_visitor.rb +6 -5
- data/lib/graphql/static_validation/literal_validator.rb +4 -4
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- 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 +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +18 -2
- data/lib/graphql/static_validation/validator.rb +6 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +5 -3
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +13 -2
- data/lib/graphql/subscriptions/serialize.rb +1 -1
- data/lib/graphql/subscriptions.rb +7 -5
- data/lib/graphql/testing/helpers.rb +48 -16
- data/lib/graphql/testing/mock_action_cable.rb +111 -0
- data/lib/graphql/testing.rb +1 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +5 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
- data/lib/graphql/tracing/appsignal_trace.rb +32 -59
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +46 -162
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +141 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +47 -54
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +183 -37
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +818 -0
- data/lib/graphql/tracing/platform_tracing.rb +1 -1
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
- data/lib/graphql/tracing/prometheus_trace.rb +73 -73
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -58
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +64 -98
- data/lib/graphql/tracing/statsd_trace.rb +33 -45
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +111 -1
- data/lib/graphql/tracing.rb +31 -30
- data/lib/graphql/type_kinds.rb +2 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +12 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +11 -1
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/types.rb +18 -11
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +64 -54
- metadata +197 -22
- data/lib/graphql/analysis/ast/analyzer.rb +0 -91
- data/lib/graphql/analysis/ast/field_usage.rb +0 -82
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -182
- data/lib/graphql/analysis/ast/visitor.rb +0 -276
- data/lib/graphql/analysis/ast.rb +0 -94
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/trace.rb +0 -93
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
|
@@ -2,23 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
module GraphQL
|
|
4
4
|
class Dataloader
|
|
5
|
-
#
|
|
5
|
+
# GraphQL-Ruby uses this when Dataloader isn't enabled.
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
7
|
+
# It runs execution code inline and gathers lazy objects (eg. Promises)
|
|
8
|
+
# and resolves them during {#run}.
|
|
9
9
|
class NullDataloader < Dataloader
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def
|
|
10
|
+
def initialize(*)
|
|
11
|
+
@lazies_at_depth = Hash.new { |h,k| h[k] = [] }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def freeze
|
|
15
|
+
@lazies_at_depth.default_proc = nil
|
|
16
|
+
@lazies_at_depth.freeze
|
|
17
|
+
super
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def run(trace_query_lazy: nil)
|
|
21
|
+
with_trace_query_lazy(trace_query_lazy) do
|
|
22
|
+
while !@lazies_at_depth.empty?
|
|
23
|
+
smallest_depth = nil
|
|
24
|
+
@lazies_at_depth.each_key do |depth_key|
|
|
25
|
+
smallest_depth ||= depth_key
|
|
26
|
+
if depth_key < smallest_depth
|
|
27
|
+
smallest_depth = depth_key
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
if smallest_depth
|
|
32
|
+
lazies = @lazies_at_depth.delete(smallest_depth)
|
|
33
|
+
lazies.each(&:value) # resolve these Lazy instances
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def run_isolated
|
|
40
|
+
new_dl = self.class.new
|
|
41
|
+
res = nil
|
|
42
|
+
new_dl.append_job {
|
|
43
|
+
res = yield
|
|
44
|
+
}
|
|
45
|
+
new_dl.run
|
|
46
|
+
res
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def clear_cache; end
|
|
50
|
+
|
|
51
|
+
def yield(_source)
|
|
15
52
|
raise GraphQL::Error, "GraphQL::Dataloader is not running -- add `use GraphQL::Dataloader` to your schema to use Dataloader sources."
|
|
16
53
|
end
|
|
17
54
|
|
|
18
|
-
def append_job
|
|
19
|
-
yield
|
|
55
|
+
def append_job(callable = nil)
|
|
56
|
+
callable ? callable.call : yield
|
|
20
57
|
nil
|
|
21
58
|
end
|
|
59
|
+
|
|
60
|
+
def with(*)
|
|
61
|
+
raise GraphQL::Error, "GraphQL::Dataloader is not running -- add `use GraphQL::Dataloader` to your schema to use Dataloader sources."
|
|
62
|
+
end
|
|
22
63
|
end
|
|
23
64
|
end
|
|
24
65
|
end
|
|
@@ -21,7 +21,7 @@ module GraphQL
|
|
|
21
21
|
def request(value)
|
|
22
22
|
res_key = result_key_for(value)
|
|
23
23
|
if !@results.key?(res_key)
|
|
24
|
-
@pending[res_key] ||= value
|
|
24
|
+
@pending[res_key] ||= normalize_fetch_key(value)
|
|
25
25
|
end
|
|
26
26
|
Dataloader::Request.new(self, value)
|
|
27
27
|
end
|
|
@@ -35,12 +35,24 @@ module GraphQL
|
|
|
35
35
|
value
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
# Implement this method if varying values given to {load} (etc) should be consolidated
|
|
39
|
+
# or normalized before being handed off to your {fetch} implementation.
|
|
40
|
+
#
|
|
41
|
+
# This is different than {result_key_for} because _that_ method handles unification inside Dataloader's cache,
|
|
42
|
+
# but this method changes the value passed into {fetch}.
|
|
43
|
+
#
|
|
44
|
+
# @param value [Object] The value passed to {load}, {load_all}, {request}, or {request_all}
|
|
45
|
+
# @return [Object] The value given to {fetch}
|
|
46
|
+
def normalize_fetch_key(value)
|
|
47
|
+
value
|
|
48
|
+
end
|
|
49
|
+
|
|
38
50
|
# @return [Dataloader::Request] a pending request for a values from `keys`. Call `.load` on that object to wait for the results.
|
|
39
51
|
def request_all(values)
|
|
40
52
|
values.each do |v|
|
|
41
53
|
res_key = result_key_for(v)
|
|
42
54
|
if !@results.key?(res_key)
|
|
43
|
-
@pending[res_key] ||= v
|
|
55
|
+
@pending[res_key] ||= normalize_fetch_key(v)
|
|
44
56
|
end
|
|
45
57
|
end
|
|
46
58
|
Dataloader::RequestAll.new(self, values)
|
|
@@ -53,7 +65,7 @@ module GraphQL
|
|
|
53
65
|
if @results.key?(result_key)
|
|
54
66
|
result_for(result_key)
|
|
55
67
|
else
|
|
56
|
-
@pending[result_key] ||= value
|
|
68
|
+
@pending[result_key] ||= normalize_fetch_key(value)
|
|
57
69
|
sync([result_key])
|
|
58
70
|
result_for(result_key)
|
|
59
71
|
end
|
|
@@ -68,12 +80,12 @@ module GraphQL
|
|
|
68
80
|
k = result_key_for(v)
|
|
69
81
|
result_keys << k
|
|
70
82
|
if !@results.key?(k)
|
|
71
|
-
@pending[k] ||= v
|
|
83
|
+
@pending[k] ||= normalize_fetch_key(v)
|
|
72
84
|
pending_keys << k
|
|
73
85
|
end
|
|
74
86
|
}
|
|
75
87
|
|
|
76
|
-
if pending_keys.
|
|
88
|
+
if !pending_keys.empty?
|
|
77
89
|
sync(pending_keys)
|
|
78
90
|
end
|
|
79
91
|
|
|
@@ -93,14 +105,14 @@ module GraphQL
|
|
|
93
105
|
# Then run the batch and update the cache.
|
|
94
106
|
# @return [void]
|
|
95
107
|
def sync(pending_result_keys)
|
|
96
|
-
@dataloader.yield
|
|
108
|
+
@dataloader.yield(self)
|
|
97
109
|
iterations = 0
|
|
98
110
|
while pending_result_keys.any? { |key| !@results.key?(key) }
|
|
99
111
|
iterations += 1
|
|
100
112
|
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."
|
|
113
|
+
raise "#{self.class}#sync tried #{MAX_ITERATIONS} times to load pending keys (#{pending_result_keys}), but they still weren't loaded. There is likely a circular dependency#{@dataloader.fiber_limit ? " or `fiber_limit: #{@dataloader.fiber_limit}` is set too low" : ""}."
|
|
102
114
|
end
|
|
103
|
-
@dataloader.yield
|
|
115
|
+
@dataloader.yield(self)
|
|
104
116
|
end
|
|
105
117
|
nil
|
|
106
118
|
end
|
|
@@ -186,7 +198,6 @@ This key should have been loaded already. This is a bug in GraphQL::Dataloader,
|
|
|
186
198
|
ERR
|
|
187
199
|
end
|
|
188
200
|
result = @results[key]
|
|
189
|
-
|
|
190
201
|
if result.is_a?(StandardError)
|
|
191
202
|
# Dup it because the rescuer may modify it.
|
|
192
203
|
# (This happens for GraphQL::ExecutionErrors, at least)
|
data/lib/graphql/dataloader.rb
CHANGED
|
@@ -4,6 +4,8 @@ require "graphql/dataloader/null_dataloader"
|
|
|
4
4
|
require "graphql/dataloader/request"
|
|
5
5
|
require "graphql/dataloader/request_all"
|
|
6
6
|
require "graphql/dataloader/source"
|
|
7
|
+
require "graphql/dataloader/active_record_association_source"
|
|
8
|
+
require "graphql/dataloader/active_record_source"
|
|
7
9
|
|
|
8
10
|
module GraphQL
|
|
9
11
|
# This plugin supports Fiber-based concurrency, along with {GraphQL::Dataloader::Source}.
|
|
@@ -24,18 +26,23 @@ module GraphQL
|
|
|
24
26
|
#
|
|
25
27
|
class Dataloader
|
|
26
28
|
class << self
|
|
27
|
-
attr_accessor :default_nonblocking
|
|
29
|
+
attr_accessor :default_nonblocking, :default_fiber_limit
|
|
28
30
|
end
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def self.use(schema, nonblocking: nil)
|
|
33
|
-
schema.dataloader_class = if nonblocking
|
|
32
|
+
def self.use(schema, nonblocking: nil, fiber_limit: nil)
|
|
33
|
+
dataloader_class = if nonblocking
|
|
34
34
|
warn("`nonblocking: true` is deprecated from `GraphQL::Dataloader`, please use `GraphQL::Dataloader::AsyncDataloader` instead. Docs: https://graphql-ruby.org/dataloader/async_dataloader.")
|
|
35
|
-
|
|
35
|
+
Class.new(self) { self.default_nonblocking = true }
|
|
36
36
|
else
|
|
37
37
|
self
|
|
38
38
|
end
|
|
39
|
+
|
|
40
|
+
if fiber_limit
|
|
41
|
+
dataloader_class = Class.new(dataloader_class)
|
|
42
|
+
dataloader_class.default_fiber_limit = fiber_limit
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
schema.dataloader_class = dataloader_class
|
|
39
46
|
end
|
|
40
47
|
|
|
41
48
|
# Call the block with a Dataloader instance,
|
|
@@ -50,14 +57,19 @@ module GraphQL
|
|
|
50
57
|
result
|
|
51
58
|
end
|
|
52
59
|
|
|
53
|
-
def initialize(nonblocking: self.class.default_nonblocking)
|
|
60
|
+
def initialize(nonblocking: self.class.default_nonblocking, fiber_limit: self.class.default_fiber_limit)
|
|
54
61
|
@source_cache = Hash.new { |h, k| h[k] = {} }
|
|
55
62
|
@pending_jobs = []
|
|
56
63
|
if !nonblocking.nil?
|
|
57
64
|
@nonblocking = nonblocking
|
|
58
65
|
end
|
|
66
|
+
@fiber_limit = fiber_limit
|
|
67
|
+
@lazies_at_depth = Hash.new { |h, k| h[k] = [] }
|
|
59
68
|
end
|
|
60
69
|
|
|
70
|
+
# @return [Integer, nil]
|
|
71
|
+
attr_reader :fiber_limit
|
|
72
|
+
|
|
61
73
|
def nonblocking?
|
|
62
74
|
@nonblocking
|
|
63
75
|
end
|
|
@@ -69,10 +81,7 @@ module GraphQL
|
|
|
69
81
|
def get_fiber_variables
|
|
70
82
|
fiber_vars = {}
|
|
71
83
|
Thread.current.keys.each do |fiber_var_key|
|
|
72
|
-
|
|
73
|
-
if fiber_var_key != :__graphql_runtime_info
|
|
74
|
-
fiber_vars[fiber_var_key] = Thread.current[fiber_var_key]
|
|
75
|
-
end
|
|
84
|
+
fiber_vars[fiber_var_key] = Thread.current[fiber_var_key]
|
|
76
85
|
end
|
|
77
86
|
fiber_vars
|
|
78
87
|
end
|
|
@@ -88,6 +97,11 @@ module GraphQL
|
|
|
88
97
|
nil
|
|
89
98
|
end
|
|
90
99
|
|
|
100
|
+
# This method is called when Dataloader is finished using a fiber.
|
|
101
|
+
# Use it to perform any cleanup, such as releasing database connections (if required manually)
|
|
102
|
+
def cleanup_fiber
|
|
103
|
+
end
|
|
104
|
+
|
|
91
105
|
# Get a Source instance from this dataloader, for calling `.load(...)` or `.request(...)` on.
|
|
92
106
|
#
|
|
93
107
|
# @param source_class [Class<GraphQL::Dataloader::Source]
|
|
@@ -118,16 +132,19 @@ module GraphQL
|
|
|
118
132
|
# Dataloader will resume the fiber after the requested data has been loaded (by another Fiber).
|
|
119
133
|
#
|
|
120
134
|
# @return [void]
|
|
121
|
-
def yield
|
|
135
|
+
def yield(source = Fiber[:__graphql_current_dataloader_source])
|
|
136
|
+
trace = Fiber[:__graphql_current_multiplex]&.current_trace
|
|
137
|
+
trace&.dataloader_fiber_yield(source)
|
|
122
138
|
Fiber.yield
|
|
139
|
+
trace&.dataloader_fiber_resume(source)
|
|
123
140
|
nil
|
|
124
141
|
end
|
|
125
142
|
|
|
126
143
|
# @api private Nothing to see here
|
|
127
|
-
def append_job(&job)
|
|
144
|
+
def append_job(callable = nil, &job)
|
|
128
145
|
# Given a block, queue it up to be worked through when `#run` is called.
|
|
129
|
-
# (If the dataloader is already running,
|
|
130
|
-
@pending_jobs.push(job)
|
|
146
|
+
# (If the dataloader is already running, then a Fiber will pick this up later.)
|
|
147
|
+
@pending_jobs.push(callable || job)
|
|
131
148
|
nil
|
|
132
149
|
end
|
|
133
150
|
|
|
@@ -144,6 +161,10 @@ module GraphQL
|
|
|
144
161
|
def run_isolated
|
|
145
162
|
prev_queue = @pending_jobs
|
|
146
163
|
prev_pending_keys = {}
|
|
164
|
+
prev_lazies_at_depth = @lazies_at_depth
|
|
165
|
+
@lazies_at_depth = @lazies_at_depth.dup.clear
|
|
166
|
+
# Clear pending loads but keep already-cached records
|
|
167
|
+
# in case they are useful to the given block.
|
|
147
168
|
@source_cache.each do |source_class, batched_sources|
|
|
148
169
|
batched_sources.each do |batch_args, batched_source_instance|
|
|
149
170
|
if batched_source_instance.pending?
|
|
@@ -163,6 +184,7 @@ module GraphQL
|
|
|
163
184
|
res
|
|
164
185
|
ensure
|
|
165
186
|
@pending_jobs = prev_queue
|
|
187
|
+
@lazies_at_depth = prev_lazies_at_depth
|
|
166
188
|
prev_pending_keys.each do |source_instance, pending|
|
|
167
189
|
pending.each do |key, value|
|
|
168
190
|
if !source_instance.results.key?(key)
|
|
@@ -172,38 +194,31 @@ module GraphQL
|
|
|
172
194
|
end
|
|
173
195
|
end
|
|
174
196
|
|
|
175
|
-
|
|
197
|
+
# @param trace_query_lazy [nil, Execution::Multiplex]
|
|
198
|
+
def run(trace_query_lazy: nil)
|
|
199
|
+
trace = Fiber[:__graphql_current_multiplex]&.current_trace
|
|
200
|
+
jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit
|
|
176
201
|
job_fibers = []
|
|
177
202
|
next_job_fibers = []
|
|
178
203
|
source_fibers = []
|
|
179
204
|
next_source_fibers = []
|
|
180
205
|
first_pass = true
|
|
181
206
|
manager = spawn_fiber do
|
|
182
|
-
|
|
207
|
+
trace&.begin_dataloader(self)
|
|
208
|
+
while first_pass || !job_fibers.empty?
|
|
183
209
|
first_pass = false
|
|
184
210
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
join_queues(job_fibers, next_job_fibers)
|
|
194
|
-
|
|
195
|
-
while source_fibers.any? || @source_cache.each_value.any? { |group_sources| group_sources.each_value.any?(&:pending?) }
|
|
196
|
-
while (f = source_fibers.shift || spawn_source_fiber)
|
|
197
|
-
if f.alive?
|
|
198
|
-
finished = run_fiber(f)
|
|
199
|
-
if !finished
|
|
200
|
-
next_source_fibers << f
|
|
201
|
-
end
|
|
202
|
-
end
|
|
211
|
+
run_pending_steps(trace, job_fibers, next_job_fibers, jobs_fiber_limit, source_fibers, next_source_fibers, total_fiber_limit)
|
|
212
|
+
|
|
213
|
+
if !@lazies_at_depth.empty?
|
|
214
|
+
with_trace_query_lazy(trace_query_lazy) do
|
|
215
|
+
run_next_pending_lazies(job_fibers, trace)
|
|
216
|
+
run_pending_steps(trace, job_fibers, next_job_fibers, jobs_fiber_limit, source_fibers, next_source_fibers, total_fiber_limit)
|
|
203
217
|
end
|
|
204
|
-
join_queues(source_fibers, next_source_fibers)
|
|
205
218
|
end
|
|
206
219
|
end
|
|
220
|
+
|
|
221
|
+
trace&.end_dataloader(self)
|
|
207
222
|
end
|
|
208
223
|
|
|
209
224
|
run_fiber(manager)
|
|
@@ -212,12 +227,13 @@ module GraphQL
|
|
|
212
227
|
raise "Invariant: Manager fiber didn't terminate properly."
|
|
213
228
|
end
|
|
214
229
|
|
|
215
|
-
if job_fibers.
|
|
230
|
+
if !job_fibers.empty?
|
|
216
231
|
raise "Invariant: job fibers should have exited but #{job_fibers.size} remained"
|
|
217
232
|
end
|
|
218
|
-
if source_fibers.
|
|
233
|
+
if !source_fibers.empty?
|
|
219
234
|
raise "Invariant: source fibers should have exited but #{source_fibers.size} remained"
|
|
220
235
|
end
|
|
236
|
+
|
|
221
237
|
rescue UncaughtThrowError => e
|
|
222
238
|
throw e.tag, e.value
|
|
223
239
|
end
|
|
@@ -226,36 +242,121 @@ module GraphQL
|
|
|
226
242
|
f.resume
|
|
227
243
|
end
|
|
228
244
|
|
|
245
|
+
# @api private
|
|
246
|
+
def lazy_at_depth(depth, lazy)
|
|
247
|
+
@lazies_at_depth[depth] << lazy
|
|
248
|
+
end
|
|
249
|
+
|
|
229
250
|
def spawn_fiber
|
|
230
251
|
fiber_vars = get_fiber_variables
|
|
231
252
|
Fiber.new(blocking: !@nonblocking) {
|
|
232
253
|
set_fiber_variables(fiber_vars)
|
|
233
254
|
yield
|
|
234
|
-
|
|
235
|
-
# if the fiber is allowed to terminate normally, control is passed to the main fiber instead.
|
|
236
|
-
true
|
|
255
|
+
cleanup_fiber
|
|
237
256
|
}
|
|
238
257
|
end
|
|
239
258
|
|
|
259
|
+
# Pre-warm the Dataloader cache with ActiveRecord objects which were loaded elsewhere.
|
|
260
|
+
# These will be used by {Dataloader::ActiveRecordSource}, {Dataloader::ActiveRecordAssociationSource} and their helper
|
|
261
|
+
# methods, `dataload_record` and `dataload_association`.
|
|
262
|
+
# @param records [Array<ActiveRecord::Base>] Already-loaded records to warm the cache with
|
|
263
|
+
# @param index_by [Symbol] The attribute to use as the cache key. (Should match `find_by:` when using {ActiveRecordSource})
|
|
264
|
+
# @return [void]
|
|
265
|
+
def merge_records(records, index_by: :id)
|
|
266
|
+
records_by_class = Hash.new { |h, k| h[k] = {} }
|
|
267
|
+
records.each do |r|
|
|
268
|
+
records_by_class[r.class][r.public_send(index_by)] = r
|
|
269
|
+
end
|
|
270
|
+
records_by_class.each do |r_class, records|
|
|
271
|
+
with(ActiveRecordSource, r_class).merge(records)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
240
275
|
private
|
|
241
276
|
|
|
277
|
+
def run_next_pending_lazies(job_fibers, trace)
|
|
278
|
+
smallest_depth = nil
|
|
279
|
+
@lazies_at_depth.each_key do |depth_key|
|
|
280
|
+
smallest_depth ||= depth_key
|
|
281
|
+
if depth_key < smallest_depth
|
|
282
|
+
smallest_depth = depth_key
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
if smallest_depth
|
|
287
|
+
lazies = @lazies_at_depth.delete(smallest_depth)
|
|
288
|
+
if !lazies.empty?
|
|
289
|
+
lazies.each_with_index do |l, idx|
|
|
290
|
+
append_job { l.value }
|
|
291
|
+
end
|
|
292
|
+
job_fibers.unshift(spawn_job_fiber(trace))
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def run_pending_steps(trace, job_fibers, next_job_fibers, jobs_fiber_limit, source_fibers, next_source_fibers, total_fiber_limit)
|
|
298
|
+
while (f = (job_fibers.shift || (((next_job_fibers.size + job_fibers.size) < jobs_fiber_limit) && spawn_job_fiber(trace))))
|
|
299
|
+
if f.alive?
|
|
300
|
+
finished = run_fiber(f)
|
|
301
|
+
if !finished
|
|
302
|
+
next_job_fibers << f
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
join_queues(job_fibers, next_job_fibers)
|
|
307
|
+
|
|
308
|
+
while (!source_fibers.empty? || @source_cache.each_value.any? { |group_sources| group_sources.each_value.any?(&:pending?) })
|
|
309
|
+
while (f = source_fibers.shift || (((job_fibers.size + source_fibers.size + next_source_fibers.size + next_job_fibers.size) < total_fiber_limit) && spawn_source_fiber(trace)))
|
|
310
|
+
if f.alive?
|
|
311
|
+
finished = run_fiber(f)
|
|
312
|
+
if !finished
|
|
313
|
+
next_source_fibers << f
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
join_queues(source_fibers, next_source_fibers)
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def with_trace_query_lazy(multiplex_or_nil, &block)
|
|
322
|
+
if (multiplex = multiplex_or_nil)
|
|
323
|
+
query = multiplex.queries.length == 1 ? multiplex.queries[0] : nil
|
|
324
|
+
multiplex.current_trace.execute_query_lazy(query: query, multiplex: multiplex, &block)
|
|
325
|
+
else
|
|
326
|
+
yield
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def calculate_fiber_limit
|
|
331
|
+
total_fiber_limit = @fiber_limit || Float::INFINITY
|
|
332
|
+
if total_fiber_limit < 4
|
|
333
|
+
raise ArgumentError, "Dataloader fiber limit is too low (#{total_fiber_limit}), it must be at least 4"
|
|
334
|
+
end
|
|
335
|
+
total_fiber_limit -= 1 # deduct one fiber for `manager`
|
|
336
|
+
# Deduct at least one fiber for sources
|
|
337
|
+
jobs_fiber_limit = total_fiber_limit - 2
|
|
338
|
+
return jobs_fiber_limit, total_fiber_limit
|
|
339
|
+
end
|
|
340
|
+
|
|
242
341
|
def join_queues(prev_queue, new_queue)
|
|
243
342
|
@nonblocking && Fiber.scheduler.run
|
|
244
343
|
prev_queue.concat(new_queue)
|
|
245
344
|
new_queue.clear
|
|
246
345
|
end
|
|
247
346
|
|
|
248
|
-
def spawn_job_fiber
|
|
249
|
-
if
|
|
347
|
+
def spawn_job_fiber(trace)
|
|
348
|
+
if !@pending_jobs.empty?
|
|
250
349
|
spawn_fiber do
|
|
350
|
+
trace&.dataloader_spawn_execution_fiber(@pending_jobs)
|
|
251
351
|
while job = @pending_jobs.shift
|
|
252
352
|
job.call
|
|
253
353
|
end
|
|
354
|
+
trace&.dataloader_fiber_exit
|
|
254
355
|
end
|
|
255
356
|
end
|
|
256
357
|
end
|
|
257
358
|
|
|
258
|
-
def spawn_source_fiber
|
|
359
|
+
def spawn_source_fiber(trace)
|
|
259
360
|
pending_sources = nil
|
|
260
361
|
@source_cache.each_value do |source_by_batch_params|
|
|
261
362
|
source_by_batch_params.each_value do |source|
|
|
@@ -268,7 +369,14 @@ module GraphQL
|
|
|
268
369
|
|
|
269
370
|
if pending_sources
|
|
270
371
|
spawn_fiber do
|
|
271
|
-
pending_sources
|
|
372
|
+
trace&.dataloader_spawn_source_fiber(pending_sources)
|
|
373
|
+
pending_sources.each do |source|
|
|
374
|
+
Fiber[:__graphql_current_dataloader_source] = source
|
|
375
|
+
trace&.begin_dataloader_source(source)
|
|
376
|
+
source.run_pending_keys
|
|
377
|
+
trace&.end_dataloader_source(source)
|
|
378
|
+
end
|
|
379
|
+
trace&.dataloader_fiber_exit
|
|
272
380
|
end
|
|
273
381
|
end
|
|
274
382
|
end
|
|
@@ -10,7 +10,7 @@ module GraphQL
|
|
|
10
10
|
|
|
11
11
|
def initialize(value)
|
|
12
12
|
@date_value = value
|
|
13
|
-
super("Date cannot be parsed: #{value}. \nDate must be
|
|
13
|
+
super("Date cannot be parsed: #{value}. \nDate must be able to be parsed as a Ruby Date object.")
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
end
|
data/lib/graphql/dig.rb
CHANGED
|
@@ -5,7 +5,8 @@ module GraphQL
|
|
|
5
5
|
# so we can use some of the magic in Schema::InputObject and Interpreter::Arguments
|
|
6
6
|
# to handle stringified/symbolized keys.
|
|
7
7
|
#
|
|
8
|
-
# @param
|
|
8
|
+
# @param own_key [String, Symbol] A key to retrieve
|
|
9
|
+
# @param rest_keys [Array<[String, Symbol>] Retrieves the value object corresponding to the each key objects repeatedly
|
|
9
10
|
# @return [Object]
|
|
10
11
|
def dig(own_key, *rest_keys)
|
|
11
12
|
val = self[own_key]
|
|
@@ -6,15 +6,19 @@ module GraphQL
|
|
|
6
6
|
# A container for metadata regarding arguments present in a GraphQL query.
|
|
7
7
|
# @see Interpreter::Arguments#argument_values for a hash of these objects.
|
|
8
8
|
class ArgumentValue
|
|
9
|
-
def initialize(definition:, value:, default_used:)
|
|
9
|
+
def initialize(definition:, value:, original_value:, default_used:)
|
|
10
10
|
@definition = definition
|
|
11
11
|
@value = value
|
|
12
|
+
@original_value = original_value
|
|
12
13
|
@default_used = default_used
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
# @return [Object] The Ruby-ready value for this Argument
|
|
16
17
|
attr_reader :value
|
|
17
18
|
|
|
19
|
+
# @return [Object] The value of this argument _before_ `prepare` is applied.
|
|
20
|
+
attr_reader :original_value
|
|
21
|
+
|
|
18
22
|
# @return [GraphQL::Schema::Argument] The definition instance for this argument
|
|
19
23
|
attr_reader :definition
|
|
20
24
|
|
|
@@ -8,22 +8,17 @@ module GraphQL
|
|
|
8
8
|
@query = query
|
|
9
9
|
@dataloader = query.context.dataloader
|
|
10
10
|
@storage = Hash.new do |h, argument_owner|
|
|
11
|
-
|
|
11
|
+
h[argument_owner] = if argument_owner.arguments_statically_coercible?
|
|
12
12
|
shared_values_cache = {}
|
|
13
13
|
Hash.new do |h2, ignored_parent_object|
|
|
14
14
|
h2[ignored_parent_object] = shared_values_cache
|
|
15
|
-
end
|
|
15
|
+
end.compare_by_identity
|
|
16
16
|
else
|
|
17
17
|
Hash.new do |h2, parent_object|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
h2[parent_object] = args_by_node
|
|
21
|
-
end
|
|
18
|
+
h2[parent_object] = {}.compare_by_identity
|
|
19
|
+
end.compare_by_identity
|
|
22
20
|
end
|
|
23
|
-
|
|
24
|
-
h[argument_owner] = args_by_parent
|
|
25
|
-
end
|
|
26
|
-
@storage.compare_by_identity
|
|
21
|
+
end.compare_by_identity
|
|
27
22
|
end
|
|
28
23
|
|
|
29
24
|
def fetch(ast_node, argument_owner, parent_object)
|
|
@@ -6,22 +6,31 @@ module GraphQL
|
|
|
6
6
|
module Resolve
|
|
7
7
|
# Continue field results in `results` until there's nothing else to continue.
|
|
8
8
|
# @return [void]
|
|
9
|
+
# @deprecated Call `dataloader.run` instead
|
|
9
10
|
def self.resolve_all(results, dataloader)
|
|
11
|
+
warn "#{self}.#{__method__} is deprecated; Use `dataloader.run` instead.#{caller(1, 5).map { |l| "\n #{l}"}.join}"
|
|
10
12
|
dataloader.append_job { resolve(results, dataloader) }
|
|
11
13
|
nil
|
|
12
14
|
end
|
|
13
15
|
|
|
16
|
+
# @deprecated Call `dataloader.run` instead
|
|
14
17
|
def self.resolve_each_depth(lazies_at_depth, dataloader)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
warn "#{self}.#{__method__} is deprecated; Use `dataloader.run` instead.#{caller(1, 5).map { |l| "\n #{l}"}.join}"
|
|
19
|
+
|
|
20
|
+
smallest_depth = nil
|
|
21
|
+
lazies_at_depth.each_key do |depth_key|
|
|
22
|
+
smallest_depth ||= depth_key
|
|
23
|
+
if depth_key < smallest_depth
|
|
24
|
+
smallest_depth = depth_key
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if smallest_depth
|
|
29
|
+
lazies = lazies_at_depth.delete(smallest_depth)
|
|
30
|
+
if !lazies.empty?
|
|
31
|
+
lazies.each do |l|
|
|
32
|
+
dataloader.append_job { l.value }
|
|
33
|
+
end
|
|
25
34
|
# Run lazies _and_ dataloader, see if more are enqueued
|
|
26
35
|
dataloader.run
|
|
27
36
|
resolve_each_depth(lazies_at_depth, dataloader)
|
|
@@ -30,20 +39,9 @@ module GraphQL
|
|
|
30
39
|
nil
|
|
31
40
|
end
|
|
32
41
|
|
|
33
|
-
#
|
|
34
|
-
# continue it until you get a response-ready Ruby value.
|
|
35
|
-
#
|
|
36
|
-
# `results` is one level of _depth_ of a query or multiplex.
|
|
37
|
-
#
|
|
38
|
-
# Resolve all lazy values in that depth before moving on
|
|
39
|
-
# to the next level.
|
|
40
|
-
#
|
|
41
|
-
# It's assumed that the lazies will
|
|
42
|
-
# return {Lazy} instances if there's more work to be done,
|
|
43
|
-
# or return {Hash}/{Array} if the query should be continued.
|
|
44
|
-
#
|
|
45
|
-
# @return [void]
|
|
42
|
+
# @deprecated Call `dataloader.run` instead
|
|
46
43
|
def self.resolve(results, dataloader)
|
|
44
|
+
warn "#{self}.#{__method__} is deprecated; Use `dataloader.run` instead.#{caller(1, 5).map { |l| "\n #{l}"}.join}"
|
|
47
45
|
# There might be pending jobs here that _will_ write lazies
|
|
48
46
|
# into the result hash. We should run them out, so we
|
|
49
47
|
# can be sure that all lazies will be present in the result hashes.
|
|
@@ -51,7 +49,7 @@ module GraphQL
|
|
|
51
49
|
# these approaches.
|
|
52
50
|
dataloader.run
|
|
53
51
|
next_results = []
|
|
54
|
-
while results.
|
|
52
|
+
while !results.empty?
|
|
55
53
|
result_value = results.shift
|
|
56
54
|
if result_value.is_a?(Runtime::GraphQLResultHash) || result_value.is_a?(Hash)
|
|
57
55
|
results.concat(result_value.values)
|
|
@@ -77,7 +75,7 @@ module GraphQL
|
|
|
77
75
|
end
|
|
78
76
|
end
|
|
79
77
|
|
|
80
|
-
if next_results.
|
|
78
|
+
if !next_results.empty?
|
|
81
79
|
# Any pending data loader jobs may populate the
|
|
82
80
|
# resutl arrays or result hashes accumulated in
|
|
83
81
|
# `next_results``. Run those **to completion**
|