graphql-client 0.0.18 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ca22da5b31b85d955d2a209f48e5767c2b953848
4
- data.tar.gz: 0150a203bb5fe856b6ea6c15bd941056f86002ff
3
+ metadata.gz: c087161bf28d989bf274ba68bf76223ff4cc7b84
4
+ data.tar.gz: 3054f8552e6e6a532ebd09a15e7f5914b8dfa994
5
5
  SHA512:
6
- metadata.gz: c41fc037d158823686bf372addbc0b6592a87f2e9b470f0fb7302393cc89ad42f452bcb87bfdb142887437c42438e95d20bd236045088e11077cb48dba99ee38
7
- data.tar.gz: 99f425fee8b8e70e876cc8d262befa594f2a2b182cad5b4b6b27a392139e1ecf84a5c6726f0719c96292afe17053ad16060be7ea73e8d414c931315cbddd0fab
6
+ metadata.gz: 4044f2bf520a94bcaf5f6a918baf4daa8eb72479f7fd9de12bacfe58f40a362f57d675207ef0a25d9508113ccc3a0985c2095fa4534385ab4d33b08db2592815
7
+ data.tar.gz: 8d19a14603c36df798b2280432d54e5dceb98d31a1d949c10bd2ac349b82dcf559359253e10b51a3d655f3e3cf22505f1b4ea97ff4a9acdf8e1992e91c462f9b
@@ -1,39 +1,17 @@
1
1
  require "active_support/inflector"
2
2
  require "active_support/notifications"
3
3
  require "graphql"
4
+ require "graphql/client/error"
4
5
  require "graphql/client/query_result"
6
+ require "graphql/client/query"
7
+ require "graphql/client/response"
5
8
  require "graphql/language/nodes/deep_freeze_ext"
6
9
  require "graphql/language/operation_slice"
7
10
 
8
11
  module GraphQL
9
12
  class Client
10
- class Error < StandardError; end
11
13
  class ValidationError < Error; end
12
14
 
13
- class ResponseError < Error
14
- def initialize(definition, error)
15
- @request_definition = definition
16
- @locations = error["locations"]
17
- super error["message"]
18
- end
19
- end
20
-
21
- class ResponseErrors < Error
22
- include Enumerable
23
-
24
- attr_reader :errors
25
-
26
- def initialize(definition, errors)
27
- @request_definition = definition
28
- @errors = errors.map { |error| ResponseError.new(definition, error) }
29
- super @errors.map(&:message).join(", ")
30
- end
31
-
32
- def each(&block)
33
- errors.each(&block)
34
- end
35
- end
36
-
37
15
  attr_reader :schema, :fetch
38
16
 
39
17
  attr_accessor :document_tracking_enabled
@@ -50,8 +28,6 @@ module GraphQL
50
28
  else
51
29
  load_schema(JSON.parse(schema))
52
30
  end
53
- else
54
- nil
55
31
  end
56
32
  end
57
33
 
@@ -114,34 +90,49 @@ module GraphQL
114
90
  end
115
91
 
116
92
  private
117
- def query_result_class
118
- @query_result_class ||= GraphQL::Client::QueryResult.wrap(definition_node, name: name)
119
- end
93
+
94
+ def query_result_class
95
+ @query_result_class ||= GraphQL::Client::QueryResult.wrap(definition_node, name: name)
96
+ end
120
97
  end
121
98
 
122
99
  class OperationDefinition < Definition
123
100
  # Public: Alias for definition name.
124
- alias_method :operation_name, :definition_name
101
+ alias operation_name definition_name
125
102
  end
126
103
 
127
104
  class FragmentDefinition < Definition
128
105
  end
129
106
 
130
- def parse(str)
107
+ def parse(str, filename = nil, lineno = nil)
108
+ if filename.nil? || lineno.nil?
109
+ filename, lineno, = caller(1, 1).first.split(":", 3)
110
+ lineno = lineno.to_i
111
+ end
112
+
131
113
  definition_dependencies = Set.new
132
114
 
133
- str = str.gsub(/\.\.\.([a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)+)/) { |m|
134
- const_name = $1
115
+ str = str.gsub(/\.\.\.([a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)+)/) do
116
+ match = Regexp.last_match
117
+ const_name = match[1]
135
118
  case fragment = ActiveSupport::Inflector.safe_constantize(const_name)
136
119
  when FragmentDefinition
137
120
  definition_dependencies.merge(fragment.document.definitions)
138
121
  "...#{fragment.definition_name}"
139
- when nil
140
- raise NameError, "uninitialized constant #{const_name}\n#{str}"
141
122
  else
142
- raise TypeError, "expected #{const_name} to be a #{FragmentDefinition}, but was a #{fragment.class}"
123
+ if fragment
124
+ error = TypeError.new("expected #{const_name} to be a #{FragmentDefinition}, but was a #{fragment.class}")
125
+ else
126
+ error = NameError.new("uninitialized constant #{const_name}")
127
+ end
128
+
129
+ if filename && lineno
130
+ error.set_backtrace(["#{filename}:#{lineno + match.pre_match.count("\n") + 1}"] + caller)
131
+ end
132
+
133
+ raise error
143
134
  end
144
- }
135
+ end
145
136
 
146
137
  doc = GraphQL.parse(str)
147
138
 
@@ -149,8 +140,7 @@ module GraphQL
149
140
  node.name ||= "__anonymous__"
150
141
  end
151
142
 
152
- definition_dependencies.merge(doc.definitions)
153
- document_dependencies = Language::Nodes::Document.new(definitions: definition_dependencies.to_a)
143
+ document_dependencies = Language::Nodes::Document.new(definitions: doc.definitions + definition_dependencies.to_a)
154
144
 
155
145
  if @schema
156
146
  rules = GraphQL::StaticValidation::ALL_RULES - [GraphQL::StaticValidation::FragmentsAreUsed]
@@ -159,7 +149,10 @@ module GraphQL
159
149
 
160
150
  errors = validator.validate(query)
161
151
  errors.fetch(:errors).each do |error|
162
- raise ValidationError, error["message"] + "\n\n" + str
152
+ validation_line = error["locations"][0]["line"]
153
+ error = ValidationError.new(error["message"])
154
+ error.set_backtrace(["#{filename}:#{lineno + validation_line}"] + caller) if filename && lineno
155
+ raise error
163
156
  end
164
157
  end
165
158
 
@@ -171,12 +164,13 @@ module GraphQL
171
164
  definitions[node.name] = definition
172
165
  end
173
166
 
174
- rename_node = -> (node, parent) {
175
- if definition = definitions[node.name]
167
+ rename_node = ->(node, _parent) do
168
+ definition = definitions[node.name]
169
+ if definition
176
170
  node.extend(LazyName)
177
171
  node.name = -> { definition.definition_name }
178
172
  end
179
- }
173
+ end
180
174
  visitor = Language::Visitor.new(doc)
181
175
  visitor[Language::Nodes::FragmentDefinition].leave << rename_node
182
176
  visitor[Language::Nodes::OperationDefinition].leave << rename_node
@@ -185,9 +179,7 @@ module GraphQL
185
179
 
186
180
  doc.deep_freeze
187
181
 
188
- if document_tracking_enabled
189
- self.document.definitions.concat(doc.definitions)
190
- end
182
+ document.definitions.concat(doc.definitions) if document_tracking_enabled
191
183
 
192
184
  if definitions[nil]
193
185
  definitions[nil]
@@ -200,87 +192,15 @@ module GraphQL
200
192
  end
201
193
  end
202
194
 
203
- def document
204
- @document
205
- end
206
-
207
- class Response
208
- attr_reader :extensions
209
-
210
- def initialize(extensions: nil)
211
- @extensions = extensions || {}
212
- end
213
- end
214
-
215
- class SuccessfulResponse < Response
216
- attr_reader :data
217
-
218
- def initialize(data:, **kargs)
219
- @data = data
220
- super(**kargs)
221
- end
222
- end
223
-
224
- class PartialResponse < SuccessfulResponse
225
- attr_reader :errors
226
-
227
- def initialize(errors:, **kargs)
228
- @errors = errors
229
- super(**kargs)
230
- end
231
- end
232
-
233
- class FailedResponse < Response
234
- attr_reader :errors
235
-
236
- def initialize(errors:, **kargs)
237
- @errors = errors
238
- super(**kargs)
239
- end
240
- end
241
-
242
- class Query
243
- attr_reader :document, :operation_name, :variables, :context
244
-
245
- def initialize(document, operation_name: nil, variables: {}, context: {})
246
- @document = document
247
- @operation_name = operation_name
248
- @variables = variables
249
- @context = context
250
- end
251
-
252
- def to_s
253
- document.to_query_string
254
- end
255
-
256
- def operation
257
- document.definitions.find { |node| node.name == operation_name }
258
- end
259
-
260
- def operation_type
261
- operation.operation_type
262
- end
263
-
264
- def payload
265
- {
266
- document: document,
267
- operation_name: operation_name,
268
- operation_type: operation_type,
269
- variables: variables
270
- }
271
- end
272
- end
195
+ attr_reader :document
273
196
 
274
197
  def query(definition, variables: {}, context: {})
275
- unless fetch
276
- raise Error, "client network fetching not configured"
277
- end
198
+ raise Error, "client network fetching not configured" unless fetch
278
199
 
279
200
  query = Query.new(definition.document,
280
- operation_name: definition.operation_name,
281
- variables: variables,
282
- context: context
283
- )
201
+ operation_name: definition.operation_name,
202
+ variables: variables,
203
+ context: context)
284
204
 
285
205
  result = ActiveSupport::Notifications.instrument("query.graphql", query.payload) do
286
206
  fetch.call(query)
@@ -316,11 +236,10 @@ module GraphQL
316
236
  fetch.call(IntrospectionQuery)
317
237
  end
318
238
 
319
- private
320
- module LazyName
321
- def name
322
- @name.call
323
- end
239
+ module LazyName
240
+ def name
241
+ @name.call
324
242
  end
243
+ end
325
244
  end
326
245
  end
@@ -0,0 +1,5 @@
1
+ module GraphQL
2
+ class Client
3
+ class Error < StandardError; end
4
+ end
5
+ end
@@ -2,12 +2,36 @@ require "action_view"
2
2
 
3
3
  module GraphQL
4
4
  class Client
5
+ # Public: Extended Erubis implementation that supports GraphQL static
6
+ # query sections.
7
+ #
8
+ # <%graphql
9
+ # query GetVerison {
10
+ # version
11
+ # }
12
+ # %>
13
+ # <%= data.version %>
14
+ #
15
+ # Configure ActionView's default ERB implementation to use this class.
16
+ #
17
+ # ActionView::Template::Handlers::ERB.erb_implementation = GraphQL::Client::Erubis
18
+ #
5
19
  class Erubis < ActionView::Template::Handlers::Erubis
6
- def self.extract_graphql_sections(src)
7
- src.scan(/<%graphql([^%]+)%>/).flatten.first
20
+ # Public: Extract GraphQL section from ERB template.
21
+ #
22
+ # src - String ERB text
23
+ #
24
+ # Returns String GraphQL query and line number or nil or no section was
25
+ # defined.
26
+ def self.extract_graphql_section(src)
27
+ query_string = src.scan(/<%graphql([^%]+)%>/).flatten.first
28
+ if query_string
29
+ return query_string, Regexp.last_match.pre_match.count("\n") + 1
30
+ end
8
31
  end
9
32
 
10
- # Ignore static <%graphql sections
33
+ # Internal: Extend Rails' Erubis handler to simply ignore <%graphql
34
+ # sections.
11
35
  def convert_input(src, input)
12
36
  input = input.gsub(/<%graphql/, "<%#")
13
37
  super(src, input)
@@ -4,19 +4,55 @@ require "uri"
4
4
 
5
5
  module GraphQL
6
6
  class Client
7
+ # Public: Basic HTTP network adapter.
8
+ #
9
+ # GraphQL::Client::Client.new(
10
+ # fetch: GraphQL::Client::HTTP.new("http://graphql-swapi.parseapp.com/")
11
+ # )
12
+ #
13
+ # Assumes GraphQL endpoint follows the express-graphql endpoint conventions.
14
+ # https://github.com/graphql/express-graphql#http-usage
15
+ #
16
+ # Production applications should consider implementing there own network
17
+ # adapter. This class exists for trivial stock usage and allows for minimal
18
+ # request header configuration.
7
19
  class HTTP
8
- attr_reader :uri
9
-
10
- # GraphQL::Client::HTTP.new("http://graphql-swapi.parseapp.com/")
20
+ # Public: Create HTTP adapter instance for a single GraphQL endpoint.
21
+ #
22
+ # GraphQL::Client::HTTP.new("http://graphql-swapi.parseapp.com/") do
23
+ # def headers(query)
24
+ # { "User-Agent": "My Client" }
25
+ # end
26
+ # end
27
+ #
28
+ # uri - String endpoint URI
29
+ # block - Optional block to configure class
11
30
  def initialize(uri, &block)
12
- @uri = ::URI.parse(uri)
31
+ @uri = URI.parse(uri)
13
32
  class_eval(&block) if block_given?
14
33
  end
15
34
 
16
- def headers(query)
35
+ # Public: Parsed endpoint URI
36
+ #
37
+ # Returns URI.
38
+ attr_reader :uri
39
+
40
+ # Public: Extension point for subclasses to set custom request headers.
41
+ #
42
+ # query - The GraphQL::Client::Query being sent
43
+ #
44
+ # Returns Hash of String header names and values.
45
+ def headers(_)
17
46
  {}
18
47
  end
19
48
 
49
+ # Public: Make an HTTP request for GraphQL query.
50
+ #
51
+ # Implements Client's "fetch" adapter interface.
52
+ #
53
+ # query - The GraphQL::Client::Query being sent
54
+ #
55
+ # Returns { "data" => ... , "errors" => ... } Hash.
20
56
  def call(query)
21
57
  http = Net::HTTP.new(uri.host, uri.port)
22
58
  http.use_ssl = uri.scheme == "https"
@@ -2,13 +2,33 @@ require "active_support/log_subscriber"
2
2
 
3
3
  module GraphQL
4
4
  class Client
5
+ # Public: Logger for "*.graphql" notification events.
6
+ #
7
+ # Logs GraphQL queries to Rails logger.
8
+ #
9
+ # QUERY (123ms) UsersController::ShowQuery
10
+ # MUTATION (456ms) UsersController::UpdateMutation
11
+ #
12
+ # Enable GraphQL Client query logging.
13
+ #
14
+ # require "graphql/client/log_subscriber"
15
+ # GraphQL::Client::LogSubscriber.attach_to :graphql
16
+ #
5
17
  class LogSubscriber < ActiveSupport::LogSubscriber
6
18
  def query(event)
7
- info { "#{event.payload[:name]} (#{event.duration.round(1)}ms) #{event.payload[:operation_name].gsub("__", "::")}" }
8
- debug { event.payload[:document].to_query_string }
19
+ # TODO: Colorize output
20
+ info do
21
+ [
22
+ event.payload[:operation_type].upcase,
23
+ "(#{event.duration.round(1)}ms)",
24
+ event.payload[:operation_name].gsub("__", "::")
25
+ ].join(" ")
26
+ end
27
+
28
+ debug do
29
+ event.payload[:document].to_query_string
30
+ end
9
31
  end
10
32
  end
11
33
  end
12
34
  end
13
-
14
- GraphQL::Client::LogSubscriber.attach_to :graphql
@@ -0,0 +1,65 @@
1
+ module GraphQL
2
+ class Client
3
+ class Query
4
+ # Internal: Construct Query.
5
+ #
6
+ # Avoid creating queries with this constructor, perfer using Client#query.
7
+ #
8
+ # document - A parsed GraphQL::Language::Nodes::Document of the query
9
+ # operation_name - String operation to execute
10
+ # variables - Hash of variables to execute with the operation
11
+ # context - Hash of metadata to pass to network adapter
12
+ def initialize(document, operation_name: nil, variables: {}, context: {})
13
+ @document = document
14
+ @operation_name = operation_name
15
+ @variables = variables
16
+ @context = context
17
+ end
18
+
19
+ # Public: A parsed GraphQL::Language::Nodes::Document of the query.
20
+ attr_reader :document
21
+
22
+ # Public: String name of operation to execute.
23
+ attr_reader :operation_name
24
+
25
+ # Public: Hash of variables to execute with the operation.
26
+ attr_reader :variables
27
+
28
+ # Public: Hash of contextual metadata.
29
+ attr_reader :context
30
+
31
+ # Public: Serialized query string
32
+ #
33
+ # Returns String.
34
+ def to_s
35
+ document.to_query_string
36
+ end
37
+
38
+ # Public: Get operation definition node.
39
+ #
40
+ # Returns GraphQL::Language::Nodes::OperationDefinition.
41
+ def operation
42
+ document.definitions.find { |node| node.name == operation_name }
43
+ end
44
+
45
+ # Public: Query operation type
46
+ #
47
+ # Returns "query", "mutation" or "subscription".
48
+ def operation_type
49
+ operation.operation_type
50
+ end
51
+
52
+ # Internal: Payload object to pass to ActiveSupport::Notifications.
53
+ #
54
+ # Returns Hash.
55
+ def payload
56
+ {
57
+ document: document,
58
+ operation_name: operation_name,
59
+ operation_type: operation_type,
60
+ variables: variables
61
+ }
62
+ end
63
+ end
64
+ end
65
+ end
@@ -42,9 +42,7 @@ module GraphQL
42
42
 
43
43
  # Convert GraphQL camelcase to snake case: commitComments -> commit_comments
44
44
  field_alias = ActiveSupport::Inflector.underscore(field)
45
- if field != field_alias
46
- send :alias_method, field_alias, field
47
- end
45
+ send :alias_method, field_alias, field if field != field_alias
48
46
 
49
47
  class_eval <<-RUBY, __FILE__, __LINE__
50
48
  def #{field_alias}?
@@ -52,15 +50,14 @@ module GraphQL
52
50
  end
53
51
  RUBY
54
52
 
55
- if field == "edges"
56
- class_eval <<-RUBY, __FILE__, __LINE__
53
+ next unless field == "edges"
54
+ class_eval <<-RUBY, __FILE__, __LINE__
57
55
  def each_node
58
56
  return enum_for(:each_node) unless block_given?
59
57
  edges.each { |edge| yield edge.node }
60
58
  self
61
59
  end
62
- RUBY
63
- end
60
+ RUBY
64
61
  end
65
62
 
66
63
  assigns = fields.map do |field, type|
@@ -85,12 +82,12 @@ module GraphQL
85
82
  end
86
83
  end
87
84
 
88
- def self.source_node
89
- @source_node
85
+ class << self
86
+ attr_reader :source_node
90
87
  end
91
88
 
92
- def self.fields
93
- @fields
89
+ class << self
90
+ attr_reader :fields
94
91
  end
95
92
 
96
93
  def self.name
@@ -98,7 +95,7 @@ module GraphQL
98
95
  end
99
96
 
100
97
  def self.inspect
101
- "#<#{self.name} fields=#{@fields.keys.inspect}>"
98
+ "#<#{name} fields=#{@fields.keys.inspect}>"
102
99
  end
103
100
 
104
101
  def self.cast(obj)
@@ -110,9 +107,9 @@ module GraphQL
110
107
  when QueryResult
111
108
  spreads = Set.new(self.spreads(obj.class.source_node).map(&:name))
112
109
 
113
- if !spreads.include?(self.source_node.name)
114
- message = "couldn't cast #{obj.inspect} to #{self.inspect}\n\n"
115
- suggestion = "\n ...#{name || "YourFragment"} # SUGGESTION"
110
+ unless spreads.include?(source_node.name)
111
+ message = "couldn't cast #{obj.inspect} to #{inspect}\n\n"
112
+ suggestion = "\n ...#{name || 'YourFragment'} # SUGGESTION"
116
113
  message << GraphQL::Language::Generation.generate(obj.class.source_node).sub(/\n}$/, "#{suggestion}\n}")
117
114
  raise TypeError, message
118
115
  end
@@ -122,7 +119,7 @@ module GraphQL
122
119
  when NilClass
123
120
  nil
124
121
  else
125
- raise TypeError, "#{obj.class}"
122
+ raise TypeError, obj.class.to_s
126
123
  end
127
124
  end
128
125
 
@@ -150,7 +147,7 @@ module GraphQL
150
147
  end
151
148
 
152
149
  def self.|(other)
153
- new_fields = self.fields.dup
150
+ new_fields = fields.dup
154
151
  other.fields.each do |name, value|
155
152
  if new_fields[name]
156
153
  new_fields[name] |= value
@@ -159,14 +156,14 @@ module GraphQL
159
156
  end
160
157
  end
161
158
  # TODO: Picking first source node seems error prone
162
- define(name: self.name, source_node: self.source_node, fields: new_fields)
159
+ define(name: self.name, source_node: source_node, fields: new_fields)
163
160
  end
164
161
 
165
162
  attr_reader :data
166
- alias_method :to_h, :data
163
+ alias to_h data
167
164
 
168
165
  def inspect
169
- ivars = (self.class.fields.keys).map { |sym| "#{sym}=#{instance_variable_get("@#{sym}").inspect}" }
166
+ ivars = self.class.fields.keys.map { |sym| "#{sym}=#{instance_variable_get("@#{sym}").inspect}" }
170
167
  buf = "#<#{self.class.name}"
171
168
  buf << " " << ivars.join(" ") if ivars.any?
172
169
  buf << ">"
@@ -178,6 +175,10 @@ module GraphQL
178
175
  rescue NoMethodError => e
179
176
  raise NoMethodError, "undefined method `#{e.name}' for #{inspect}"
180
177
  end
178
+
179
+ def respond_to_missing?(*args)
180
+ super
181
+ end
181
182
  end
182
183
  end
183
184
  end
@@ -1,6 +1,5 @@
1
1
  require "graphql"
2
2
  require "graphql/client"
3
- require "graphql/client/log_subscriber"
4
3
  require "rails/railtie"
5
4
 
6
5
  module GraphQL
@@ -11,12 +10,17 @@ module GraphQL
11
10
 
12
11
  # Eager load leaky dependency to workaround AS::Dependencies unloading issues
13
12
  # https://github.com/rmosolgo/graphql-ruby/pull/240
14
- initializer "graphql.eager_load_hack" do |app|
13
+ initializer "graphql.eager_load_hack" do |_app|
15
14
  require "graphql"
16
15
  GraphQL::BOOLEAN_TYPE.name
17
16
  end
18
17
 
19
- initializer "graphql.configure_erb_implementation" do |app|
18
+ initializer "graphql.configure_log_subscriber" do |_app|
19
+ require "graphql/client/log_subscriber"
20
+ GraphQL::Client::LogSubscriber.attach_to :graphql
21
+ end
22
+
23
+ initializer "graphql.configure_erb_implementation" do |_app|
20
24
  require "graphql/client/erubis"
21
25
  ActionView::Template::Handlers::ERB.erb_implementation = GraphQL::Client::Erubis
22
26
  end
@@ -27,11 +31,13 @@ module GraphQL
27
31
  path = app.paths["app/views"].first
28
32
  client = config.graphql.client
29
33
 
30
- Object.const_set(:Views, Module.new {
34
+ config.watchable_dirs[path] = [:erb]
35
+
36
+ Object.const_set(:Views, Module.new do
31
37
  extend GraphQL::Client::ViewModule
32
38
  self.path = path
33
39
  self.client = client
34
- })
40
+ end)
35
41
  end
36
42
  end
37
43
  end
@@ -0,0 +1,87 @@
1
+ require "graphql/client/error"
2
+
3
+ module GraphQL
4
+ class Client
5
+ # Public: Abstract base class for GraphQL responses.
6
+ #
7
+ # https://facebook.github.io/graphql/#sec-Response-Format
8
+ class Response
9
+ # Public: Hash of server specific extension metadata.
10
+ attr_reader :extensions
11
+
12
+ # Internal: Initialize base class.
13
+ def initialize(extensions: nil)
14
+ @extensions = extensions || {}
15
+ end
16
+ end
17
+
18
+ class SuccessfulResponse < Response
19
+ # Public: Wrapped QueryResult of data returned from the server.
20
+ #
21
+ # https://facebook.github.io/graphql/#sec-Data
22
+ #
23
+ # Returns instance of QueryResult subclass.
24
+ attr_reader :data
25
+
26
+ # Internal: Initialize SuccessfulResponse.
27
+ def initialize(data:, **kargs)
28
+ @data = data
29
+ super(**kargs)
30
+ end
31
+ end
32
+
33
+ class PartialResponse < SuccessfulResponse
34
+ # Public: Get partial failures from response.
35
+ #
36
+ # https://facebook.github.io/graphql/#sec-Errors
37
+ #
38
+ # Returns ResponseErrors collection object.
39
+ attr_reader :errors
40
+
41
+ # Internal: Initialize PartialResponse.
42
+ def initialize(errors:, **kargs)
43
+ @errors = errors
44
+ super(**kargs)
45
+ end
46
+ end
47
+
48
+ class FailedResponse < Response
49
+ # Public: Get errors from response.
50
+ #
51
+ # https://facebook.github.io/graphql/#sec-Errors
52
+ #
53
+ # Returns ResponseErrors collection object.
54
+ attr_reader :errors
55
+
56
+ # Internal: Initialize FailedResponse.
57
+ def initialize(errors:, **kargs)
58
+ @errors = errors
59
+ super(**kargs)
60
+ end
61
+ end
62
+
63
+ class ResponseError < Error
64
+ def initialize(definition, error)
65
+ @request_definition = definition
66
+ @locations = error["locations"]
67
+ super error["message"]
68
+ end
69
+ end
70
+
71
+ class ResponseErrors < Error
72
+ include Enumerable
73
+
74
+ attr_reader :errors
75
+
76
+ def initialize(definition, errors)
77
+ @request_definition = definition
78
+ @errors = errors.map { |error| ResponseError.new(definition, error) }
79
+ super @errors.map(&:message).join(", ")
80
+ end
81
+
82
+ def each(&block)
83
+ errors.each(&block)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -20,17 +20,14 @@ module GraphQL
20
20
  #
21
21
  # Returns nothing.
22
22
  def eager_load!
23
- return unless File.directory?(self.path)
23
+ return unless File.directory?(path)
24
24
 
25
- Dir.entries(self.path).each do |entry|
25
+ Dir.entries(path).each do |entry|
26
26
  next if entry == "." || entry == ".."
27
27
  name = entry.sub(/(\.\w+)+$/, "").camelize.to_sym
28
28
  if ViewModule.valid_constant_name?(name) && loadable_const_defined?(name)
29
29
  mod = const_get(name, false)
30
30
  mod.eager_load!
31
- else
32
- # Ignore template names that don't camelize to safe constants:
33
- # 404, foo-dash
34
31
  end
35
32
  end
36
33
 
@@ -97,7 +94,7 @@ module GraphQL
97
94
  # Returns String absolute path to file, otherwise nil.
98
95
  def const_path(name)
99
96
  pathname = ActiveSupport::Inflector.underscore(name.to_s)
100
- Dir[File.join(self.path, "{#{pathname},_#{pathname}}{/,.*}")].map { |fn| File.expand_path(fn) }.first
97
+ Dir[File.join(path, "{#{pathname},_#{pathname}}{/,.*}")].map { |fn| File.expand_path(fn) }.first
101
98
  end
102
99
 
103
100
  # Internal: Initialize new module for constant name and load ERB statics.
@@ -115,13 +112,12 @@ module GraphQL
115
112
 
116
113
  if File.extname(path) == ".erb"
117
114
  contents = File.read(path)
118
- query = GraphQL::Client::Erubis.extract_graphql_sections(contents)
119
- # TODO: Use generic client parser
120
- mod = client.parse(query) if query
115
+ query, lineno = GraphQL::Client::Erubis.extract_graphql_section(contents)
116
+ mod = client.parse(query, path, lineno) if query
121
117
  end
122
118
 
123
119
  mod.extend(ViewModule)
124
- mod.client = self.client
120
+ mod.client = client
125
121
  mod.path = path
126
122
  mod
127
123
  end
@@ -132,7 +128,9 @@ module GraphQL
132
128
  #
133
129
  # Returns module or raises NameError if missing.
134
130
  def const_missing(name)
135
- if path = const_path(name)
131
+ path = const_path(name)
132
+
133
+ if path
136
134
  mod = load_module(path)
137
135
  const_set(name, mod)
138
136
  mod.unloadable
@@ -9,9 +9,7 @@ module GraphQL
9
9
  # Returns self Node.
10
10
  def deep_freeze
11
11
  self.class.child_attributes.each do |attr_name|
12
- public_send(attr_name).freeze.each do |node|
13
- node.deep_freeze
14
- end
12
+ public_send(attr_name).freeze.each(&:deep_freeze)
15
13
  end
16
14
  freeze
17
15
  end
@@ -16,7 +16,7 @@ module GraphQL
16
16
  seen = Set.new([operation_name])
17
17
  stack = [operation_name]
18
18
 
19
- while stack.length > 0
19
+ until stack.empty?
20
20
  name = stack.pop
21
21
  names = find_definition_fragment_spreads(document, name)
22
22
  seen.merge(names)
@@ -28,12 +28,12 @@ module GraphQL
28
28
 
29
29
  def self.find_definition_fragment_spreads(document, definition_name)
30
30
  definition = document.definitions.find { |node| node.name == definition_name }
31
- raise "missing definition: #{definition_name}" if !definition
31
+ raise "missing definition: #{definition_name}" unless definition
32
32
  spreads = Set.new
33
33
  visitor = Visitor.new(definition)
34
- visitor[Nodes::FragmentSpread].enter << -> (node, parent) {
34
+ visitor[Nodes::FragmentSpread].enter << -> (node, _parent) do
35
35
  spreads << node.name
36
- }
36
+ end
37
37
  visitor.visit
38
38
  spreads
39
39
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.18
4
+ version: 0.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-10 00:00:00.000000000 Z
11
+ date: 2016-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: actionpack
14
+ name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -31,7 +31,21 @@ dependencies:
31
31
  - !ruby/object:Gem::Version
32
32
  version: '6.0'
33
33
  - !ruby/object:Gem::Dependency
34
- name: activesupport
34
+ name: graphql
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.18'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.18'
47
+ - !ruby/object:Gem::Dependency
48
+ name: actionpack
35
49
  requirement: !ruby/object:Gem::Requirement
36
50
  requirements:
37
51
  - - ">="
@@ -40,7 +54,7 @@ dependencies:
40
54
  - - "<"
41
55
  - !ruby/object:Gem::Version
42
56
  version: '6.0'
43
- type: :runtime
57
+ type: :development
44
58
  prerelease: false
45
59
  version_requirements: !ruby/object:Gem::Requirement
46
60
  requirements:
@@ -51,47 +65,47 @@ dependencies:
51
65
  - !ruby/object:Gem::Version
52
66
  version: '6.0'
53
67
  - !ruby/object:Gem::Dependency
54
- name: graphql
68
+ name: minitest
55
69
  requirement: !ruby/object:Gem::Requirement
56
70
  requirements:
57
71
  - - "~>"
58
72
  - !ruby/object:Gem::Version
59
- version: '0.18'
60
- type: :runtime
73
+ version: '5.9'
74
+ type: :development
61
75
  prerelease: false
62
76
  version_requirements: !ruby/object:Gem::Requirement
63
77
  requirements:
64
78
  - - "~>"
65
79
  - !ruby/object:Gem::Version
66
- version: '0.18'
80
+ version: '5.9'
67
81
  - !ruby/object:Gem::Dependency
68
- name: minitest
82
+ name: rake
69
83
  requirement: !ruby/object:Gem::Requirement
70
84
  requirements:
71
85
  - - "~>"
72
86
  - !ruby/object:Gem::Version
73
- version: '5.9'
87
+ version: '11.2'
74
88
  type: :development
75
89
  prerelease: false
76
90
  version_requirements: !ruby/object:Gem::Requirement
77
91
  requirements:
78
92
  - - "~>"
79
93
  - !ruby/object:Gem::Version
80
- version: '5.9'
94
+ version: '11.2'
81
95
  - !ruby/object:Gem::Dependency
82
- name: rake
96
+ name: rubocop
83
97
  requirement: !ruby/object:Gem::Requirement
84
98
  requirements:
85
99
  - - "~>"
86
100
  - !ruby/object:Gem::Version
87
- version: '11.2'
101
+ version: '0.42'
88
102
  type: :development
89
103
  prerelease: false
90
104
  version_requirements: !ruby/object:Gem::Requirement
91
105
  requirements:
92
106
  - - "~>"
93
107
  - !ruby/object:Gem::Version
94
- version: '11.2'
108
+ version: '0.42'
95
109
  description: "???"
96
110
  email: engineering@github.com
97
111
  executables: []
@@ -100,11 +114,14 @@ extra_rdoc_files: []
100
114
  files:
101
115
  - LICENSE
102
116
  - lib/graphql/client.rb
117
+ - lib/graphql/client/error.rb
103
118
  - lib/graphql/client/erubis.rb
104
119
  - lib/graphql/client/http.rb
105
120
  - lib/graphql/client/log_subscriber.rb
121
+ - lib/graphql/client/query.rb
106
122
  - lib/graphql/client/query_result.rb
107
123
  - lib/graphql/client/railtie.rb
124
+ - lib/graphql/client/response.rb
108
125
  - lib/graphql/client/view_module.rb
109
126
  - lib/graphql/language/nodes/deep_freeze_ext.rb
110
127
  - lib/graphql/language/operation_slice.rb