graphql 1.12.19 → 1.12.23
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/object_generator.rb +2 -1
- data/lib/generators/graphql/relay.rb +19 -11
- data/lib/generators/graphql/templates/schema.erb +14 -2
- data/lib/graphql/analysis/ast/field_usage.rb +6 -2
- data/lib/graphql/dataloader/source.rb +30 -2
- data/lib/graphql/deprecation.rb +1 -5
- data/lib/graphql/language/nodes.rb +10 -1
- data/lib/graphql/pagination/connections.rb +35 -16
- data/lib/graphql/schema/validator/format_validator.rb +3 -1
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +51 -25
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -0
- data/lib/graphql/static_validation/validation_context.rb +2 -1
- data/lib/graphql/subscriptions/event.rb +46 -2
- data/lib/graphql/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e95b4e227ec93bce92db8d50253b83fdd8f310e7a41fca40db6df9e95b6d96a
|
4
|
+
data.tar.gz: b97ac815e644d1c2e7b8b8ea43c28f9a9247ad8d9cec5e90145ffc98ad2987a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64dc815853f24b6c6be56e24ed2058696f4e37479d48aba44b6da7d280c80e6d44af07d9002295b4d1f2d1082ec07a3513a2d5440d7682178ebb46fdaad01c84
|
7
|
+
data.tar.gz: 65672dab093d67208b1826000f9c3a7bc8125b085c72b8056820894a2c9f7d79ac4f3fd4b2aa519e944bbeb741bf9060b1c730f32a20ef1d1278c7b70ec56ece
|
@@ -12,7 +12,8 @@ module Graphql
|
|
12
12
|
#
|
13
13
|
# Add the Node interface with `--node`.
|
14
14
|
class ObjectGenerator < TypeGeneratorBase
|
15
|
-
desc "Create a GraphQL::ObjectType with the given name and fields"
|
15
|
+
desc "Create a GraphQL::ObjectType with the given name and fields." \
|
16
|
+
"If the given type name matches an existing ActiveRecord model, the generated type will automatically include fields for the models database columns."
|
16
17
|
source_root File.expand_path('../templates', __FILE__)
|
17
18
|
|
18
19
|
argument :custom_fields,
|
@@ -32,20 +32,28 @@ module Graphql
|
|
32
32
|
|
33
33
|
# Return a string UUID for `object`
|
34
34
|
def self.id_from_object(object, type_definition, query_ctx)
|
35
|
-
#
|
36
|
-
|
37
|
-
#
|
38
|
-
|
35
|
+
# For example, use Rails' GlobalID library (https://github.com/rails/globalid):
|
36
|
+
object_id = object.to_global_id.to_s
|
37
|
+
# Remove this redundant prefix to make IDs shorter:
|
38
|
+
object_id = object_id.sub("gid://\#{GlobalID.app}/", "")
|
39
|
+
encoded_id = Base64.urlsafe_encode64(object_id)
|
40
|
+
# Remove the "=" padding
|
41
|
+
encoded_id = encoded_id.sub(/=+/, "")
|
42
|
+
# Add a type hint
|
43
|
+
type_hint = type_definition.graphql_name.first
|
44
|
+
"\#{type_hint}_\#{encoded_id}"
|
39
45
|
end
|
40
46
|
|
41
47
|
# Given a string UUID, find the object
|
42
|
-
def self.object_from_id(
|
43
|
-
# For example,
|
44
|
-
#
|
45
|
-
|
46
|
-
#
|
47
|
-
|
48
|
-
#
|
48
|
+
def self.object_from_id(encoded_id_with_hint, query_ctx)
|
49
|
+
# For example, use Rails' GlobalID library (https://github.com/rails/globalid):
|
50
|
+
# Split off the type hint
|
51
|
+
_type_hint, encoded_id = encoded_id_with_hint.split("_", 2)
|
52
|
+
# Decode the ID
|
53
|
+
id = Base64.urlsafe_decode64(encoded_id)
|
54
|
+
# Rebuild it for Rails then find the object:
|
55
|
+
full_global_id = "gid://\#{GlobalID.app}/\#{id}"
|
56
|
+
GlobalID::Locator.locate(full_global_id)
|
49
57
|
end
|
50
58
|
RUBY
|
51
59
|
inject_into_file schema_file_path, schema_code, before: /^end\n/m, force: false
|
@@ -4,11 +4,23 @@ class <%= schema_name %> < GraphQL::Schema
|
|
4
4
|
<% if options[:batch] %>
|
5
5
|
# GraphQL::Batch setup:
|
6
6
|
use GraphQL::Batch
|
7
|
+
<% else %>
|
8
|
+
# For batch-loading (see https://graphql-ruby.org/dataloader/overview.html)
|
9
|
+
use GraphQL::Dataloader
|
7
10
|
<% end %>
|
11
|
+
# GraphQL-Ruby calls this when something goes wrong while running a query:
|
12
|
+
def self.type_error(err, context)
|
13
|
+
# if err.is_a?(GraphQL::InvalidNullError)
|
14
|
+
# # report to your bug tracker here
|
15
|
+
# return nil
|
16
|
+
# end
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
8
20
|
# Union and Interface Resolution
|
9
21
|
def self.resolve_type(abstract_type, obj, ctx)
|
10
|
-
# TODO: Implement this
|
11
|
-
# to return the correct object type for `obj`
|
22
|
+
# TODO: Implement this method
|
23
|
+
# to return the correct GraphQL object type for `obj`
|
12
24
|
raise(GraphQL::RequiredImplementationMissingError)
|
13
25
|
end
|
14
26
|
end
|
@@ -15,8 +15,12 @@ module GraphQL
|
|
15
15
|
field = "#{visitor.parent_type_definition.graphql_name}.#{field_defn.graphql_name}"
|
16
16
|
@used_fields << field
|
17
17
|
@used_deprecated_fields << field if field_defn.deprecation_reason
|
18
|
-
|
19
|
-
|
18
|
+
arguments = visitor.query.arguments_for(node, visitor.field_definition)
|
19
|
+
# If there was an error when preparing this argument object,
|
20
|
+
# then this might be an error or something:
|
21
|
+
if arguments.respond_to?(:argument_values)
|
22
|
+
extract_deprecated_arguments(arguments.argument_values)
|
23
|
+
end
|
20
24
|
end
|
21
25
|
|
22
26
|
def result
|
@@ -6,7 +6,11 @@ module GraphQL
|
|
6
6
|
# Called by {Dataloader} to prepare the {Source}'s internal state
|
7
7
|
# @api private
|
8
8
|
def setup(dataloader)
|
9
|
+
# These keys have been requested but haven't been fetched yet
|
9
10
|
@pending_keys = []
|
11
|
+
# These keys have been passed to `fetch` but haven't been finished yet
|
12
|
+
@fetching_keys = []
|
13
|
+
# { key => result }
|
10
14
|
@results = {}
|
11
15
|
@dataloader = dataloader
|
12
16
|
end
|
@@ -64,29 +68,46 @@ module GraphQL
|
|
64
68
|
# Then run the batch and update the cache.
|
65
69
|
# @return [void]
|
66
70
|
def sync
|
71
|
+
pending_keys = @pending_keys.dup
|
67
72
|
@dataloader.yield
|
73
|
+
iterations = 0
|
74
|
+
while pending_keys.any? { |k| !@results.key?(k) }
|
75
|
+
iterations += 1
|
76
|
+
if iterations > 1000
|
77
|
+
raise "#{self.class}#sync tried 1000 times to load pending keys (#{pending_keys}), but they still weren't loaded. There is likely a circular dependency."
|
78
|
+
end
|
79
|
+
@dataloader.yield
|
80
|
+
end
|
81
|
+
nil
|
68
82
|
end
|
69
83
|
|
70
84
|
# @return [Boolean] True if this source has any pending requests for data.
|
71
85
|
def pending?
|
72
|
-
|
86
|
+
!@pending_keys.empty?
|
73
87
|
end
|
74
88
|
|
75
89
|
# Called by {GraphQL::Dataloader} to resolve and pending requests to this source.
|
76
90
|
# @api private
|
77
91
|
# @return [void]
|
78
92
|
def run_pending_keys
|
93
|
+
if !@fetching_keys.empty?
|
94
|
+
@pending_keys -= @fetching_keys
|
95
|
+
end
|
79
96
|
return if @pending_keys.empty?
|
80
97
|
fetch_keys = @pending_keys.uniq
|
98
|
+
@fetching_keys.concat(fetch_keys)
|
81
99
|
@pending_keys = []
|
82
100
|
results = fetch(fetch_keys)
|
83
101
|
fetch_keys.each_with_index do |key, idx|
|
84
102
|
@results[key] = results[idx]
|
85
103
|
end
|
104
|
+
nil
|
86
105
|
rescue StandardError => error
|
87
106
|
fetch_keys.each { |key| @results[key] = error }
|
88
107
|
ensure
|
89
|
-
|
108
|
+
if fetch_keys
|
109
|
+
@fetching_keys -= fetch_keys
|
110
|
+
end
|
90
111
|
end
|
91
112
|
|
92
113
|
# These arguments are given to `dataloader.with(source_class, ...)`. The object
|
@@ -116,6 +137,13 @@ module GraphQL
|
|
116
137
|
# @return [Object] The result from {#fetch} for `key`.
|
117
138
|
# @api private
|
118
139
|
def result_for(key)
|
140
|
+
if !@results.key?(key)
|
141
|
+
raise <<-ERR
|
142
|
+
Invariant: fetching result for a key on #{self.class} that hasn't been loaded yet (#{key.inspect}, loaded: #{@results.keys})
|
143
|
+
|
144
|
+
This key should have been loaded already. This is a bug in GraphQL::Dataloader, please report it on GitHub: https://github.com/rmosolgo/graphql-ruby/issues/new.
|
145
|
+
ERR
|
146
|
+
end
|
119
147
|
result = @results[key]
|
120
148
|
|
121
149
|
raise result if result.class <= StandardError
|
data/lib/graphql/deprecation.rb
CHANGED
@@ -197,7 +197,16 @@ module GraphQL
|
|
197
197
|
else
|
198
198
|
module_eval <<-RUBY, __FILE__, __LINE__
|
199
199
|
def children
|
200
|
-
@children ||=
|
200
|
+
@children ||= begin
|
201
|
+
if #{children_of_type.keys.map { |k| "@#{k}.any?" }.join(" || ")}
|
202
|
+
new_children = []
|
203
|
+
#{children_of_type.keys.map { |k| "new_children.concat(@#{k})" }.join("; ")}
|
204
|
+
new_children.freeze
|
205
|
+
new_children
|
206
|
+
else
|
207
|
+
NO_CHILDREN
|
208
|
+
end
|
209
|
+
end
|
201
210
|
end
|
202
211
|
RUBY
|
203
212
|
end
|
@@ -70,23 +70,42 @@ module GraphQL
|
|
70
70
|
wrappers = context ? context.namespace(:connections)[:all_wrappers] : all_wrappers
|
71
71
|
impl = wrapper_for(items, wrappers: wrappers)
|
72
72
|
|
73
|
-
if impl
|
74
|
-
|
73
|
+
if impl
|
74
|
+
impl.new(
|
75
|
+
items,
|
76
|
+
context: context,
|
77
|
+
parent: parent,
|
78
|
+
field: field,
|
79
|
+
max_page_size: field.has_max_page_size? ? field.max_page_size : context.schema.default_max_page_size,
|
80
|
+
first: arguments[:first],
|
81
|
+
after: arguments[:after],
|
82
|
+
last: arguments[:last],
|
83
|
+
before: arguments[:before],
|
84
|
+
arguments: arguments,
|
85
|
+
edge_class: edge_class_for_field(field),
|
86
|
+
)
|
87
|
+
else
|
88
|
+
begin
|
89
|
+
connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(items)
|
90
|
+
if parent.is_a?(GraphQL::Schema::Object)
|
91
|
+
parent = parent.object
|
92
|
+
end
|
93
|
+
connection_class.new(
|
94
|
+
items,
|
95
|
+
arguments,
|
96
|
+
field: field,
|
97
|
+
max_page_size: field.max_page_size,
|
98
|
+
parent: parent,
|
99
|
+
context: context,
|
100
|
+
)
|
101
|
+
rescue RuntimeError => err
|
102
|
+
if err.message.include?("No connection implementation to wrap")
|
103
|
+
raise ImplementationMissingError, "Couldn't find a connection wrapper for #{items.class} during #{field.path} (#{items.inspect})"
|
104
|
+
else
|
105
|
+
raise err
|
106
|
+
end
|
107
|
+
end
|
75
108
|
end
|
76
|
-
|
77
|
-
impl.new(
|
78
|
-
items,
|
79
|
-
context: context,
|
80
|
-
parent: parent,
|
81
|
-
field: field,
|
82
|
-
max_page_size: field.has_max_page_size? ? field.max_page_size : context.schema.default_max_page_size,
|
83
|
-
first: arguments[:first],
|
84
|
-
after: arguments[:after],
|
85
|
-
last: arguments[:last],
|
86
|
-
before: arguments[:before],
|
87
|
-
arguments: arguments,
|
88
|
-
edge_class: edge_class_for_field(field),
|
89
|
-
)
|
90
109
|
end
|
91
110
|
|
92
111
|
# use an override if there is one
|
@@ -38,7 +38,9 @@ module GraphQL
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def validate(_object, _context, value)
|
41
|
-
if value
|
41
|
+
if permitted_empty_value?(value)
|
42
|
+
# Do nothing
|
43
|
+
elsif value.nil? ||
|
42
44
|
(@with_pattern && !value.match?(@with_pattern)) ||
|
43
45
|
(@without_pattern && value.match?(@without_pattern))
|
44
46
|
@message
|
@@ -10,6 +10,7 @@ module GraphQL
|
|
10
10
|
#
|
11
11
|
# Original Algorithm: https://github.com/graphql/graphql-js/blob/master/src/validation/rules/OverlappingFieldsCanBeMerged.js
|
12
12
|
NO_ARGS = {}.freeze
|
13
|
+
|
13
14
|
Field = Struct.new(:node, :definition, :owner_type, :parents)
|
14
15
|
FragmentSpread = Struct.new(:name, :parents)
|
15
16
|
|
@@ -17,24 +18,47 @@ module GraphQL
|
|
17
18
|
super
|
18
19
|
@visited_fragments = {}
|
19
20
|
@compared_fragments = {}
|
21
|
+
@conflict_count = 0
|
20
22
|
end
|
21
23
|
|
22
24
|
def on_operation_definition(node, _parent)
|
23
|
-
conflicts_within_selection_set(node, type_definition)
|
25
|
+
setting_errors { conflicts_within_selection_set(node, type_definition) }
|
24
26
|
super
|
25
27
|
end
|
26
28
|
|
27
29
|
def on_field(node, _parent)
|
28
|
-
conflicts_within_selection_set(node, type_definition)
|
30
|
+
setting_errors { conflicts_within_selection_set(node, type_definition) }
|
29
31
|
super
|
30
32
|
end
|
31
33
|
|
32
34
|
private
|
33
35
|
|
36
|
+
def field_conflicts
|
37
|
+
@field_conflicts ||= Hash.new do |errors, field|
|
38
|
+
errors[field] = GraphQL::StaticValidation::FieldsWillMergeError.new(kind: :field, field_name: field)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def arg_conflicts
|
43
|
+
@arg_conflicts ||= Hash.new do |errors, field|
|
44
|
+
errors[field] = GraphQL::StaticValidation::FieldsWillMergeError.new(kind: :argument, field_name: field)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def setting_errors
|
49
|
+
@field_conflicts = nil
|
50
|
+
@arg_conflicts = nil
|
51
|
+
|
52
|
+
yield
|
53
|
+
# don't initialize these if they weren't initialized in the block:
|
54
|
+
@field_conflicts && @field_conflicts.each_value { |error| add_error(error) }
|
55
|
+
@arg_conflicts && @arg_conflicts.each_value { |error| add_error(error) }
|
56
|
+
end
|
57
|
+
|
34
58
|
def conflicts_within_selection_set(node, parent_type)
|
35
59
|
return if parent_type.nil?
|
36
60
|
|
37
|
-
fields, fragment_spreads = fields_and_fragments_from_selection(node, owner_type: parent_type, parents:
|
61
|
+
fields, fragment_spreads = fields_and_fragments_from_selection(node, owner_type: parent_type, parents: nil)
|
38
62
|
|
39
63
|
# (A) Find find all conflicts "within" the fields of this selection set.
|
40
64
|
find_conflicts_within(fields)
|
@@ -174,15 +198,21 @@ module GraphQL
|
|
174
198
|
response_keys.each do |key, fields|
|
175
199
|
next if fields.size < 2
|
176
200
|
# find conflicts within nodes
|
177
|
-
|
178
|
-
|
201
|
+
i = 0
|
202
|
+
while i < fields.size
|
203
|
+
j = i + 1
|
204
|
+
while j < fields.size
|
179
205
|
find_conflict(key, fields[i], fields[j])
|
206
|
+
j += 1
|
180
207
|
end
|
208
|
+
i += 1
|
181
209
|
end
|
182
210
|
end
|
183
211
|
end
|
184
212
|
|
185
213
|
def find_conflict(response_key, field1, field2, mutually_exclusive: false)
|
214
|
+
return if @conflict_count >= context.max_errors
|
215
|
+
|
186
216
|
node1 = field1.node
|
187
217
|
node2 = field2.node
|
188
218
|
|
@@ -191,28 +221,21 @@ module GraphQL
|
|
191
221
|
|
192
222
|
if !are_mutually_exclusive
|
193
223
|
if node1.name != node2.name
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
field_name: response_key,
|
201
|
-
conflicts: errored_nodes
|
202
|
-
))
|
224
|
+
conflict = field_conflicts[response_key]
|
225
|
+
|
226
|
+
conflict.add_conflict(node1, node1.name)
|
227
|
+
conflict.add_conflict(node2, node2.name)
|
228
|
+
|
229
|
+
@conflict_count += 1
|
203
230
|
end
|
204
231
|
|
205
232
|
if !same_arguments?(node1, node2)
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
path: [],
|
213
|
-
field_name: response_key,
|
214
|
-
conflicts: conflicts
|
215
|
-
))
|
233
|
+
conflict = arg_conflicts[response_key]
|
234
|
+
|
235
|
+
conflict.add_conflict(node1, GraphQL::Language.serialize(serialize_field_args(node1)))
|
236
|
+
conflict.add_conflict(node2, GraphQL::Language.serialize(serialize_field_args(node2)))
|
237
|
+
|
238
|
+
@conflict_count += 1
|
216
239
|
end
|
217
240
|
end
|
218
241
|
|
@@ -224,7 +247,9 @@ module GraphQL
|
|
224
247
|
end
|
225
248
|
|
226
249
|
def find_conflicts_between_sub_selection_sets(field1, field2, mutually_exclusive:)
|
227
|
-
return if field1.definition.nil? ||
|
250
|
+
return if field1.definition.nil? ||
|
251
|
+
field2.definition.nil? ||
|
252
|
+
(field1.node.selections.empty? && field2.node.selections.empty?)
|
228
253
|
|
229
254
|
return_type1 = field1.definition.type.unwrap
|
230
255
|
return_type2 = field2.definition.type.unwrap
|
@@ -304,6 +329,7 @@ module GraphQL
|
|
304
329
|
if node.selections.empty?
|
305
330
|
NO_SELECTIONS
|
306
331
|
else
|
332
|
+
parents ||= []
|
307
333
|
fields, fragment_spreads = find_fields_and_fragments(node.selections, owner_type: owner_type, parents: parents, fields: [], fragment_spreads: [])
|
308
334
|
response_keys = fields.group_by { |f| f.node.alias || f.node.name }
|
309
335
|
[response_keys, fragment_spreads]
|
@@ -3,12 +3,33 @@ module GraphQL
|
|
3
3
|
module StaticValidation
|
4
4
|
class FieldsWillMergeError < StaticValidation::Error
|
5
5
|
attr_reader :field_name
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :kind
|
7
|
+
|
8
|
+
def initialize(kind:, field_name:)
|
9
|
+
super(nil)
|
7
10
|
|
8
|
-
def initialize(message, path: nil, nodes: [], field_name:, conflicts:)
|
9
|
-
super(message, path: path, nodes: nodes)
|
10
11
|
@field_name = field_name
|
11
|
-
@
|
12
|
+
@kind = kind
|
13
|
+
@conflicts = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def message
|
17
|
+
"Field '#{field_name}' has #{kind == :argument ? 'an' : 'a'} #{kind} conflict: #{conflicts}?"
|
18
|
+
end
|
19
|
+
|
20
|
+
def path
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
|
24
|
+
def conflicts
|
25
|
+
@conflicts.join(' or ')
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_conflict(node, conflict_str)
|
29
|
+
return if nodes.include?(node)
|
30
|
+
|
31
|
+
@nodes << node
|
32
|
+
@conflicts << conflict_str
|
12
33
|
end
|
13
34
|
|
14
35
|
# A hash representation of this Message
|
@@ -16,6 +16,8 @@ module GraphQL
|
|
16
16
|
private
|
17
17
|
|
18
18
|
def assert_required_args(ast_node, defn)
|
19
|
+
args = defn.arguments
|
20
|
+
return if args.empty?
|
19
21
|
present_argument_names = ast_node.arguments.map(&:name)
|
20
22
|
required_argument_names = defn.arguments.each_value
|
21
23
|
.select { |a| a.type.kind.non_null? && !a.default_value? && context.warden.get_argument(defn, a.name) }
|
@@ -53,6 +53,36 @@ module GraphQL
|
|
53
53
|
|
54
54
|
class << self
|
55
55
|
private
|
56
|
+
|
57
|
+
# This method does not support cyclic references in the Hash,
|
58
|
+
# nor does it support Hashes whose keys are not sortable
|
59
|
+
# with respect to their peers ( cases where a <=> b might throw an error )
|
60
|
+
def deep_sort_hash_keys(hash_to_sort)
|
61
|
+
raise ArgumentError.new("Argument must be a Hash") unless hash_to_sort.is_a?(Hash)
|
62
|
+
hash_to_sort.keys.sort.map do |k|
|
63
|
+
if hash_to_sort[k].is_a?(Hash)
|
64
|
+
[k, deep_sort_hash_keys(hash_to_sort[k])]
|
65
|
+
elsif hash_to_sort[k].is_a?(Array)
|
66
|
+
[k, deep_sort_array_hashes(hash_to_sort[k])]
|
67
|
+
else
|
68
|
+
[k, hash_to_sort[k]]
|
69
|
+
end
|
70
|
+
end.to_h
|
71
|
+
end
|
72
|
+
|
73
|
+
def deep_sort_array_hashes(array_to_inspect)
|
74
|
+
raise ArgumentError.new("Argument must be an Array") unless array_to_inspect.is_a?(Array)
|
75
|
+
array_to_inspect.map do |v|
|
76
|
+
if v.is_a?(Hash)
|
77
|
+
deep_sort_hash_keys(v)
|
78
|
+
elsif v.is_a?(Array)
|
79
|
+
deep_sort_array_hashes(v)
|
80
|
+
else
|
81
|
+
v
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
56
86
|
def stringify_args(arg_owner, args)
|
57
87
|
arg_owner = arg_owner.respond_to?(:unwrap) ? arg_owner.unwrap : arg_owner # remove list and non-null wrappers
|
58
88
|
case args
|
@@ -65,12 +95,26 @@ module GraphQL
|
|
65
95
|
|
66
96
|
if arg_defn
|
67
97
|
normalized_arg_name = camelized_arg_name
|
68
|
-
next_args[normalized_arg_name] = stringify_args(arg_defn.type, v)
|
69
98
|
else
|
70
99
|
normalized_arg_name = arg_name
|
71
100
|
arg_defn = get_arg_definition(arg_owner, normalized_arg_name)
|
72
101
|
end
|
73
|
-
|
102
|
+
arg_base_type = arg_defn.type.unwrap
|
103
|
+
# In the case where the value being emitted is seen as a "JSON"
|
104
|
+
# type, treat the value as one atomic unit of serialization
|
105
|
+
is_json_definition = arg_base_type && arg_base_type <= GraphQL::Types::JSON
|
106
|
+
if is_json_definition
|
107
|
+
sorted_value = if v.is_a?(Hash)
|
108
|
+
deep_sort_hash_keys(v)
|
109
|
+
elsif v.is_a?(Array)
|
110
|
+
deep_sort_array_hashes(v)
|
111
|
+
else
|
112
|
+
v
|
113
|
+
end
|
114
|
+
next_args[normalized_arg_name] = sorted_value.respond_to?(:to_json) ? sorted_value.to_json : sorted_value
|
115
|
+
else
|
116
|
+
next_args[normalized_arg_name] = stringify_args(arg_base_type, v)
|
117
|
+
end
|
74
118
|
end
|
75
119
|
# Make sure they're deeply sorted
|
76
120
|
next_args.sort.to_h
|
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: 1.12.
|
4
|
+
version: 1.12.23
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|