graphql-client 0.2.6 → 0.3.0
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 +4 -4
- data/lib/graphql/client.rb +20 -3
- data/lib/graphql/client/document_types.rb +43 -0
- data/lib/graphql/client/error.rb +1 -0
- data/lib/graphql/client/errors.rb +1 -0
- data/lib/graphql/client/erubis.rb +1 -0
- data/lib/graphql/client/hash_with_indifferent_access.rb +1 -0
- data/lib/graphql/client/http.rb +1 -0
- data/lib/graphql/client/list.rb +1 -0
- data/lib/graphql/client/log_subscriber.rb +1 -0
- data/lib/graphql/client/query_result.rb +22 -10
- data/lib/graphql/client/query_typename.rb +56 -0
- data/lib/graphql/client/railtie.rb +1 -0
- data/lib/graphql/client/response.rb +1 -0
- data/lib/graphql/client/view_module.rb +1 -0
- data/lib/graphql/language/nodes/deep_freeze_ext.rb +1 -0
- data/lib/rubocop/cop/graphql/heredoc.rb +1 -0
- data/lib/rubocop/cop/graphql/overfetch.rb +1 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 490142029326d682bd6956d1f825d9429aa49389
|
4
|
+
data.tar.gz: 3cc776110140c024c801f8b3a9eb52bf72cc924f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e3cba4f02d0fff593cadcbd0d39bcdecb0576f087bb9088f2dc5902426bb54b7829ea3eb7d8d96c86fae155eb6ba248c5414ba24006834c8a4d806063e1be4c
|
7
|
+
data.tar.gz: bb8b0a56f1f1d0be7a4315aa626af65a08e7285adb03fb02e382a0fb6fdb53e67326ed6654f171709f267897141e396813ac2245f6c45097157b78f492dba7da
|
data/lib/graphql/client.rb
CHANGED
@@ -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(
|
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
|
data/lib/graphql/client/error.rb
CHANGED
data/lib/graphql/client/http.rb
CHANGED
data/lib/graphql/client/list.rb
CHANGED
@@ -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 =
|
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,
|
48
|
-
@fields[field.to_sym] =
|
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,
|
73
|
-
if
|
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
|
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.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-
|
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.
|
154
|
+
rubygems_version: 2.5.2
|
153
155
|
signing_key:
|
154
156
|
specification_version: 4
|
155
157
|
summary: GraphQL Client
|