graphql-client 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 342aa95830be1c53716c72962fad3c3785058f160404fba1aa603f9b94a96f92
|
4
|
+
data.tar.gz: c63ff270ab64ad1ee8a8ece5a36d20be9b12e138e86cc0a4eb88246bf2d4c2bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a701d2ad7b0776f43d04b63fa394d5470fe7f5a8d0d71467affd78d04069ec212249fc1e0ab9c86d82bdabadc750ac6eb63b7e6c77d3b842f82f5c6c88d81baf
|
7
|
+
data.tar.gz: 3033fcb57a59f3518436f0f903154f9eaaa070230afd6ba4f83d3c6c42904f71a503f92f42aa5b91932770c15bb8551a5ea7ce7130a9bf8ac7eca11756ef53ce
|
data/lib/graphql/client.rb
CHANGED
@@ -120,13 +120,21 @@ module GraphQL
|
|
120
120
|
|
121
121
|
definition_dependencies = Set.new
|
122
122
|
|
123
|
+
# Replace Ruby constant reference with GraphQL fragment names,
|
124
|
+
# while populating `definition_dependencies` with
|
125
|
+
# GraphQL Fragment ASTs which this operation depends on
|
123
126
|
str = str.gsub(/\.\.\.([a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)*)/) do
|
124
127
|
match = Regexp.last_match
|
125
128
|
const_name = match[1]
|
126
129
|
|
127
130
|
if str.match(/fragment\s*#{const_name}/)
|
131
|
+
# It's a fragment _definition_, not a fragment usage
|
128
132
|
match[0]
|
129
133
|
else
|
134
|
+
# It's a fragment spread, so we should load the fragment
|
135
|
+
# which corresponds to the spread.
|
136
|
+
# We depend on ActiveSupport to either find the already-loaded
|
137
|
+
# constant, or to load the constant by name
|
130
138
|
begin
|
131
139
|
fragment = ActiveSupport::Inflector.constantize(const_name)
|
132
140
|
rescue NameError
|
@@ -135,6 +143,10 @@ module GraphQL
|
|
135
143
|
|
136
144
|
case fragment
|
137
145
|
when FragmentDefinition
|
146
|
+
# We found the fragment definition that this fragment spread belongs to.
|
147
|
+
# So, register the AST of this fragment in `definition_dependencies`
|
148
|
+
# and update the query string to valid GraphQL syntax,
|
149
|
+
# replacing the Ruby constant
|
138
150
|
definition_dependencies.merge(fragment.document.definitions)
|
139
151
|
"...#{fragment.definition_name}"
|
140
152
|
else
|
@@ -157,10 +169,17 @@ module GraphQL
|
|
157
169
|
doc = GraphQL.parse(str)
|
158
170
|
|
159
171
|
document_types = DocumentTypes.analyze_types(self.schema, doc).freeze
|
160
|
-
QueryTypename.insert_typename_fields(doc, types: document_types)
|
172
|
+
doc = QueryTypename.insert_typename_fields(doc, types: document_types)
|
161
173
|
|
162
174
|
doc.definitions.each do |node|
|
163
|
-
node.name
|
175
|
+
if node.name.nil?
|
176
|
+
if node.respond_to?(:merge) # GraphQL 1.9 +
|
177
|
+
node_with_name = node.merge(name: "__anonymous__")
|
178
|
+
doc = doc.replace_child(node, node_with_name)
|
179
|
+
else
|
180
|
+
node.name = "__anonymous__"
|
181
|
+
end
|
182
|
+
end
|
164
183
|
end
|
165
184
|
|
166
185
|
document_dependencies = Language::Nodes::Document.new(definitions: doc.definitions + definition_dependencies.to_a)
|
@@ -192,7 +211,6 @@ module GraphQL
|
|
192
211
|
raise TypeError, "unexpected #{node.class}"
|
193
212
|
end
|
194
213
|
|
195
|
-
node.name = nil if node.name == "__anonymous__"
|
196
214
|
sliced_document = Language::DefinitionSlice.slice(document_dependencies, node.name)
|
197
215
|
definition = Definition.for(
|
198
216
|
client: self,
|
@@ -205,18 +223,26 @@ module GraphQL
|
|
205
223
|
end
|
206
224
|
|
207
225
|
name_hook = RenameNodeHook.new(definitions)
|
208
|
-
visitor = Language::Visitor.new(
|
226
|
+
visitor = Language::Visitor.new(document_dependencies)
|
209
227
|
visitor[Language::Nodes::FragmentDefinition].leave << name_hook.method(:rename_node)
|
210
228
|
visitor[Language::Nodes::OperationDefinition].leave << name_hook.method(:rename_node)
|
211
229
|
visitor[Language::Nodes::FragmentSpread].leave << name_hook.method(:rename_node)
|
212
230
|
visitor.visit
|
213
231
|
|
214
|
-
doc.
|
232
|
+
if !doc.respond_to?(:merge)
|
233
|
+
doc.deep_freeze # 1.9 introduced immutable AST nodes, so we skip this on 1.9+
|
234
|
+
end
|
215
235
|
|
216
|
-
|
236
|
+
if document_tracking_enabled
|
237
|
+
if @document.respond_to?(:merge) # GraphQL 1.9+
|
238
|
+
@document = @document.merge(definitions: @document.definitions + doc.definitions)
|
239
|
+
else
|
240
|
+
@document.definitions.concat(doc.definitions)
|
241
|
+
end
|
242
|
+
end
|
217
243
|
|
218
|
-
if definitions[
|
219
|
-
definitions[
|
244
|
+
if definitions["__anonymous__"]
|
245
|
+
definitions["__anonymous__"]
|
220
246
|
else
|
221
247
|
Module.new do
|
222
248
|
definitions.each do |name, definition|
|
@@ -235,7 +261,7 @@ module GraphQL
|
|
235
261
|
definition = @definitions[node.name]
|
236
262
|
if definition
|
237
263
|
node.extend(LazyName)
|
238
|
-
node.
|
264
|
+
node.name_proc = -> { definition.definition_name }
|
239
265
|
end
|
240
266
|
end
|
241
267
|
end
|
@@ -358,8 +384,10 @@ module GraphQL
|
|
358
384
|
# name to point to a lazily defined Proc instead of a static string.
|
359
385
|
module LazyName
|
360
386
|
def name
|
361
|
-
@
|
387
|
+
@name_proc.call
|
362
388
|
end
|
389
|
+
|
390
|
+
attr_writer :name_proc
|
363
391
|
end
|
364
392
|
|
365
393
|
private
|
@@ -13,33 +13,84 @@ module GraphQL
|
|
13
13
|
# document - GraphQL::Language::Nodes::Document to modify
|
14
14
|
# schema - Optional Map of GraphQL::Language::Nodes::Node to GraphQL::Type
|
15
15
|
#
|
16
|
-
# Returns
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
# Returns the document with `__typename` added to it
|
17
|
+
if GraphQL::Language::Nodes::AbstractNode.method_defined?(:merge)
|
18
|
+
# GraphQL 1.9 introduces a new visitor class
|
19
|
+
# and doesn't expose writer methods for node attributes.
|
20
|
+
# So, use the node mutation API instead.
|
21
|
+
class InsertTypenameVisitor < GraphQL::Language::Visitor
|
22
|
+
def initialize(document, types:)
|
23
|
+
@types = types
|
24
|
+
super(document)
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_typename(node, parent)
|
28
|
+
type = @types[node]
|
29
|
+
type = type && type.unwrap
|
30
|
+
|
31
|
+
if (node.selections.any? && (type.nil? || type.is_a?(GraphQL::InterfaceType) || type.is_a?(GraphQL::UnionType))) ||
|
32
|
+
(node.selections.none? && type.is_a?(GraphQL::ObjectType))
|
33
|
+
names = QueryTypename.node_flatten_selections(node.selections).map { |s| s.respond_to?(:name) ? s.name : nil }
|
25
34
|
names = Set.new(names.compact)
|
26
35
|
|
27
|
-
|
28
|
-
node
|
36
|
+
if names.include?("__typename")
|
37
|
+
yield(node, parent)
|
38
|
+
else
|
39
|
+
node_with_typename = node.merge(selections: [GraphQL::Language::Nodes::Field.new(name: "__typename")] + node.selections)
|
40
|
+
yield(node_with_typename, parent)
|
29
41
|
end
|
42
|
+
else
|
43
|
+
yield(node, parent)
|
30
44
|
end
|
31
|
-
|
32
|
-
|
45
|
+
end
|
46
|
+
|
47
|
+
def on_operation_definition(node, parent)
|
48
|
+
add_typename(node, parent) { |n, p| super(n, p) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def on_field(node, parent)
|
52
|
+
add_typename(node, parent) { |n, p| super(n, p) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def on_fragment_definition(node, parent)
|
56
|
+
add_typename(node, parent) { |n, p| super(n, p) }
|
33
57
|
end
|
34
58
|
end
|
35
59
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
60
|
+
def self.insert_typename_fields(document, types: {})
|
61
|
+
visitor = InsertTypenameVisitor.new(document, types: types)
|
62
|
+
visitor.visit
|
63
|
+
visitor.result
|
64
|
+
end
|
65
|
+
|
66
|
+
else
|
67
|
+
def self.insert_typename_fields(document, types: {})
|
68
|
+
on_selections = ->(node, _parent) do
|
69
|
+
type = types[node]
|
70
|
+
|
71
|
+
if node.selections.any?
|
72
|
+
case type && type.unwrap
|
73
|
+
when NilClass, GraphQL::InterfaceType, GraphQL::UnionType
|
74
|
+
names = node_flatten_selections(node.selections).map { |s| s.respond_to?(:name) ? s.name : nil }
|
75
|
+
names = Set.new(names.compact)
|
41
76
|
|
42
|
-
|
77
|
+
unless names.include?("__typename")
|
78
|
+
node.selections = [GraphQL::Language::Nodes::Field.new(name: "__typename")] + node.selections
|
79
|
+
end
|
80
|
+
end
|
81
|
+
elsif type && type.unwrap.is_a?(GraphQL::ObjectType)
|
82
|
+
node.selections = [GraphQL::Language::Nodes::Field.new(name: "__typename")]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
visitor = GraphQL::Language::Visitor.new(document)
|
87
|
+
visitor[GraphQL::Language::Nodes::Field].leave << on_selections
|
88
|
+
visitor[GraphQL::Language::Nodes::FragmentDefinition].leave << on_selections
|
89
|
+
visitor[GraphQL::Language::Nodes::OperationDefinition].leave << on_selections
|
90
|
+
visitor.visit
|
91
|
+
|
92
|
+
document
|
93
|
+
end
|
43
94
|
end
|
44
95
|
|
45
96
|
def self.node_flatten_selections(selections)
|
@@ -41,7 +41,7 @@ module GraphQL
|
|
41
41
|
if type = possible_types[typename]
|
42
42
|
type.cast(value, errors)
|
43
43
|
else
|
44
|
-
raise InvariantError, "expected value to be one of (#{possible_types.keys.join(", ")}), but was #{typename}"
|
44
|
+
raise InvariantError, "expected value to be one of (#{possible_types.keys.join(", ")}), but was #{typename.inspect}"
|
45
45
|
end
|
46
46
|
when NilClass
|
47
47
|
nil
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|