graphql 2.0.21 → 2.0.32
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/mutation_delete_generator.rb +1 -1
- data/lib/generators/graphql/mutation_update_generator.rb +1 -1
- data/lib/generators/graphql/relay.rb +18 -1
- data/lib/graphql/backtrace.rb +0 -4
- data/lib/graphql/dataloader/source.rb +69 -45
- data/lib/graphql/dataloader.rb +4 -4
- data/lib/graphql/execution/interpreter/arguments_cache.rb +31 -30
- data/lib/graphql/execution/interpreter/runtime.rb +122 -101
- data/lib/graphql/execution/interpreter.rb +1 -2
- data/lib/graphql/execution/lookahead.rb +1 -1
- data/lib/graphql/filter.rb +2 -1
- data/lib/graphql/introspection/entry_points.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +16 -9
- data/lib/graphql/language/lexer.rb +89 -57
- data/lib/graphql/language/nodes.rb +3 -0
- data/lib/graphql/language/parser.rb +706 -691
- data/lib/graphql/language/parser.y +1 -0
- data/lib/graphql/language/printer.rb +28 -14
- data/lib/graphql/language/visitor.rb +64 -61
- data/lib/graphql/query/context.rb +16 -7
- data/lib/graphql/query/null_context.rb +8 -18
- data/lib/graphql/query/validation_pipeline.rb +2 -1
- data/lib/graphql/query.rb +37 -12
- data/lib/graphql/schema/addition.rb +38 -12
- data/lib/graphql/schema/always_visible.rb +10 -0
- data/lib/graphql/schema/argument.rb +8 -10
- data/lib/graphql/schema/build_from_definition.rb +8 -7
- data/lib/graphql/schema/directive.rb +1 -1
- data/lib/graphql/schema/enum_value.rb +2 -2
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +26 -15
- data/lib/graphql/schema/input_object.rb +9 -7
- data/lib/graphql/schema/interface.rb +5 -1
- data/lib/graphql/schema/introspection_system.rb +1 -1
- data/lib/graphql/schema/member/build_type.rb +10 -2
- data/lib/graphql/schema/member/has_arguments.rb +9 -7
- data/lib/graphql/schema/member/has_directives.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +1 -1
- data/lib/graphql/schema/member/has_interfaces.rb +1 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema/object.rb +6 -1
- data/lib/graphql/schema/printer.rb +3 -1
- data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
- data/lib/graphql/schema/resolver.rb +12 -10
- data/lib/graphql/schema/timeout.rb +1 -1
- data/lib/graphql/schema/validator.rb +1 -1
- data/lib/graphql/schema/warden.rb +37 -4
- data/lib/graphql/schema.rb +92 -23
- data/lib/graphql/tracing/appoptics_trace.rb +35 -11
- data/lib/graphql/tracing/appsignal_trace.rb +4 -0
- data/lib/graphql/tracing/data_dog_trace.rb +89 -50
- data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
- data/lib/graphql/tracing/legacy_trace.rb +5 -1
- data/lib/graphql/tracing/notifications_trace.rb +7 -0
- data/lib/graphql/tracing/platform_trace.rb +26 -12
- data/lib/graphql/tracing/prometheus_trace.rb +4 -0
- data/lib/graphql/tracing/scout_trace.rb +3 -0
- data/lib/graphql/tracing/statsd_trace.rb +4 -0
- data/lib/graphql/tracing.rb +1 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +1 -1
- data/lib/graphql/types/relay/edge_behaviors.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/readme.md +1 -1
- metadata +36 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c86c6f3920de2d67a9d8b23a2783ec33f15b70571236db184ca9a9e6b459b80b
|
4
|
+
data.tar.gz: 6f4659f46b99da5c6065ba7084b899253958bdb5627b65f469262898cb38205c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02bf27d69ec35ecdad618ed18a7731fe7d66cd1b5105fcc7625e7b68f534b31e7e5b6f458ba1efe22b5f6e9e6d819cc696e7cdeba6e80bbfa3259691d9ede441
|
7
|
+
data.tar.gz: 5b91453bbc8e01a72bcfbe5cef21e7f65704ff1976d945c01291e48667a4a1f36e35f690048ba2a029d5c9f019cfa9c72fa46b2f851b422117de48a4722152ec
|
@@ -6,7 +6,7 @@ module Graphql
|
|
6
6
|
# TODO: What other options should be supported?
|
7
7
|
#
|
8
8
|
# @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
|
9
|
-
# rails g graphql:mutation
|
9
|
+
# rails g graphql:mutation DeletePostMutation
|
10
10
|
class MutationDeleteGenerator < OrmMutationsBase
|
11
11
|
|
12
12
|
desc "Scaffold a Relay Classic ORM delete mutation for the given model class"
|
@@ -6,7 +6,7 @@ module Graphql
|
|
6
6
|
# TODO: What other options should be supported?
|
7
7
|
#
|
8
8
|
# @example Generate a `GraphQL::Schema::RelayClassicMutation` by name
|
9
|
-
# rails g graphql:mutation
|
9
|
+
# rails g graphql:mutation UpdatePostMutation
|
10
10
|
class MutationUpdateGenerator < OrmMutationsBase
|
11
11
|
|
12
12
|
desc "Scaffold a Relay Classic ORM update mutation for the given model class"
|
@@ -6,7 +6,24 @@ module Graphql
|
|
6
6
|
# Add Node, `node(id:)`, and `nodes(ids:)`
|
7
7
|
template("node_type.erb", "#{options[:directory]}/types/node_type.rb")
|
8
8
|
in_root do
|
9
|
-
fields =
|
9
|
+
fields = <<-RUBY
|
10
|
+
field :node, Types::NodeType, null: true, description: "Fetches an object given its ID." do
|
11
|
+
argument :id, ID, required: true, description: "ID of the object."
|
12
|
+
end
|
13
|
+
|
14
|
+
def node(id:)
|
15
|
+
context.schema.object_from_id(id, context)
|
16
|
+
end
|
17
|
+
|
18
|
+
field :nodes, [Types::NodeType, null: true], null: true, description: "Fetches a list of objects given a list of IDs." do
|
19
|
+
argument :ids, [ID], required: true, description: "IDs of the objects."
|
20
|
+
end
|
21
|
+
|
22
|
+
def nodes(ids:)
|
23
|
+
ids.map { |id| context.schema.object_from_id(id, context) }
|
24
|
+
end
|
25
|
+
|
26
|
+
RUBY
|
10
27
|
inject_into_file "#{options[:directory]}/types/query_type.rb", fields, after: /class .*QueryType\s*<\s*[^\s]+?\n/m, force: false
|
11
28
|
end
|
12
29
|
|
data/lib/graphql/backtrace.rb
CHANGED
@@ -7,9 +7,9 @@ module GraphQL
|
|
7
7
|
# @api private
|
8
8
|
def setup(dataloader)
|
9
9
|
# These keys have been requested but haven't been fetched yet
|
10
|
-
@
|
10
|
+
@pending = {}
|
11
11
|
# These keys have been passed to `fetch` but haven't been finished yet
|
12
|
-
@
|
12
|
+
@fetching = {}
|
13
13
|
# { key => result }
|
14
14
|
@results = {}
|
15
15
|
@dataloader = dataloader
|
@@ -18,42 +18,66 @@ module GraphQL
|
|
18
18
|
attr_reader :dataloader
|
19
19
|
|
20
20
|
# @return [Dataloader::Request] a pending request for a value from `key`. Call `.load` on that object to wait for the result.
|
21
|
-
def request(
|
22
|
-
|
23
|
-
|
21
|
+
def request(value)
|
22
|
+
res_key = result_key_for(value)
|
23
|
+
if !@results.key?(res_key)
|
24
|
+
@pending[res_key] ||= value
|
24
25
|
end
|
25
|
-
Dataloader::Request.new(self,
|
26
|
+
Dataloader::Request.new(self, value)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Implement this method to return a stable identifier if different
|
30
|
+
# key objects should load the same data value.
|
31
|
+
#
|
32
|
+
# @param value [Object] A value passed to `.request` or `.load`, for which a value will be loaded
|
33
|
+
# @return [Object] The key for tracking this pending data
|
34
|
+
def result_key_for(value)
|
35
|
+
value
|
26
36
|
end
|
27
37
|
|
28
38
|
# @return [Dataloader::Request] a pending request for a values from `keys`. Call `.load` on that object to wait for the results.
|
29
|
-
def request_all(
|
30
|
-
|
31
|
-
|
32
|
-
|
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)
|
33
47
|
end
|
34
48
|
|
35
|
-
# @param
|
49
|
+
# @param value [Object] A loading value which will be passed to {#fetch} if it isn't already in the internal cache.
|
36
50
|
# @return [Object] The result from {#fetch} for `key`. If `key` hasn't been loaded yet, the Fiber will yield until it's loaded.
|
37
|
-
def load(
|
38
|
-
|
39
|
-
|
51
|
+
def load(value)
|
52
|
+
result_key = result_key_for(value)
|
53
|
+
if @results.key?(result_key)
|
54
|
+
result_for(result_key)
|
40
55
|
else
|
41
|
-
@
|
42
|
-
sync
|
43
|
-
result_for(
|
56
|
+
@pending[result_key] ||= value
|
57
|
+
sync([result_key])
|
58
|
+
result_for(result_key)
|
44
59
|
end
|
45
60
|
end
|
46
61
|
|
47
|
-
# @param
|
62
|
+
# @param values [Array<Object>] Loading keys which will be passed to `#fetch` (or read from the internal cache).
|
48
63
|
# @return [Object] The result from {#fetch} for `keys`. If `keys` haven't been loaded yet, the Fiber will yield until they're loaded.
|
49
|
-
def load_all(
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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.any?
|
77
|
+
sync(pending_keys)
|
54
78
|
end
|
55
79
|
|
56
|
-
|
80
|
+
result_keys.map { |k| result_for(k) }
|
57
81
|
end
|
58
82
|
|
59
83
|
# Subclasses must implement this method to return a value for each of `keys`
|
@@ -67,14 +91,13 @@ module GraphQL
|
|
67
91
|
# Wait for a batch, if there's anything to batch.
|
68
92
|
# Then run the batch and update the cache.
|
69
93
|
# @return [void]
|
70
|
-
def sync
|
71
|
-
pending_keys = @pending_keys.dup
|
94
|
+
def sync(pending_result_keys)
|
72
95
|
@dataloader.yield
|
73
96
|
iterations = 0
|
74
|
-
while
|
97
|
+
while pending_result_keys.any? { |key| !@results.key?(key) }
|
75
98
|
iterations += 1
|
76
99
|
if iterations > 1000
|
77
|
-
raise "#{self.class}#sync tried 1000 times to load pending keys (#{
|
100
|
+
raise "#{self.class}#sync tried 1000 times to load pending keys (#{pending_result_keys}), but they still weren't loaded. There is likely a circular dependency."
|
78
101
|
end
|
79
102
|
@dataloader.yield
|
80
103
|
end
|
@@ -83,15 +106,18 @@ module GraphQL
|
|
83
106
|
|
84
107
|
# @return [Boolean] True if this source has any pending requests for data.
|
85
108
|
def pending?
|
86
|
-
!@
|
109
|
+
!@pending.empty?
|
87
110
|
end
|
88
111
|
|
89
112
|
# Add these key-value pairs to this source's cache
|
90
113
|
# (future loads will use these merged values).
|
91
|
-
# @param
|
114
|
+
# @param new_results [Hash<Object => Object>] key-value pairs to cache in this source
|
92
115
|
# @return [void]
|
93
|
-
def merge(
|
94
|
-
|
116
|
+
def merge(new_results)
|
117
|
+
new_results.each do |new_k, new_v|
|
118
|
+
key = result_key_for(new_k)
|
119
|
+
@results[key] = new_v
|
120
|
+
end
|
95
121
|
nil
|
96
122
|
end
|
97
123
|
|
@@ -99,24 +125,22 @@ module GraphQL
|
|
99
125
|
# @api private
|
100
126
|
# @return [void]
|
101
127
|
def run_pending_keys
|
102
|
-
if !@
|
103
|
-
@
|
128
|
+
if !@fetching.empty?
|
129
|
+
@fetching.each_key { |k| @pending.delete(k) }
|
104
130
|
end
|
105
|
-
return if @
|
106
|
-
|
107
|
-
@
|
108
|
-
@
|
109
|
-
results = fetch(
|
110
|
-
|
131
|
+
return if @pending.empty?
|
132
|
+
fetch_h = @pending
|
133
|
+
@pending = {}
|
134
|
+
@fetching.merge!(fetch_h)
|
135
|
+
results = fetch(fetch_h.values)
|
136
|
+
fetch_h.each_with_index do |(key, _value), idx|
|
111
137
|
@results[key] = results[idx]
|
112
138
|
end
|
113
139
|
nil
|
114
140
|
rescue StandardError => error
|
115
|
-
|
141
|
+
fetch_h.each_key { |key| @results[key] = error }
|
116
142
|
ensure
|
117
|
-
|
118
|
-
@fetching_keys -= fetch_keys
|
119
|
-
end
|
143
|
+
fetch_h && fetch_h.each_key { |k| @fetching.delete(k) }
|
120
144
|
end
|
121
145
|
|
122
146
|
# These arguments are given to `dataloader.with(source_class, ...)`. The object
|
@@ -137,7 +161,7 @@ module GraphQL
|
|
137
161
|
[*batch_args, **batch_kwargs]
|
138
162
|
end
|
139
163
|
|
140
|
-
attr_reader :
|
164
|
+
attr_reader :pending
|
141
165
|
|
142
166
|
private
|
143
167
|
|
data/lib/graphql/dataloader.rb
CHANGED
@@ -111,8 +111,8 @@ module GraphQL
|
|
111
111
|
@source_cache.each do |source_class, batched_sources|
|
112
112
|
batched_sources.each do |batch_args, batched_source_instance|
|
113
113
|
if batched_source_instance.pending?
|
114
|
-
prev_pending_keys[batched_source_instance] = batched_source_instance.
|
115
|
-
batched_source_instance.
|
114
|
+
prev_pending_keys[batched_source_instance] = batched_source_instance.pending.dup
|
115
|
+
batched_source_instance.pending.clear
|
116
116
|
end
|
117
117
|
end
|
118
118
|
end
|
@@ -127,8 +127,8 @@ module GraphQL
|
|
127
127
|
res
|
128
128
|
ensure
|
129
129
|
@pending_jobs = prev_queue
|
130
|
-
prev_pending_keys.each do |source_instance,
|
131
|
-
source_instance.
|
130
|
+
prev_pending_keys.each do |source_instance, pending|
|
131
|
+
source_instance.pending.merge!(pending)
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
@@ -7,49 +7,50 @@ module GraphQL
|
|
7
7
|
def initialize(query)
|
8
8
|
@query = query
|
9
9
|
@dataloader = query.context.dataloader
|
10
|
-
@storage = Hash.new do |h,
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
h3[parent_object] = NO_ARGUMENTS
|
22
|
-
else
|
23
|
-
h3[parent_object]
|
24
|
-
end
|
10
|
+
@storage = Hash.new do |h, argument_owner|
|
11
|
+
args_by_parent = if argument_owner.arguments_statically_coercible?
|
12
|
+
shared_values_cache = {}
|
13
|
+
Hash.new do |h2, ignored_parent_object|
|
14
|
+
h2[ignored_parent_object] = shared_values_cache
|
15
|
+
end
|
16
|
+
else
|
17
|
+
Hash.new do |h2, parent_object|
|
18
|
+
args_by_node = {}
|
19
|
+
args_by_node.compare_by_identity
|
20
|
+
h2[parent_object] = args_by_node
|
25
21
|
end
|
26
22
|
end
|
23
|
+
args_by_parent.compare_by_identity
|
24
|
+
h[argument_owner] = args_by_parent
|
27
25
|
end
|
26
|
+
@storage.compare_by_identity
|
28
27
|
end
|
29
28
|
|
30
29
|
def fetch(ast_node, argument_owner, parent_object)
|
31
|
-
#
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@
|
36
|
-
@storage[
|
30
|
+
# This runs eagerly if no block is given
|
31
|
+
@storage[argument_owner][parent_object][ast_node] ||= begin
|
32
|
+
args_hash = self.class.prepare_args_hash(@query, ast_node)
|
33
|
+
kwarg_arguments = argument_owner.coerce_arguments(parent_object, args_hash, @query.context)
|
34
|
+
@query.after_lazy(kwarg_arguments) do |resolved_args|
|
35
|
+
@storage[argument_owner][parent_object][ast_node] = resolved_args
|
37
36
|
end
|
38
37
|
end
|
39
|
-
|
40
|
-
# overridden with an immutable arguments instance.
|
41
|
-
# The first call queues up the job,
|
42
|
-
# then this call fetches the result.
|
43
|
-
# TODO this should be better, find a solution
|
44
|
-
# that works with merging the runtime.rb code
|
45
|
-
@storage[ast_node][argument_owner][parent_object]
|
38
|
+
|
46
39
|
end
|
47
40
|
|
48
41
|
# @yield [Interpreter::Arguments, Lazy<Interpreter::Arguments>] The finally-loaded arguments
|
49
42
|
def dataload_for(ast_node, argument_owner, parent_object, &block)
|
50
43
|
# First, normalize all AST or Ruby values to a plain Ruby hash
|
51
|
-
|
52
|
-
|
44
|
+
arg_storage = @storage[argument_owner][parent_object]
|
45
|
+
if (args = arg_storage[ast_node])
|
46
|
+
yield(args)
|
47
|
+
else
|
48
|
+
args_hash = self.class.prepare_args_hash(@query, ast_node)
|
49
|
+
argument_owner.coerce_arguments(parent_object, args_hash, @query.context) do |resolved_args|
|
50
|
+
arg_storage[ast_node] = resolved_args
|
51
|
+
yield(resolved_args)
|
52
|
+
end
|
53
|
+
end
|
53
54
|
nil
|
54
55
|
end
|
55
56
|
|