graphql-client 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/client.rb +12 -3
- data/lib/graphql/client/errors.rb +200 -0
- data/lib/graphql/client/hash_with_indifferent_access.rb +57 -0
- data/lib/graphql/client/list.rb +19 -0
- data/lib/graphql/client/query_result.rb +22 -13
- data/lib/graphql/client/response.rb +8 -115
- data/lib/graphql/language/nodes/deep_freeze_ext.rb +6 -0
- metadata +9 -7
- data/lib/graphql/language/operation_slice.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c2383236dd4b9c7a7589212a7ec4fa057d0355cb
|
4
|
+
data.tar.gz: 0e858ee34e190846593cadec92238c406b9903dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4fa1b4185938e68e90082eaa6be4ce1c814503b2254aea005c44cfe636f2c2ea358fc97250ef868ad5271e4609359296eb7e18b32a9dbf697b323becea67866d
|
7
|
+
data.tar.gz: 3f3ae9c9a78dddfcc5b8758a072dd173b47d5fe5a1bfa1a853443bebcd5386250a360862ff3c6482a1a40e3671f9664215dbbf7f46351323fdc3401a98ce109a
|
data/lib/graphql/client.rb
CHANGED
@@ -2,10 +2,10 @@ require "active_support/inflector"
|
|
2
2
|
require "active_support/notifications"
|
3
3
|
require "graphql"
|
4
4
|
require "graphql/client/error"
|
5
|
+
require "graphql/client/errors"
|
5
6
|
require "graphql/client/query_result"
|
6
7
|
require "graphql/client/response"
|
7
8
|
require "graphql/language/nodes/deep_freeze_ext"
|
8
|
-
require "graphql/language/operation_slice"
|
9
9
|
require "json"
|
10
10
|
|
11
11
|
module GraphQL
|
@@ -203,7 +203,7 @@ module GraphQL
|
|
203
203
|
definitions = {}
|
204
204
|
doc.definitions.each do |node|
|
205
205
|
node.name = nil if node.name == "__anonymous__"
|
206
|
-
sliced_document = Language::
|
206
|
+
sliced_document = Language::DefinitionSlice.slice(document_dependencies, node.name)
|
207
207
|
definition = Definition.for(node: node, document: sliced_document)
|
208
208
|
definitions[node.name] = definition
|
209
209
|
end
|
@@ -265,7 +265,16 @@ module GraphQL
|
|
265
265
|
)
|
266
266
|
end
|
267
267
|
|
268
|
-
|
268
|
+
data, errors, extensions = result.values_at("data", "errors", "extensions")
|
269
|
+
|
270
|
+
errors ||= []
|
271
|
+
GraphQL::Client::Errors.normalize_error_paths(data, errors)
|
272
|
+
|
273
|
+
Response.new(
|
274
|
+
data: definition.new(data, Errors.new(errors, ["data"])),
|
275
|
+
errors: Errors.new(errors),
|
276
|
+
extensions: extensions
|
277
|
+
)
|
269
278
|
end
|
270
279
|
|
271
280
|
# Internal: FragmentSpread and FragmentDefinition extension to allow its
|
@@ -0,0 +1,200 @@
|
|
1
|
+
require "graphql/client/hash_with_indifferent_access"
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Client
|
5
|
+
# Public: Collection of errors associated with GraphQL object type.
|
6
|
+
#
|
7
|
+
# Inspired by ActiveModel::Errors.
|
8
|
+
class Errors
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
# Internal: Normalize GraphQL Error "path" ensuring the path exists.
|
12
|
+
#
|
13
|
+
# Records "normalizedPath" value to error object.
|
14
|
+
#
|
15
|
+
# data - Hash of response data
|
16
|
+
# errors - Array of error Hashes
|
17
|
+
#
|
18
|
+
# Returns nothing.
|
19
|
+
def self.normalize_error_paths(data = nil, errors = [])
|
20
|
+
errors.each do |error|
|
21
|
+
path = ["data"]
|
22
|
+
current = data
|
23
|
+
error.fetch("path", []).each do |key|
|
24
|
+
break unless current
|
25
|
+
path << key
|
26
|
+
current = current[key]
|
27
|
+
end
|
28
|
+
error["normalizedPath"] = path
|
29
|
+
end
|
30
|
+
errors
|
31
|
+
end
|
32
|
+
|
33
|
+
# Internal: Initalize from collection of errors.
|
34
|
+
#
|
35
|
+
# errors - Array of GraphQL Hash error objects
|
36
|
+
# path - Array of String|Integer fields to data
|
37
|
+
# all - Boolean flag if all nested errors should be available
|
38
|
+
def initialize(errors = [], path = [], all = false)
|
39
|
+
@ast_path = path
|
40
|
+
@all = all
|
41
|
+
@raw_errors = errors
|
42
|
+
end
|
43
|
+
|
44
|
+
# Public: Return collection of all nested errors.
|
45
|
+
#
|
46
|
+
# data.errors[:node]
|
47
|
+
# data.errors.all[:node]
|
48
|
+
#
|
49
|
+
# Returns Errors collection.
|
50
|
+
def all
|
51
|
+
if @all
|
52
|
+
self
|
53
|
+
else
|
54
|
+
self.class.new(@raw_errors, @ast_path, true)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Internal: Return collection of errors for a given subfield.
|
59
|
+
#
|
60
|
+
# data.errors.filter_by_path("node")
|
61
|
+
#
|
62
|
+
# Returns Errors collection.
|
63
|
+
def filter_by_path(field)
|
64
|
+
self.class.new(@raw_errors, @ast_path + [field], @all)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Public: Access Hash of error messages.
|
68
|
+
#
|
69
|
+
# data.errors.messages["node"]
|
70
|
+
# data.errors.messages[:node]
|
71
|
+
#
|
72
|
+
# Returns HashWithIndifferentAccess.
|
73
|
+
def messages
|
74
|
+
return @messages if defined? @messages
|
75
|
+
|
76
|
+
messages = {}
|
77
|
+
|
78
|
+
details.each do |field, errors|
|
79
|
+
messages[field] ||= []
|
80
|
+
errors.each do |error|
|
81
|
+
messages[field] << error.fetch("message")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
@messages = HashWithIndifferentAccess.new(messages)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Public: Access Hash of error objects.
|
89
|
+
#
|
90
|
+
# data.errors.details["node"]
|
91
|
+
# data.errors.details[:node]
|
92
|
+
#
|
93
|
+
# Returns HashWithIndifferentAccess.
|
94
|
+
def details
|
95
|
+
return @details if defined? @details
|
96
|
+
|
97
|
+
details = {}
|
98
|
+
|
99
|
+
@raw_errors.each do |error|
|
100
|
+
path = error.fetch("normalizedPath", [])
|
101
|
+
matched_path = @all ? path[0, @ast_path.length] : path[0...-1]
|
102
|
+
next unless @ast_path == matched_path
|
103
|
+
|
104
|
+
field = path[@ast_path.length]
|
105
|
+
next unless field
|
106
|
+
|
107
|
+
details[field] ||= []
|
108
|
+
details[field] << error
|
109
|
+
end
|
110
|
+
|
111
|
+
@details = HashWithIndifferentAccess.new(details)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Public: When passed a symbol or a name of a field, returns an array of
|
115
|
+
# errors for the method.
|
116
|
+
#
|
117
|
+
# data.errors[:node] # => ["couldn't find node by id"]
|
118
|
+
# data.errors['node'] # => ["couldn't find node by id"]
|
119
|
+
#
|
120
|
+
# Returns Array of errors.
|
121
|
+
def [](key)
|
122
|
+
messages.fetch(key, [])
|
123
|
+
end
|
124
|
+
|
125
|
+
# Public: Iterates through each error key, value pair in the error
|
126
|
+
# messages hash. Yields the field and the error for that attribute. If the
|
127
|
+
# field has more than one error message, yields once for each error
|
128
|
+
# message.
|
129
|
+
def each
|
130
|
+
return enum_for(:each) unless block_given?
|
131
|
+
messages.keys.each do |field|
|
132
|
+
messages[field].each { |error| yield field, error }
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Public: Check if there are any errors on a given field.
|
137
|
+
#
|
138
|
+
# data.errors.messages # => {"node"=>["couldn't find node by id", "unauthorized"]}
|
139
|
+
# data.errors.include?("node") # => true
|
140
|
+
# data.errors.include?("version") # => false
|
141
|
+
#
|
142
|
+
# Returns true if the error messages include an error for the given field,
|
143
|
+
# otherwise false.
|
144
|
+
def include?(field)
|
145
|
+
self[field].any?
|
146
|
+
end
|
147
|
+
alias has_key? include?
|
148
|
+
alias key? include?
|
149
|
+
|
150
|
+
# Public: Count the number of errors on object.
|
151
|
+
#
|
152
|
+
# data.errors.messages # => {"node"=>["couldn't find node by id", "unauthorized"]}
|
153
|
+
# data.errors.size # => 2
|
154
|
+
#
|
155
|
+
# Returns the number of error messages.
|
156
|
+
def size
|
157
|
+
values.flatten.size
|
158
|
+
end
|
159
|
+
alias count size
|
160
|
+
|
161
|
+
# Public: Check if there are no errors on object.
|
162
|
+
#
|
163
|
+
# data.errors.messages # => {"node"=>["couldn't find node by id"]}
|
164
|
+
# data.errors.empty? # => false
|
165
|
+
#
|
166
|
+
# Returns true if no errors are found, otherwise false.
|
167
|
+
def empty?
|
168
|
+
size.zero?
|
169
|
+
end
|
170
|
+
alias blank? empty?
|
171
|
+
|
172
|
+
# Public: Returns all message keys.
|
173
|
+
#
|
174
|
+
# data.errors.messages # => {"node"=>["couldn't find node by id"]}
|
175
|
+
# data.errors.values # => ["node"]
|
176
|
+
#
|
177
|
+
# Returns Array of String field names.
|
178
|
+
def keys
|
179
|
+
messages.keys
|
180
|
+
end
|
181
|
+
|
182
|
+
# Public: Returns all message values.
|
183
|
+
#
|
184
|
+
# data.errors.messages # => {"node"=>["couldn't find node by id"]}
|
185
|
+
# data.errors.values # => [["couldn't find node by id"]]
|
186
|
+
#
|
187
|
+
# Returns Array of Array String messages.
|
188
|
+
def values
|
189
|
+
messages.values
|
190
|
+
end
|
191
|
+
|
192
|
+
# Public: Display console friendly representation of errors collection.
|
193
|
+
#
|
194
|
+
# Returns String.
|
195
|
+
def inspect
|
196
|
+
"#<#{self.class} @messages=#{messages.inspect} @details=#{details.inspect}>"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "active_support/inflector"
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Client
|
5
|
+
# Public: Implements a read only hash where keys can be accessed by
|
6
|
+
# strings, symbols, snake or camel case.
|
7
|
+
#
|
8
|
+
# Also see ActiveSupport::HashWithIndifferentAccess.
|
9
|
+
class HashWithIndifferentAccess
|
10
|
+
extend Forwardable
|
11
|
+
include Enumerable
|
12
|
+
|
13
|
+
def initialize(hash = {})
|
14
|
+
@hash = hash
|
15
|
+
@aliases = {}
|
16
|
+
|
17
|
+
hash.keys.each do |key|
|
18
|
+
if key.is_a?(String)
|
19
|
+
key_alias = ActiveSupport::Inflector.underscore(key)
|
20
|
+
@aliases[key_alias] = key if key != key_alias
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
freeze
|
25
|
+
end
|
26
|
+
|
27
|
+
def_delegators :@hash, :each, :empty?, :inspect, :keys, :length, :size, :to_h, :to_hash, :values
|
28
|
+
|
29
|
+
def [](key)
|
30
|
+
@hash[convert_value(key)]
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetch(key, *args, &block)
|
34
|
+
@hash.fetch(convert_value(key), *args, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def key?(key)
|
38
|
+
@hash.key?(convert_value(key))
|
39
|
+
end
|
40
|
+
alias include? key?
|
41
|
+
alias has_key? key?
|
42
|
+
alias member? key?
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def convert_value(key)
|
47
|
+
case key
|
48
|
+
when String, Symbol
|
49
|
+
key = key.to_s
|
50
|
+
@aliases.fetch(key, key)
|
51
|
+
else
|
52
|
+
key
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "graphql/client/errors"
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Client
|
5
|
+
# Public: Array wrapper for value returned from GraphQL List.
|
6
|
+
class List < Array
|
7
|
+
def initialize(values, errors = Errors.new)
|
8
|
+
super(values)
|
9
|
+
@errors = errors
|
10
|
+
freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
# Public: Return errors associated with list of data.
|
14
|
+
#
|
15
|
+
# Returns Errors collection.
|
16
|
+
attr_reader :errors
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require "active_support/inflector"
|
2
2
|
require "graphql"
|
3
|
+
require "graphql/client/errors"
|
4
|
+
require "graphql/client/list"
|
3
5
|
require "set"
|
4
6
|
|
5
7
|
module GraphQL
|
@@ -58,18 +60,18 @@ module GraphQL
|
|
58
60
|
|
59
61
|
next unless field == "edges"
|
60
62
|
class_eval <<-RUBY, __FILE__, __LINE__
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
def each_node
|
64
|
+
return enum_for(:each_node) unless block_given?
|
65
|
+
edges.each { |edge| yield edge.node }
|
66
|
+
self
|
67
|
+
end
|
66
68
|
RUBY
|
67
69
|
end
|
68
70
|
|
69
71
|
assigns = fields.map do |field, type|
|
70
72
|
if type
|
71
73
|
<<-RUBY
|
72
|
-
@#{field} = self.class.fields[:#{field}].cast(@data["#{field}"])
|
74
|
+
@#{field} = self.class.fields[:#{field}].cast(@data["#{field}"], @errors.filter_by_path("#{field}"))
|
73
75
|
RUBY
|
74
76
|
else
|
75
77
|
<<-RUBY
|
@@ -79,8 +81,10 @@ module GraphQL
|
|
79
81
|
end
|
80
82
|
|
81
83
|
class_eval <<-RUBY, __FILE__, __LINE__
|
82
|
-
def initialize(data)
|
84
|
+
def initialize(data, errors = Errors.new)
|
83
85
|
@data = data
|
86
|
+
@errors = errors
|
87
|
+
|
84
88
|
#{assigns.join("\n")}
|
85
89
|
freeze
|
86
90
|
end
|
@@ -106,10 +110,10 @@ module GraphQL
|
|
106
110
|
"#<#{name} fields=#{@fields.keys.inspect}>"
|
107
111
|
end
|
108
112
|
|
109
|
-
def self.cast(obj)
|
113
|
+
def self.cast(obj, errors = Errors.new)
|
110
114
|
case obj
|
111
115
|
when Hash
|
112
|
-
new(obj)
|
116
|
+
new(obj, errors)
|
113
117
|
when self
|
114
118
|
return obj
|
115
119
|
when QueryResult
|
@@ -121,9 +125,9 @@ module GraphQL
|
|
121
125
|
message << GraphQL::Language::Generation.generate(obj.class.source_node).sub(/\n}$/, "#{suggestion}\n}")
|
122
126
|
raise TypeError, message
|
123
127
|
end
|
124
|
-
cast(obj.to_h)
|
128
|
+
cast(obj.to_h, obj.errors)
|
125
129
|
when Array
|
126
|
-
obj.map { |e| cast(e) }
|
130
|
+
List.new(obj.each_with_index.map { |e, idx| cast(e, errors.filter_by_path(idx)) }, errors)
|
127
131
|
when NilClass
|
128
132
|
nil
|
129
133
|
else
|
@@ -145,12 +149,12 @@ module GraphQL
|
|
145
149
|
end
|
146
150
|
end
|
147
151
|
|
148
|
-
def self.new(obj)
|
152
|
+
def self.new(obj, *args)
|
149
153
|
case obj
|
150
154
|
when Hash
|
151
155
|
super
|
152
156
|
else
|
153
|
-
cast(obj)
|
157
|
+
cast(obj, *args)
|
154
158
|
end
|
155
159
|
end
|
156
160
|
|
@@ -167,6 +171,11 @@ module GraphQL
|
|
167
171
|
define(name: self.name, source_node: source_node, fields: new_fields)
|
168
172
|
end
|
169
173
|
|
174
|
+
# Public: Return errors associated with data.
|
175
|
+
#
|
176
|
+
# Returns Errors collection.
|
177
|
+
attr_reader :errors
|
178
|
+
|
170
179
|
attr_reader :data
|
171
180
|
alias to_h data
|
172
181
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "graphql/client/
|
1
|
+
require "graphql/client/errors"
|
2
2
|
|
3
3
|
module GraphQL
|
4
4
|
class Client
|
@@ -6,45 +6,6 @@ module GraphQL
|
|
6
6
|
#
|
7
7
|
# https://facebook.github.io/graphql/#sec-Response-Format
|
8
8
|
class Response
|
9
|
-
# Internal: Initialize Response subclass.
|
10
|
-
def self.for(definition, result)
|
11
|
-
data, errors, extensions = result.values_at("data", "errors", "extensions")
|
12
|
-
|
13
|
-
if data && errors
|
14
|
-
PartialResponse.new(
|
15
|
-
data: definition.new(data),
|
16
|
-
errors: ResponseErrors.new(definition, errors),
|
17
|
-
extensions: extensions
|
18
|
-
)
|
19
|
-
elsif data && !errors
|
20
|
-
SuccessfulResponse.new(
|
21
|
-
data: definition.new(data),
|
22
|
-
extensions: extensions
|
23
|
-
)
|
24
|
-
elsif !data && errors
|
25
|
-
FailedResponse.new(
|
26
|
-
errors: ResponseErrors.new(definition, errors),
|
27
|
-
extensions: extensions
|
28
|
-
)
|
29
|
-
else
|
30
|
-
FailedResponse.new(
|
31
|
-
errors: ResponseErrors.new(definition, [{ "message" => "invalid GraphQL response" }])
|
32
|
-
)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Public: Hash of server specific extension metadata.
|
37
|
-
attr_reader :extensions
|
38
|
-
|
39
|
-
# Internal: Initialize base class.
|
40
|
-
def initialize(extensions: nil)
|
41
|
-
@extensions = extensions || {}
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Public: A successful response means the query executed without any errors
|
46
|
-
# and returned all the requested data.
|
47
|
-
class SuccessfulResponse < Response
|
48
9
|
# Public: Wrapped QueryResult of data returned from the server.
|
49
10
|
#
|
50
11
|
# https://facebook.github.io/graphql/#sec-Data
|
@@ -52,89 +13,21 @@ module GraphQL
|
|
52
13
|
# Returns instance of QueryResult subclass.
|
53
14
|
attr_reader :data
|
54
15
|
|
55
|
-
# Internal: Initialize SuccessfulResponse.
|
56
|
-
def initialize(data:, **kargs)
|
57
|
-
@data = data
|
58
|
-
super(**kargs)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# Public: A partial response means the query executed with some errors but
|
63
|
-
# returned all non-nullable fields. PartialResponse is still considered a
|
64
|
-
# SuccessfulResponse as it returns data and the client may still proceed
|
65
|
-
# with its normal render flow.
|
66
|
-
class PartialResponse < SuccessfulResponse
|
67
16
|
# Public: Get partial failures from response.
|
68
17
|
#
|
69
18
|
# https://facebook.github.io/graphql/#sec-Errors
|
70
19
|
#
|
71
|
-
# Returns
|
20
|
+
# Returns Errors collection object with zero or more errors.
|
72
21
|
attr_reader :errors
|
73
22
|
|
74
|
-
#
|
75
|
-
|
76
|
-
@errors = errors
|
77
|
-
super(**kargs)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Public: A failed response returns no data and at least one error message.
|
82
|
-
# Cases may likely be a query validation error, missing authorization,
|
83
|
-
# or internal server crash.
|
84
|
-
class FailedResponse < Response
|
85
|
-
# Public: Get errors from response.
|
86
|
-
#
|
87
|
-
# https://facebook.github.io/graphql/#sec-Errors
|
88
|
-
#
|
89
|
-
# Returns ResponseErrors collection object with one or more errors.
|
90
|
-
attr_reader :errors
|
23
|
+
# Public: Hash of server specific extension metadata.
|
24
|
+
attr_reader :extensions
|
91
25
|
|
92
|
-
# Internal: Initialize
|
93
|
-
def initialize(errors
|
26
|
+
# Internal: Initialize base class.
|
27
|
+
def initialize(data: nil, errors: Errors.new, extensions: {})
|
28
|
+
@data = data
|
94
29
|
@errors = errors
|
95
|
-
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
# Public: An error received from the server on execution.
|
100
|
-
#
|
101
|
-
# Extends StandardError hierarchy so you may raise this instance.
|
102
|
-
#
|
103
|
-
# Examples
|
104
|
-
#
|
105
|
-
# raise response.errors.first
|
106
|
-
#
|
107
|
-
class ResponseError < Error
|
108
|
-
# Internal: Initialize ResponseError.
|
109
|
-
def initialize(definition, error)
|
110
|
-
@request_definition = definition
|
111
|
-
@locations = error["locations"]
|
112
|
-
super error["message"]
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Public: A collection of errors received from the server on execution.
|
117
|
-
#
|
118
|
-
# Extends StandardError hierarchy so you may raise this instance.
|
119
|
-
#
|
120
|
-
# Examples
|
121
|
-
#
|
122
|
-
# raise response.errors
|
123
|
-
#
|
124
|
-
class ResponseErrors < Error
|
125
|
-
include Enumerable
|
126
|
-
|
127
|
-
attr_reader :errors
|
128
|
-
|
129
|
-
# Internal: Initialize ResponseErrors.
|
130
|
-
def initialize(definition, errors)
|
131
|
-
@request_definition = definition
|
132
|
-
@errors = errors.map { |error| ResponseError.new(definition, error) }
|
133
|
-
super @errors.map(&:message).join(", ")
|
134
|
-
end
|
135
|
-
|
136
|
-
def each(&block)
|
137
|
-
errors.each(&block)
|
30
|
+
@extensions = extensions
|
138
31
|
end
|
139
32
|
end
|
140
33
|
end
|
@@ -12,6 +12,12 @@ module GraphQL
|
|
12
12
|
self.class.child_attributes.each do |attr_name|
|
13
13
|
public_send(attr_name).freeze.each(&:deep_freeze)
|
14
14
|
end
|
15
|
+
|
16
|
+
self.class.scalar_attributes.each do |attr_name|
|
17
|
+
object = public_send(attr_name)
|
18
|
+
object.freeze if object
|
19
|
+
end
|
20
|
+
|
15
21
|
freeze
|
16
22
|
end
|
17
23
|
end
|
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.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-10-
|
11
|
+
date: 2016-10-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -36,20 +36,20 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '0.
|
39
|
+
version: '0.19'
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 0.
|
42
|
+
version: 0.19.2
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
47
|
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: '0.
|
49
|
+
version: '0.19'
|
50
50
|
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: 0.
|
52
|
+
version: 0.19.2
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: actionpack
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,15 +122,17 @@ files:
|
|
122
122
|
- README.md
|
123
123
|
- lib/graphql/client.rb
|
124
124
|
- lib/graphql/client/error.rb
|
125
|
+
- lib/graphql/client/errors.rb
|
125
126
|
- lib/graphql/client/erubis.rb
|
127
|
+
- lib/graphql/client/hash_with_indifferent_access.rb
|
126
128
|
- lib/graphql/client/http.rb
|
129
|
+
- lib/graphql/client/list.rb
|
127
130
|
- lib/graphql/client/log_subscriber.rb
|
128
131
|
- lib/graphql/client/query_result.rb
|
129
132
|
- lib/graphql/client/railtie.rb
|
130
133
|
- lib/graphql/client/response.rb
|
131
134
|
- lib/graphql/client/view_module.rb
|
132
135
|
- lib/graphql/language/nodes/deep_freeze_ext.rb
|
133
|
-
- lib/graphql/language/operation_slice.rb
|
134
136
|
homepage: https://github.com/github/graphql-client
|
135
137
|
licenses:
|
136
138
|
- MIT
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require "graphql"
|
2
|
-
|
3
|
-
module GraphQL
|
4
|
-
module Language
|
5
|
-
# Public: Document transformations to return a minimal document to represent
|
6
|
-
# operation.
|
7
|
-
module OperationSlice
|
8
|
-
# Public: Return's minimal document to represent operation.
|
9
|
-
#
|
10
|
-
# Find's target operation and any fragment dependencies and returns a
|
11
|
-
# new document with just those definitions.
|
12
|
-
#
|
13
|
-
# document - The Nodes::Document to find definitions.
|
14
|
-
# operation_name - The String name of Nodes::OperationDefinition
|
15
|
-
#
|
16
|
-
# Returns new Nodes::Document.
|
17
|
-
def self.slice(document, operation_name)
|
18
|
-
seen = Set.new([operation_name])
|
19
|
-
stack = [operation_name]
|
20
|
-
|
21
|
-
until stack.empty?
|
22
|
-
name = stack.pop
|
23
|
-
names = find_definition_fragment_spreads(document, name)
|
24
|
-
seen.merge(names)
|
25
|
-
stack.concat(names.to_a)
|
26
|
-
end
|
27
|
-
|
28
|
-
Nodes::Document.new(definitions: document.definitions.select { |node| seen.include?(node.name) })
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.find_definition_fragment_spreads(document, definition_name)
|
32
|
-
definition = document.definitions.find { |node| node.name == definition_name }
|
33
|
-
raise "missing definition: #{definition_name}" unless definition
|
34
|
-
spreads = Set.new
|
35
|
-
visitor = Visitor.new(definition)
|
36
|
-
visitor[Nodes::FragmentSpread].enter << -> (node, _parent) do
|
37
|
-
spreads << node.name
|
38
|
-
end
|
39
|
-
visitor.visit
|
40
|
-
spreads
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|