graphql-client 0.2.6 → 0.3.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
  SHA1:
3
- metadata.gz: 6fb2c7543a34c26a3ffa6718ddb35a4e4ae9972c
4
- data.tar.gz: f879a3fff89104e8c5eff98ba15c62ec2694de17
3
+ metadata.gz: 490142029326d682bd6956d1f825d9429aa49389
4
+ data.tar.gz: 3cc776110140c024c801f8b3a9eb52bf72cc924f
5
5
  SHA512:
6
- metadata.gz: d0b95e7dd51deebc8edd667ac3b824f270173992f5b8d7017eb96490c0a9eab6e4fdee58a989209640062e3f70a74f52e607a056b730ca34eeb6bc6599ef6d99
7
- data.tar.gz: 2c21b4f7ec54721953afaeb88f41f10af9b13006cfbaca45e6573649df23b464afa39d6208d4dacc29ce0bfdc558a67290e3915afd6d094ea7aa7a50000137a0
6
+ metadata.gz: 2e3cba4f02d0fff593cadcbd0d39bcdecb0576f087bb9088f2dc5902426bb54b7829ea3eb7d8d96c86fae155eb6ba248c5414ba24006834c8a4d806063e1be4c
7
+ data.tar.gz: bb8b0a56f1f1d0be7a4315aa626af65a08e7285adb03fb02e382a0fb6fdb53e67326ed6654f171709f267897141e396813ac2245f6c45097157b78f492dba7da
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
1
2
  require "active_support/inflector"
2
3
  require "active_support/notifications"
3
4
  require "graphql"
4
5
  require "graphql/client/error"
5
6
  require "graphql/client/errors"
6
7
  require "graphql/client/query_result"
8
+ require "graphql/client/query_typename"
7
9
  require "graphql/client/response"
8
10
  require "graphql/language/nodes/deep_freeze_ext"
9
11
  require "json"
@@ -95,9 +97,11 @@ module GraphQL
95
97
  end
96
98
  end
97
99
 
98
- def initialize(node:, document:)
100
+ def initialize(node:, document:, schema:, document_types:)
99
101
  @definition_node = node
100
102
  @document = document
103
+ @schema = schema
104
+ @document_types = document_types
101
105
  end
102
106
 
103
107
  # Internal: Get underlying operation or fragment defintion AST node for
@@ -130,13 +134,15 @@ module GraphQL
130
134
  # and any FragmentDefinition dependencies.
131
135
  attr_reader :document
132
136
 
137
+ attr_reader :schema
138
+
133
139
  def new(*args)
134
140
  type.new(*args)
135
141
  end
136
142
 
137
143
  def type
138
144
  # TODO: Fix type indirection
139
- @type ||= GraphQL::Client::QueryResult.wrap(definition_node, name: "#{name}.type")
145
+ @type ||= GraphQL::Client::QueryResult.wrap(definition_node, name: "#{name}.type", types: @document_types)
140
146
  end
141
147
  end
142
148
 
@@ -208,13 +214,24 @@ module GraphQL
208
214
  error.set_backtrace(["#{filename}:#{lineno + validation_line}"] + caller) if filename && lineno
209
215
  raise error
210
216
  end
217
+
218
+ document_types = DocumentTypes.analyze_types(@schema, doc).freeze
219
+ else
220
+ document_types = {}.freeze
211
221
  end
212
222
 
223
+ QueryTypename.insert_typename_fields(doc, types: document_types)
224
+
213
225
  definitions = {}
214
226
  doc.definitions.each do |node|
215
227
  node.name = nil if node.name == "__anonymous__"
216
228
  sliced_document = Language::DefinitionSlice.slice(document_dependencies, node.name)
217
- definition = Definition.for(node: node, document: sliced_document)
229
+ definition = Definition.for(
230
+ schema: @schema,
231
+ node: node,
232
+ document: sliced_document,
233
+ document_types: document_types
234
+ )
218
235
  definitions[node.name] = definition
219
236
  end
220
237
 
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+ require "graphql"
3
+
4
+ module GraphQL
5
+ class Client
6
+ # Internal: Use schema to detect definition and field types.
7
+ module DocumentTypes
8
+ # Internal: Detect all types used in a given document
9
+ #
10
+ # schema - A GraphQL::Schema
11
+ # document - A GraphQL::Language::Nodes::Document to scan
12
+ #
13
+ # Returns a Hash[Language::Nodes::Node] to GraphQL::Type objects.
14
+ def self.analyze_types(schema, document)
15
+ unless schema.is_a?(GraphQL::Schema)
16
+ raise TypeError, "expected schema to be a GraphQL::Schema, but was #{schema.class}"
17
+ end
18
+
19
+ unless document.is_a?(GraphQL::Language::Nodes::Document)
20
+ raise TypeError, "expected schema to be a GraphQL::Language::Nodes::Document, but was #{document.class}"
21
+ end
22
+
23
+ visitor = GraphQL::Language::Visitor.new(document)
24
+ type_stack = GraphQL::StaticValidation::TypeStack.new(schema, visitor)
25
+
26
+ fields = {}
27
+
28
+ visitor[GraphQL::Language::Nodes::OperationDefinition] << ->(node, _parent) do
29
+ fields[node] = type_stack.object_types.last
30
+ end
31
+ visitor[GraphQL::Language::Nodes::FragmentDefinition] << ->(node, _parent) do
32
+ fields[node] = type_stack.object_types.last
33
+ end
34
+ visitor[GraphQL::Language::Nodes::Field] << ->(node, _parent) do
35
+ fields[node] = type_stack.field_definitions.last.type
36
+ end
37
+ visitor.visit
38
+
39
+ fields
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Client
3
4
  # Public: Abstract base class for all errors raised by GraphQL::Client.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "graphql/client/hash_with_indifferent_access"
2
3
 
3
4
  module GraphQL
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "action_view"
2
3
 
3
4
  module GraphQL
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "active_support/inflector"
2
3
 
3
4
  module GraphQL
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "json"
2
3
  require "net/http"
3
4
  require "uri"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "graphql/client/errors"
2
3
 
3
4
  module GraphQL
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "active_support/log_subscriber"
2
3
 
3
4
  module GraphQL
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "active_support/inflector"
2
3
  require "graphql"
3
4
  require "graphql/client/errors"
@@ -16,7 +17,7 @@ module GraphQL
16
17
  # Internal: Get QueryResult class for result of query.
17
18
  #
18
19
  # Returns subclass of QueryResult or nil.
19
- def self.wrap(node, name: nil)
20
+ def self.wrap(node, name: nil, types: {})
20
21
  fields = {}
21
22
 
22
23
  node.selections.each do |selection|
@@ -25,27 +26,29 @@ module GraphQL
25
26
  nil
26
27
  when Language::Nodes::Field
27
28
  field_name = selection.alias || selection.name
28
- field_klass = selection.selections.any? ? wrap(selection, name: "#{name}[:#{field_name}]") : nil
29
+ field_klass = nil
30
+ field_klass = wrap(selection, name: "#{name}[:#{field_name}]", types: types) if selection.selections.any?
29
31
  fields[field_name] ? fields[field_name] |= field_klass : fields[field_name] = field_klass
30
32
  when Language::Nodes::InlineFragment
31
- wrap(selection, name: name).fields.each do |fragment_name, klass|
33
+ wrap(selection, name: name, types: types).fields.each do |fragment_name, klass|
32
34
  fields[fragment_name.to_s] ? fields[fragment_name.to_s] |= klass : fields[fragment_name.to_s] = klass
33
35
  end
34
36
  end
35
37
  end
36
38
 
37
- define(name: name, source_node: node, fields: fields)
39
+ define(name: name, source_node: node, fields: fields, type: types[node] && types[node].unwrap)
38
40
  end
39
41
 
40
42
  # Internal
41
- def self.define(name:, source_node:, fields: {})
43
+ def self.define(name:, source_node:, fields: {}, type: nil)
42
44
  Class.new(self) do
43
45
  @name = name
46
+ @type = type
44
47
  @source_node = source_node
45
48
  @fields = {}
46
49
 
47
- fields.each do |field, type|
48
- @fields[field.to_sym] = type
50
+ fields.each do |field, klass|
51
+ @fields[field.to_sym] = klass
49
52
 
50
53
  send :attr_reader, field
51
54
 
@@ -69,8 +72,8 @@ module GraphQL
69
72
  RUBY
70
73
  end
71
74
 
72
- assigns = fields.map do |field, type|
73
- if type
75
+ assigns = fields.map do |field, klass|
76
+ if klass
74
77
  <<-RUBY
75
78
  @#{field} = self.class.fields[:#{field}].cast(@data["#{field}"], @errors.filter_by_path("#{field}"))
76
79
  RUBY
@@ -81,6 +84,10 @@ module GraphQL
81
84
  end
82
85
  end
83
86
 
87
+ if @type && @type.is_a?(GraphQL::ObjectType)
88
+ assigns.unshift "@__typename = self.class.type.name"
89
+ end
90
+
84
91
  class_eval <<-RUBY, __FILE__, __LINE__
85
92
  def initialize(data, errors = Errors.new)
86
93
  @data = data
@@ -94,6 +101,8 @@ module GraphQL
94
101
  end
95
102
 
96
103
  class << self
104
+ attr_reader :type
105
+
97
106
  attr_reader :source_node
98
107
 
99
108
  attr_reader :fields
@@ -177,6 +186,9 @@ module GraphQL
177
186
  attr_reader :data
178
187
  alias to_h data
179
188
 
189
+ attr_reader :__typename
190
+ alias typename __typename
191
+
180
192
  def inspect
181
193
  ivars = self.class.fields.keys.map do |sym|
182
194
  value = instance_variable_get("@#{sym}")
@@ -186,7 +198,7 @@ module GraphQL
186
198
  "#{sym}=#{value.inspect}"
187
199
  end
188
200
  end
189
- buf = "#<#{self.class.name}"
201
+ buf = "#<#{self.class.name}".dup
190
202
  buf << " " << ivars.join(" ") if ivars.any?
191
203
  buf << ">"
192
204
  buf
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+ require "graphql"
3
+ require "graphql/client/document_types"
4
+
5
+ module GraphQL
6
+ class Client
7
+ # Internal: Insert __typename field selections into query.
8
+ module QueryTypename
9
+ # Internal: Insert __typename field selections into query.
10
+ #
11
+ # Skips known types when schema is provided.
12
+ #
13
+ # document - GraphQL::Language::Nodes::Document to modify
14
+ # schema - Optional Map of GraphQL::Language::Nodes::Node to GraphQL::Type
15
+ #
16
+ # Returns nothing.
17
+ def self.insert_typename_fields(document, types: {})
18
+ on_selections = ->(node, _parent) do
19
+ return unless node.selections.any?
20
+
21
+ type = types[node]
22
+ case type && type.unwrap
23
+ when NilClass, GraphQL::InterfaceType, GraphQL::UnionType
24
+ names = node_flatten_selections(node.selections).map { |s| s.respond_to?(:name) ? s.name : nil }
25
+ names = Set.new(names.compact)
26
+
27
+ unless names.include?("__typename")
28
+ node.selections = [GraphQL::Language::Nodes::Field.new(name: "__typename")] + node.selections
29
+ end
30
+ end
31
+ end
32
+
33
+ visitor = GraphQL::Language::Visitor.new(document)
34
+ visitor[GraphQL::Language::Nodes::Field].leave << on_selections
35
+ visitor[GraphQL::Language::Nodes::FragmentDefinition].leave << on_selections
36
+ visitor[GraphQL::Language::Nodes::OperationDefinition].leave << on_selections
37
+ visitor.visit
38
+
39
+ nil
40
+ end
41
+
42
+ def self.node_flatten_selections(selections)
43
+ selections.flat_map do |selection|
44
+ case selection
45
+ when GraphQL::Language::Nodes::Field
46
+ selection
47
+ when GraphQL::Language::Nodes::InlineFragment
48
+ node_flatten_selections(selection.selections)
49
+ else
50
+ []
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "graphql"
2
3
  require "graphql/client"
3
4
  require "rails/railtie"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "graphql/client/errors"
2
3
 
3
4
  module GraphQL
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "active_support/dependencies"
2
3
  require "active_support/inflector"
3
4
  require "graphql/client/erubis"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "graphql"
2
3
 
3
4
  module GraphQL
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "rubocop"
2
3
 
3
4
  module RuboCop
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "active_support/inflector"
2
3
  require "graphql"
3
4
  require "graphql/client/erubis"
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.2.6
4
+ version: 0.3.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-11-26 00:00:00.000000000 Z
11
+ date: 2016-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -115,6 +115,7 @@ files:
115
115
  - LICENSE
116
116
  - README.md
117
117
  - lib/graphql/client.rb
118
+ - lib/graphql/client/document_types.rb
118
119
  - lib/graphql/client/error.rb
119
120
  - lib/graphql/client/errors.rb
120
121
  - lib/graphql/client/erubis.rb
@@ -123,6 +124,7 @@ files:
123
124
  - lib/graphql/client/list.rb
124
125
  - lib/graphql/client/log_subscriber.rb
125
126
  - lib/graphql/client/query_result.rb
127
+ - lib/graphql/client/query_typename.rb
126
128
  - lib/graphql/client/railtie.rb
127
129
  - lib/graphql/client/response.rb
128
130
  - lib/graphql/client/view_module.rb
@@ -149,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
151
  version: '0'
150
152
  requirements: []
151
153
  rubyforge_project:
152
- rubygems_version: 2.5.1
154
+ rubygems_version: 2.5.2
153
155
  signing_key:
154
156
  specification_version: 4
155
157
  summary: GraphQL Client