graphql 2.0.23 → 2.0.25
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/mutation_delete_generator.rb +1 -1
- data/lib/generators/graphql/mutation_update_generator.rb +1 -1
- data/lib/graphql/dataloader/source.rb +69 -45
- data/lib/graphql/dataloader.rb +4 -4
- data/lib/graphql/execution/interpreter/runtime.rb +13 -19
- data/lib/graphql/introspection/entry_points.rb +1 -1
- data/lib/graphql/query/validation_pipeline.rb +2 -1
- data/lib/graphql/query.rb +16 -1
- data/lib/graphql/schema/addition.rb +32 -12
- data/lib/graphql/schema/field.rb +1 -1
- data/lib/graphql/schema/introspection_system.rb +1 -1
- data/lib/graphql/schema/member/build_type.rb +10 -2
- data/lib/graphql/schema/object.rb +5 -0
- data/lib/graphql/schema.rb +69 -15
- data/lib/graphql/tracing/appoptics_trace.rb +32 -12
- data/lib/graphql/tracing/data_dog_trace.rb +42 -17
- data/lib/graphql/tracing/platform_trace.rb +22 -13
- data/lib/graphql/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 289b06689b36a3673c053d13d2ce0835a089e92db60e3e24e8af791fdd934d81
|
4
|
+
data.tar.gz: 3c5257c0732d0729b97ac92376427ccba26ef66397f9b9d07c18e9792ea03251
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72ad503ed008aa168a63c1a40ac9e44dbb9b2d6a7871f1cd6191a692d6275506ce17f0df3135ae0a2ef95fe695a457d76239a2623f477cf7cd7f27cc124888c7
|
7
|
+
data.tar.gz: 90976b77a4230bf8a7d3fe5470deae70082e6caac1d3b30c799e958621cd2177283d0f83eb06128081e7e2179e33e718a1ba9353ab388fac83553e0988e7b4bc
|
@@ -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"
|
@@ -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
|
|
@@ -247,15 +247,15 @@ module GraphQL
|
|
247
247
|
st = get_current_runtime_state
|
248
248
|
st.current_object = query.root_value
|
249
249
|
st.current_result = @response
|
250
|
-
|
251
|
-
|
250
|
+
runtime_object = root_type.wrap(query.root_value, context)
|
251
|
+
runtime_object = schema.sync_lazy(runtime_object)
|
252
252
|
|
253
|
-
if
|
253
|
+
if runtime_object.nil?
|
254
254
|
# Root .authorized? returned false.
|
255
255
|
@response = nil
|
256
256
|
else
|
257
|
-
call_method_on_directives(:resolve,
|
258
|
-
gathered_selections = gather_selections(
|
257
|
+
call_method_on_directives(:resolve, runtime_object, root_operation.directives) do # execute query level directives
|
258
|
+
gathered_selections = gather_selections(runtime_object, root_type, root_operation.selections)
|
259
259
|
# This is kind of a hack -- `gathered_selections` is an Array if any of the selections
|
260
260
|
# require isolation during execution (because of runtime directives). In that case,
|
261
261
|
# make a new, isolated result hash for writing the result into. (That isolated response
|
@@ -280,9 +280,9 @@ module GraphQL
|
|
280
280
|
if (directives = selections[:graphql_directives])
|
281
281
|
selections.delete(:graphql_directives)
|
282
282
|
end
|
283
|
-
call_method_on_directives(:resolve,
|
283
|
+
call_method_on_directives(:resolve, runtime_object, directives) do
|
284
284
|
evaluate_selections(
|
285
|
-
|
285
|
+
runtime_object,
|
286
286
|
root_type,
|
287
287
|
root_op_type == "mutation",
|
288
288
|
selections,
|
@@ -438,10 +438,8 @@ module GraphQL
|
|
438
438
|
st.current_result = selections_result
|
439
439
|
st.current_result_name = result_name
|
440
440
|
|
441
|
-
object = owner_object
|
442
|
-
|
443
441
|
if is_introspection
|
444
|
-
|
442
|
+
owner_object = field_defn.owner.wrap(owner_object, context)
|
445
443
|
end
|
446
444
|
|
447
445
|
total_args_count = field_defn.arguments(context).size
|
@@ -449,14 +447,14 @@ module GraphQL
|
|
449
447
|
resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
|
450
448
|
if field_defn.extras.size == 0
|
451
449
|
evaluate_selection_with_resolved_keyword_args(
|
452
|
-
NO_ARGS, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type,
|
450
|
+
NO_ARGS, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, return_type_non_null
|
453
451
|
)
|
454
452
|
else
|
455
|
-
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type,
|
453
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, return_type_non_null)
|
456
454
|
end
|
457
455
|
else
|
458
|
-
@query.arguments_cache.dataload_for(ast_node, field_defn,
|
459
|
-
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type,
|
456
|
+
@query.arguments_cache.dataload_for(ast_node, field_defn, owner_object) do |resolved_arguments|
|
457
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, return_type_non_null)
|
460
458
|
end
|
461
459
|
end
|
462
460
|
end
|
@@ -774,7 +772,7 @@ module GraphQL
|
|
774
772
|
end
|
775
773
|
when "OBJECT"
|
776
774
|
object_proxy = begin
|
777
|
-
|
775
|
+
current_type.wrap(value, context)
|
778
776
|
rescue GraphQL::ExecutionError => err
|
779
777
|
err
|
780
778
|
end
|
@@ -1047,10 +1045,6 @@ module GraphQL
|
|
1047
1045
|
end
|
1048
1046
|
end
|
1049
1047
|
|
1050
|
-
def authorized_new(type, value, context)
|
1051
|
-
type.authorized_new(value, context)
|
1052
|
-
end
|
1053
|
-
|
1054
1048
|
def lazy?(object)
|
1055
1049
|
obj_class = object.class
|
1056
1050
|
is_lazy = @lazy_cache[obj_class]
|
@@ -11,7 +11,7 @@ module GraphQL
|
|
11
11
|
# Apply wrapping manually since this field isn't wrapped by instrumentation
|
12
12
|
schema = @context.query.schema
|
13
13
|
schema_type = schema.introspection_system.types["__Schema"]
|
14
|
-
schema_type.
|
14
|
+
schema_type.wrap(schema, @context)
|
15
15
|
end
|
16
16
|
|
17
17
|
def __type(name:)
|
@@ -68,7 +68,8 @@ module GraphQL
|
|
68
68
|
elsif @operation_name_error
|
69
69
|
@validation_errors << @operation_name_error
|
70
70
|
else
|
71
|
-
|
71
|
+
validator = @query.static_validator || @schema.static_validator
|
72
|
+
validation_result = validator.validate(@query, validate: @query.validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
|
72
73
|
@validation_errors.concat(validation_result[:errors])
|
73
74
|
|
74
75
|
if @validation_errors.empty?
|
data/lib/graphql/query.rb
CHANGED
@@ -45,6 +45,20 @@ module GraphQL
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
# @return [GraphQL::StaticValidation::Validator] if present, the query will validate with these rules.
|
49
|
+
attr_reader :static_validator
|
50
|
+
|
51
|
+
# @param new_validate [GraphQL::StaticValidation::Validator] if present, the query will validate with these rules. This can't be reasssigned after validation.
|
52
|
+
def static_validator=(new_validator)
|
53
|
+
if defined?(@validation_pipeline) && @validation_pipeline && @validation_pipeline.has_validated?
|
54
|
+
raise ArgumentError, "Can't reassign Query#static_validator= after validation has run, remove this assignment."
|
55
|
+
elsif !new_validator.is_a?(GraphQL::StaticValidation::Validator)
|
56
|
+
raise ArgumentError, "Expected a `GraphQL::StaticValidation::Validator` instance."
|
57
|
+
else
|
58
|
+
@static_validator = new_validator
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
48
62
|
attr_writer :query_string
|
49
63
|
|
50
64
|
# @return [GraphQL::Language::Nodes::Document]
|
@@ -83,7 +97,7 @@ module GraphQL
|
|
83
97
|
# @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
|
84
98
|
# @param except [<#call(schema_member, context)>] If provided, objects will be hidden from the schema when `.call(schema_member, context)` returns truthy
|
85
99
|
# @param only [<#call(schema_member, context)>] If provided, objects will be hidden from the schema when `.call(schema_member, context)` returns false
|
86
|
-
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, except: nil, only: nil, warden: nil)
|
100
|
+
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, except: nil, only: nil, warden: nil)
|
87
101
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
88
102
|
variables ||= {}
|
89
103
|
@schema = schema
|
@@ -97,6 +111,7 @@ module GraphQL
|
|
97
111
|
@fragments = nil
|
98
112
|
@operations = nil
|
99
113
|
@validate = validate
|
114
|
+
self.static_validator = static_validator if static_validator
|
100
115
|
context_tracers = (context ? context.fetch(:tracers, []) : [])
|
101
116
|
@tracers = schema.tracers + context_tracers
|
102
117
|
|
@@ -40,14 +40,21 @@ module GraphQL
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def add_directives_from(owner)
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
if (dir_instances = owner.directives).any?
|
44
|
+
dirs = dir_instances.map(&:class)
|
45
|
+
@directives.merge(dirs)
|
46
|
+
add_type_and_traverse(dirs)
|
47
|
+
end
|
46
48
|
end
|
47
49
|
|
48
50
|
def add_type_and_traverse(new_types)
|
49
51
|
late_types = []
|
50
|
-
|
52
|
+
path = []
|
53
|
+
new_types.each do |t|
|
54
|
+
path.push(t.graphql_name)
|
55
|
+
add_type(t, owner: nil, late_types: late_types, path: path)
|
56
|
+
path.pop
|
57
|
+
end
|
51
58
|
missed_late_types = 0
|
52
59
|
while (late_type_vals = late_types.shift)
|
53
60
|
type_owner, lt = late_type_vals
|
@@ -158,7 +165,9 @@ module GraphQL
|
|
158
165
|
type.all_argument_definitions.each do |arg|
|
159
166
|
arg_type = arg.type.unwrap
|
160
167
|
references_to(arg_type, from: arg)
|
161
|
-
|
168
|
+
path.push(arg.graphql_name)
|
169
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: path)
|
170
|
+
path.pop
|
162
171
|
if arg.default_value?
|
163
172
|
@arguments_with_default_values << arg
|
164
173
|
end
|
@@ -179,18 +188,21 @@ module GraphQL
|
|
179
188
|
name = field.graphql_name
|
180
189
|
field_type = field.type.unwrap
|
181
190
|
references_to(field_type, from: field)
|
182
|
-
|
183
|
-
add_type(field_type, owner: field, late_types: late_types, path:
|
191
|
+
path.push(name)
|
192
|
+
add_type(field_type, owner: field, late_types: late_types, path: path)
|
184
193
|
add_directives_from(field)
|
185
194
|
field.all_argument_definitions.each do |arg|
|
186
195
|
add_directives_from(arg)
|
187
196
|
arg_type = arg.type.unwrap
|
188
197
|
references_to(arg_type, from: arg)
|
189
|
-
|
198
|
+
path.push(arg.graphql_name)
|
199
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: path)
|
200
|
+
path.pop
|
190
201
|
if arg.default_value?
|
191
202
|
@arguments_with_default_values << arg
|
192
203
|
end
|
193
204
|
end
|
205
|
+
path.pop
|
194
206
|
end
|
195
207
|
end
|
196
208
|
if type.kind.input_object?
|
@@ -198,7 +210,9 @@ module GraphQL
|
|
198
210
|
add_directives_from(arg)
|
199
211
|
arg_type = arg.type.unwrap
|
200
212
|
references_to(arg_type, from: arg)
|
201
|
-
|
213
|
+
path.push(arg.graphql_name)
|
214
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: path)
|
215
|
+
path.pop
|
202
216
|
if arg.default_value?
|
203
217
|
@arguments_with_default_values << arg
|
204
218
|
end
|
@@ -206,14 +220,18 @@ module GraphQL
|
|
206
220
|
end
|
207
221
|
if type.kind.union?
|
208
222
|
@possible_types[type.graphql_name] = type.all_possible_types
|
223
|
+
path.push("possible_types")
|
209
224
|
type.all_possible_types.each do |t|
|
210
|
-
add_type(t, owner: type, late_types: late_types, path: path
|
225
|
+
add_type(t, owner: type, late_types: late_types, path: path)
|
211
226
|
end
|
227
|
+
path.pop
|
212
228
|
end
|
213
229
|
if type.kind.interface?
|
230
|
+
path.push("orphan_types")
|
214
231
|
type.orphan_types.each do |t|
|
215
|
-
add_type(t, owner: type, late_types: late_types, path: path
|
232
|
+
add_type(t, owner: type, late_types: late_types, path: path)
|
216
233
|
end
|
234
|
+
path.pop
|
217
235
|
end
|
218
236
|
if type.kind.object?
|
219
237
|
possible_types_for_this_name = @possible_types[type.graphql_name] ||= []
|
@@ -221,6 +239,7 @@ module GraphQL
|
|
221
239
|
end
|
222
240
|
|
223
241
|
if type.kind.object? || type.kind.interface?
|
242
|
+
path.push("implements")
|
224
243
|
type.interface_type_memberships.each do |interface_type_membership|
|
225
244
|
case interface_type_membership
|
226
245
|
when Schema::TypeMembership
|
@@ -235,8 +254,9 @@ module GraphQL
|
|
235
254
|
else
|
236
255
|
raise ArgumentError, "Invariant: unexpected type membership for #{type.graphql_name}: #{interface_type_membership.class} (#{interface_type_membership.inspect})"
|
237
256
|
end
|
238
|
-
add_type(interface_type, owner: type, late_types: late_types, path: path
|
257
|
+
add_type(interface_type, owner: type, late_types: late_types, path: path)
|
239
258
|
end
|
259
|
+
path.pop
|
240
260
|
end
|
241
261
|
end
|
242
262
|
end
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -155,7 +155,7 @@ module GraphQL
|
|
155
155
|
if obj.is_a?(GraphQL::Schema::Object)
|
156
156
|
obj = obj.object
|
157
157
|
end
|
158
|
-
wrapped_object = @object_class.
|
158
|
+
wrapped_object = @object_class.wrap(obj, query_ctx)
|
159
159
|
@inner_resolve.call(wrapped_object, args, ctx)
|
160
160
|
end
|
161
161
|
end
|
@@ -109,7 +109,14 @@ module GraphQL
|
|
109
109
|
to_type_name(something.name)
|
110
110
|
end
|
111
111
|
when String
|
112
|
-
something.
|
112
|
+
if something.include?("]") ||
|
113
|
+
something.include?("[") ||
|
114
|
+
something.include?("!") ||
|
115
|
+
something.include?("::")
|
116
|
+
something.gsub(/\]\[\!/, "").split("::").last
|
117
|
+
else
|
118
|
+
something
|
119
|
+
end
|
113
120
|
when GraphQL::Schema::NonNull, GraphQL::Schema::List
|
114
121
|
to_type_name(something.unwrap)
|
115
122
|
else
|
@@ -122,7 +129,8 @@ module GraphQL
|
|
122
129
|
return string unless string.include?("_")
|
123
130
|
camelized = string.split('_').each(&:capitalize!).join
|
124
131
|
camelized[0] = camelized[0].downcase
|
125
|
-
if
|
132
|
+
if string.start_with?("_")
|
133
|
+
match_data = string.match(/\A(_+)/)
|
126
134
|
camelized = "#{match_data[0]}#{camelized}"
|
127
135
|
end
|
128
136
|
camelized
|
@@ -30,6 +30,11 @@ module GraphQL
|
|
30
30
|
# @see authorized_new to make instances
|
31
31
|
protected :new
|
32
32
|
|
33
|
+
# This is called by the runtime to return an object to call methods on.
|
34
|
+
def wrap(object, context)
|
35
|
+
authorized_new(object, context)
|
36
|
+
end
|
37
|
+
|
33
38
|
# Make a new instance of this type _if_ the auth check passes,
|
34
39
|
# otherwise, raise an error.
|
35
40
|
#
|
data/lib/graphql/schema.rb
CHANGED
@@ -158,16 +158,24 @@ module GraphQL
|
|
158
158
|
def trace_class_for(mode)
|
159
159
|
@trace_modes ||= {}
|
160
160
|
@trace_modes[mode] ||= begin
|
161
|
-
|
161
|
+
case mode
|
162
|
+
when :default
|
163
|
+
superclass_base_class = if superclass.respond_to?(:trace_class_for)
|
164
|
+
superclass.trace_class_for(mode)
|
165
|
+
else
|
166
|
+
GraphQL::Tracing::Trace
|
167
|
+
end
|
168
|
+
Class.new(superclass_base_class)
|
169
|
+
when :default_backtrace
|
162
170
|
schema_base_class = trace_class_for(:default)
|
163
171
|
Class.new(schema_base_class) do
|
164
172
|
include(GraphQL::Backtrace::Trace)
|
165
173
|
end
|
166
|
-
elsif superclass.respond_to?(:trace_class_for)
|
167
|
-
superclass_base_class = superclass.trace_class_for(mode)
|
168
|
-
Class.new(superclass_base_class)
|
169
174
|
else
|
170
|
-
|
175
|
+
mods = trace_modules_for(mode)
|
176
|
+
Class.new(trace_class_for(:default)) do
|
177
|
+
mods.any? && include(*mods)
|
178
|
+
end
|
171
179
|
end
|
172
180
|
end
|
173
181
|
end
|
@@ -183,6 +191,19 @@ module GraphQL
|
|
183
191
|
nil
|
184
192
|
end
|
185
193
|
|
194
|
+
def own_trace_modules
|
195
|
+
@own_trace_modules ||= Hash.new { |h, k| h[k] = [] }
|
196
|
+
end
|
197
|
+
|
198
|
+
# @return [Array<Module>] Modules added for tracing in `trace_mode`, including inherited ones
|
199
|
+
def trace_modules_for(trace_mode)
|
200
|
+
modules = own_trace_modules[trace_mode]
|
201
|
+
if superclass.respond_to?(:trace_modules_for)
|
202
|
+
modules += superclass.trace_modules_for(trace_mode)
|
203
|
+
end
|
204
|
+
modules
|
205
|
+
end
|
206
|
+
|
186
207
|
|
187
208
|
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
188
209
|
# @see {#as_json}
|
@@ -992,26 +1013,58 @@ module GraphQL
|
|
992
1013
|
# will be called at runtime.
|
993
1014
|
#
|
994
1015
|
# @param trace_mod [Module] A module that implements tracing methods
|
1016
|
+
# @param mode [Symbol] Trace module will only be used for this trade mode
|
995
1017
|
# @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
|
996
1018
|
# @return [void]
|
997
|
-
def trace_with(trace_mod, **options)
|
998
|
-
|
999
|
-
|
1019
|
+
def trace_with(trace_mod, mode: :default, **options)
|
1020
|
+
if mode.is_a?(Array)
|
1021
|
+
mode.each { |m| trace_with(trace_mod, mode: m, **options) }
|
1022
|
+
else
|
1023
|
+
tc = trace_class_for(mode)
|
1024
|
+
tc.include(trace_mod)
|
1025
|
+
if mode != :default
|
1026
|
+
own_trace_modules[mode] << trace_mod
|
1027
|
+
end
|
1028
|
+
t_opts = trace_options_for(mode)
|
1029
|
+
t_opts.merge!(options)
|
1030
|
+
end
|
1031
|
+
nil
|
1000
1032
|
end
|
1001
1033
|
|
1002
|
-
|
1003
|
-
|
1034
|
+
# The options hash for this trace mode
|
1035
|
+
# @return [Hash]
|
1036
|
+
def trace_options_for(mode)
|
1037
|
+
@trace_options_for_mode ||= {}
|
1038
|
+
@trace_options_for_mode[mode] ||= begin
|
1039
|
+
if superclass.respond_to?(:trace_options_for)
|
1040
|
+
superclass.trace_options_for(mode).dup
|
1041
|
+
else
|
1042
|
+
{}
|
1043
|
+
end
|
1044
|
+
end
|
1004
1045
|
end
|
1005
1046
|
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1047
|
+
# Create a trace instance which will include the trace modules specified for the optional mode.
|
1048
|
+
#
|
1049
|
+
# @param mode [Symbol] Trace modules for this trade mode will be included
|
1050
|
+
# @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
|
1051
|
+
# @return [Tracing::Trace]
|
1052
|
+
def new_trace(mode: nil, **options)
|
1053
|
+
target = options[:query] || options[:multiplex]
|
1054
|
+
mode ||= target && target.context[:trace_mode]
|
1055
|
+
|
1056
|
+
trace_mode = if mode
|
1057
|
+
mode
|
1058
|
+
elsif target && target.context[:backtrace]
|
1009
1059
|
:default_backtrace
|
1010
1060
|
else
|
1011
1061
|
:default
|
1012
1062
|
end
|
1013
|
-
|
1014
|
-
|
1063
|
+
|
1064
|
+
base_trace_options = trace_options_for(trace_mode)
|
1065
|
+
trace_options = base_trace_options.merge(options)
|
1066
|
+
trace_class_for_mode = trace_class_for(trace_mode)
|
1067
|
+
trace_class_for_mode.new(**trace_options)
|
1015
1068
|
end
|
1016
1069
|
|
1017
1070
|
def query_analyzer(new_analyzer)
|
@@ -1052,6 +1105,7 @@ module GraphQL
|
|
1052
1105
|
tracers: ctx[:tracers],
|
1053
1106
|
trace: ctx[:trace],
|
1054
1107
|
dataloader: ctx[:dataloader],
|
1108
|
+
trace_mode: ctx[:trace_mode],
|
1055
1109
|
}
|
1056
1110
|
else
|
1057
1111
|
{}
|
@@ -55,20 +55,39 @@ module GraphQL
|
|
55
55
|
RUBY
|
56
56
|
end
|
57
57
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
58
|
+
def execute_field(query:, field:, ast_node:, arguments:, object:)
|
59
|
+
return_type = field.type.unwrap
|
60
|
+
trace_field = if return_type.kind.scalar? || return_type.kind.enum?
|
61
|
+
(field.trace.nil? && @trace_scalars) || field.trace
|
62
|
+
else
|
63
|
+
true
|
64
|
+
end
|
65
|
+
platform_key = if trace_field
|
66
|
+
@platform_key_cache[AppOpticsTrace].platform_field_key_cache[field]
|
67
|
+
else
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
if platform_key && trace_field
|
71
|
+
return super if !defined?(AppOpticsAPM) || gql_config[:enabled] == false
|
72
|
+
layer = platform_key
|
73
|
+
kvs = metadata({query: query, field: field, ast_node: ast_node, arguments: arguments, object: object}, layer)
|
74
|
+
|
75
|
+
::AppOpticsAPM::SDK.trace(layer, kvs) do
|
76
|
+
kvs.clear # we don't have to send them twice
|
77
|
+
super
|
78
|
+
end
|
79
|
+
else
|
80
|
+
super
|
66
81
|
end
|
67
82
|
end
|
68
83
|
|
84
|
+
def execute_field_lazy(query:, field:, ast_node:, arguments:, object:)
|
85
|
+
execute_field(query: query, field: field, ast_node: ast_node, arguments: arguments, object: object)
|
86
|
+
end
|
87
|
+
|
69
88
|
def authorized(**data)
|
70
89
|
return super if !defined?(AppOpticsAPM) || gql_config[:enabled] == false
|
71
|
-
layer = @platform_authorized_key_cache[data[:type]]
|
90
|
+
layer = @platform_key_cache[AppOpticsTrace].platform_authorized_key_cache[data[:type]]
|
72
91
|
kvs = metadata(data, layer)
|
73
92
|
|
74
93
|
::AppOpticsAPM::SDK.trace(layer, kvs) do
|
@@ -79,7 +98,7 @@ module GraphQL
|
|
79
98
|
|
80
99
|
def authorized_lazy(**data)
|
81
100
|
return super if !defined?(AppOpticsAPM) || gql_config[:enabled] == false
|
82
|
-
layer = @platform_authorized_key_cache[data[:type]]
|
101
|
+
layer = @platform_key_cache[AppOpticsTrace].platform_authorized_key_cache[data[:type]]
|
83
102
|
kvs = metadata(data, layer)
|
84
103
|
|
85
104
|
::AppOpticsAPM::SDK.trace(layer, kvs) do
|
@@ -90,7 +109,8 @@ module GraphQL
|
|
90
109
|
|
91
110
|
def resolve_type(**data)
|
92
111
|
return super if !defined?(AppOpticsAPM) || gql_config[:enabled] == false
|
93
|
-
layer = @platform_resolve_type_key_cache[data[:type]]
|
112
|
+
layer = @platform_key_cache[AppOpticsTrace].platform_resolve_type_key_cache[data[:type]]
|
113
|
+
|
94
114
|
kvs = metadata(data, layer)
|
95
115
|
|
96
116
|
::AppOpticsAPM::SDK.trace(layer, kvs) do
|
@@ -101,7 +121,7 @@ module GraphQL
|
|
101
121
|
|
102
122
|
def resolve_type_lazy(**data)
|
103
123
|
return super if !defined?(AppOpticsAPM) || gql_config[:enabled] == false
|
104
|
-
layer = @platform_resolve_type_key_cache[data[:type]]
|
124
|
+
layer = @platform_key_cache[AppOpticsTrace].platform_resolve_type_key_cache[data[:type]]
|
105
125
|
kvs = metadata(data, layer)
|
106
126
|
|
107
127
|
::AppOpticsAPM::SDK.trace(layer, kvs) do
|
@@ -18,6 +18,7 @@ module GraphQL
|
|
18
18
|
@analytics_enabled = analytics_available && Datadog::Contrib::Analytics.enabled?(analytics_enabled)
|
19
19
|
@analytics_sample_rate = analytics_sample_rate
|
20
20
|
@service_name = service
|
21
|
+
@has_prepare_span = respond_to?(:prepare_span)
|
21
22
|
super
|
22
23
|
end
|
23
24
|
|
@@ -66,38 +67,60 @@ module GraphQL
|
|
66
67
|
RUBY
|
67
68
|
end
|
68
69
|
}
|
69
|
-
|
70
|
+
if @has_prepare_span
|
71
|
+
prepare_span("#{trace_method.sub("platform_", "")}", data, span)
|
72
|
+
end
|
70
73
|
super
|
71
74
|
end
|
72
75
|
end
|
73
76
|
RUBY
|
74
77
|
end
|
75
78
|
|
76
|
-
def
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
79
|
+
def execute_field(span_key = "execute_field", query:, field:, ast_node:, arguments:, object:)
|
80
|
+
return_type = field.type.unwrap
|
81
|
+
trace_field = if return_type.kind.scalar? || return_type.kind.enum?
|
82
|
+
(field.trace.nil? && @trace_scalars) || field.trace
|
83
|
+
else
|
84
|
+
true
|
85
|
+
end
|
86
|
+
platform_key = if trace_field
|
87
|
+
@platform_key_cache[DataDogTrace].platform_field_key_cache[field]
|
88
|
+
else
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
if platform_key && trace_field
|
92
|
+
@tracer.trace(platform_key, service: @service_name) do |span|
|
93
|
+
span.span_type = 'custom'
|
94
|
+
if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
|
95
|
+
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
|
96
|
+
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
|
97
|
+
end
|
98
|
+
if @has_prepare_span
|
99
|
+
prepare_span_data = { query: query, field: field, ast_node: ast_node, arguments: arguments, object: object }
|
100
|
+
prepare_span(span_key, prepare_span_data, span)
|
101
|
+
end
|
102
|
+
super(query: query, field: field, ast_node: ast_node, arguments: arguments, object: object)
|
82
103
|
end
|
83
|
-
|
84
|
-
|
104
|
+
else
|
105
|
+
super(query: query, field: field, ast_node: ast_node, arguments: arguments, object: object)
|
85
106
|
end
|
86
107
|
end
|
87
108
|
|
88
|
-
def
|
89
|
-
|
109
|
+
def execute_field_lazy(query:, field:, ast_node:, arguments:, object:)
|
110
|
+
execute_field("execute_field_lazy", query: query, field: field, ast_node: ast_node, arguments: arguments, object: object)
|
90
111
|
end
|
91
112
|
|
92
113
|
def authorized(object:, type:, query:, span_key: "authorized")
|
93
|
-
platform_key = @platform_authorized_key_cache[type]
|
114
|
+
platform_key = @platform_key_cache[DataDogTrace].platform_authorized_key_cache[type]
|
94
115
|
@tracer.trace(platform_key, service: @service_name) do |span|
|
95
116
|
span.span_type = 'custom'
|
96
117
|
if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
|
97
118
|
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
|
98
119
|
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
|
99
120
|
end
|
100
|
-
|
121
|
+
if @has_prepare_span
|
122
|
+
prepare_span(span_key, {object: object, type: type, query: query}, span)
|
123
|
+
end
|
101
124
|
super(query: query, type: type, object: object)
|
102
125
|
end
|
103
126
|
end
|
@@ -107,14 +130,16 @@ module GraphQL
|
|
107
130
|
end
|
108
131
|
|
109
132
|
def resolve_type(object:, type:, query:, span_key: "resolve_type")
|
110
|
-
platform_key = @platform_resolve_type_key_cache[type]
|
133
|
+
platform_key = @platform_key_cache[DataDogTrace].platform_resolve_type_key_cache[type]
|
111
134
|
@tracer.trace(platform_key, service: @service_name) do |span|
|
112
135
|
span.span_type = 'custom'
|
113
136
|
if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
|
114
137
|
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
|
115
138
|
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
|
116
139
|
end
|
117
|
-
|
140
|
+
if @has_prepare_span
|
141
|
+
prepare_span(span_key, {object: object, type: type, query: query}, span)
|
142
|
+
end
|
118
143
|
super(query: query, type: type, object: object)
|
119
144
|
end
|
120
145
|
end
|
@@ -129,8 +154,8 @@ module GraphQL
|
|
129
154
|
# @param key [String] The event being traced
|
130
155
|
# @param data [Hash] The runtime data for this event (@see GraphQL::Tracing for keys for each event)
|
131
156
|
# @param span [Datadog::Tracing::SpanOperation] The datadog span for this event
|
132
|
-
def prepare_span(key, data, span)
|
133
|
-
end
|
157
|
+
# def prepare_span(key, data, span)
|
158
|
+
# end
|
134
159
|
|
135
160
|
def platform_field_key(field)
|
136
161
|
field.path
|
@@ -5,12 +5,22 @@ module GraphQL
|
|
5
5
|
module PlatformTrace
|
6
6
|
def initialize(trace_scalars: false, **_options)
|
7
7
|
@trace_scalars = trace_scalars
|
8
|
-
|
9
|
-
@
|
10
|
-
@platform_resolve_type_key_cache = Hash.new { |h, k| h[k] = platform_resolve_type_key(k) }
|
8
|
+
|
9
|
+
@platform_key_cache = Hash.new { |h, mod| h[mod] = mod::KeyCache.new }
|
11
10
|
super
|
12
11
|
end
|
13
12
|
|
13
|
+
module BaseKeyCache
|
14
|
+
def initialize
|
15
|
+
@platform_field_key_cache = Hash.new { |h, k| h[k] = platform_field_key(k) }
|
16
|
+
@platform_authorized_key_cache = Hash.new { |h, k| h[k] = platform_authorized_key(k) }
|
17
|
+
@platform_resolve_type_key_cache = Hash.new { |h, k| h[k] = platform_resolve_type_key(k) }
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :platform_field_key_cache, :platform_authorized_key_cache, :platform_resolve_type_key_cache
|
21
|
+
end
|
22
|
+
|
23
|
+
|
14
24
|
def platform_execute_field_lazy(*args, &block)
|
15
25
|
platform_execute_field(*args, &block)
|
16
26
|
end
|
@@ -24,10 +34,11 @@ module GraphQL
|
|
24
34
|
end
|
25
35
|
|
26
36
|
def self.included(child_class)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
37
|
+
key_methods_class = Class.new {
|
38
|
+
include(child_class)
|
39
|
+
include(BaseKeyCache)
|
40
|
+
}
|
41
|
+
child_class.const_set(:KeyCache, key_methods_class)
|
31
42
|
[:execute_field, :execute_field_lazy].each do |field_trace_method|
|
32
43
|
if !child_class.method_defined?(field_trace_method)
|
33
44
|
child_class.module_eval <<-RUBY, __FILE__, __LINE__
|
@@ -39,12 +50,12 @@ module GraphQL
|
|
39
50
|
true
|
40
51
|
end
|
41
52
|
platform_key = if trace_field
|
42
|
-
@platform_field_key_cache[field]
|
53
|
+
@platform_key_cache[#{child_class}].platform_field_key_cache[field]
|
43
54
|
else
|
44
55
|
nil
|
45
56
|
end
|
46
57
|
if platform_key && trace_field
|
47
|
-
platform_#{field_trace_method}(platform_key
|
58
|
+
platform_#{field_trace_method}(platform_key) do
|
48
59
|
super
|
49
60
|
end
|
50
61
|
else
|
@@ -60,7 +71,7 @@ module GraphQL
|
|
60
71
|
if !child_class.method_defined?(auth_trace_method)
|
61
72
|
child_class.module_eval <<-RUBY, __FILE__, __LINE__
|
62
73
|
def #{auth_trace_method}(type:, query:, object:)
|
63
|
-
platform_key = @platform_authorized_key_cache[type]
|
74
|
+
platform_key = @platform_key_cache[#{child_class}].platform_authorized_key_cache[type]
|
64
75
|
platform_#{auth_trace_method}(platform_key) do
|
65
76
|
super
|
66
77
|
end
|
@@ -73,7 +84,7 @@ module GraphQL
|
|
73
84
|
if !child_class.method_defined?(rt_trace_method)
|
74
85
|
child_class.module_eval <<-RUBY, __FILE__, __LINE__
|
75
86
|
def #{rt_trace_method}(query:, type:, object:)
|
76
|
-
platform_key = @platform_resolve_type_key_cache[type]
|
87
|
+
platform_key = @platform_key_cache[#{child_class}].platform_resolve_type_key_cache[type]
|
77
88
|
platform_#{rt_trace_method}(platform_key) do
|
78
89
|
super
|
79
90
|
end
|
@@ -83,8 +94,6 @@ module GraphQL
|
|
83
94
|
end
|
84
95
|
end
|
85
96
|
|
86
|
-
|
87
|
-
|
88
97
|
private
|
89
98
|
|
90
99
|
# Get the transaction name based on the operation type and name if possible, or fall back to a user provided
|
data/lib/graphql/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.25
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -623,7 +623,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
623
623
|
- !ruby/object:Gem::Version
|
624
624
|
version: '0'
|
625
625
|
requirements: []
|
626
|
-
rubygems_version: 3.4.
|
626
|
+
rubygems_version: 3.4.10
|
627
627
|
signing_key:
|
628
628
|
specification_version: 4
|
629
629
|
summary: A GraphQL language and runtime for Ruby
|