graphql-client 0.8.0 → 0.8.1
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 +25 -20
- data/lib/graphql/client/definition.rb +1 -1
- data/lib/graphql/client/document_types.rb +3 -0
- data/lib/graphql/client/query_result.rb +100 -45
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3207be7a370ae7995dd3355381f4dfc6d839e100
|
4
|
+
data.tar.gz: 80b877dd6c13310c10217a6a65a375728a6a9cb6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 036b98757f630e799ca5f8b111aad802d77f2723bc0cc73dae113c24687189cbfd6ad440224a6ba952902dc401a57a6f7cfa33523c6b764aa83f37e526a3452f
|
7
|
+
data.tar.gz: db865264342c1e9dc7b42d07fbe4ae5d01319514ca884c92bee4aff7e3980436e5fad4a851768f1c97bd371d1ae3a0b7c6460e3c0b895a48bf81dd2d0e3153d8
|
data/lib/graphql/client.rb
CHANGED
@@ -110,32 +110,37 @@ module GraphQL
|
|
110
110
|
|
111
111
|
definition_dependencies = Set.new
|
112
112
|
|
113
|
-
str = str.gsub(/\.\.\.([a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)
|
113
|
+
str = str.gsub(/\.\.\.([a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)*)/) do
|
114
114
|
match = Regexp.last_match
|
115
115
|
const_name = match[1]
|
116
|
-
begin
|
117
|
-
fragment = ActiveSupport::Inflector.constantize(const_name)
|
118
|
-
rescue NameError
|
119
|
-
fragment = nil
|
120
|
-
end
|
121
116
|
|
122
|
-
|
123
|
-
|
124
|
-
definition_dependencies.merge(fragment.document.definitions)
|
125
|
-
"...#{fragment.definition_name}"
|
117
|
+
if str.match(/fragment\s*#{const_name}/)
|
118
|
+
match[0]
|
126
119
|
else
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
end
|
132
|
-
else
|
133
|
-
message = "uninitialized constant #{const_name}"
|
120
|
+
begin
|
121
|
+
fragment = ActiveSupport::Inflector.constantize(const_name)
|
122
|
+
rescue NameError
|
123
|
+
fragment = nil
|
134
124
|
end
|
135
125
|
|
136
|
-
|
137
|
-
|
138
|
-
|
126
|
+
case fragment
|
127
|
+
when FragmentDefinition
|
128
|
+
definition_dependencies.merge(fragment.document.definitions)
|
129
|
+
"...#{fragment.definition_name}"
|
130
|
+
else
|
131
|
+
if fragment
|
132
|
+
message = "expected #{const_name} to be a #{FragmentDefinition}, but was a #{fragment.class}."
|
133
|
+
if fragment.is_a?(Module) && fragment.constants.any?
|
134
|
+
message += " Did you mean #{fragment}::#{fragment.constants.first}?"
|
135
|
+
end
|
136
|
+
else
|
137
|
+
message = "uninitialized constant #{const_name}"
|
138
|
+
end
|
139
|
+
|
140
|
+
error = ValidationError.new(message)
|
141
|
+
error.set_backtrace(["#{filename}:#{lineno + match.pre_match.count("\n") + 1}"] + caller)
|
142
|
+
raise error
|
143
|
+
end
|
139
144
|
end
|
140
145
|
end
|
141
146
|
|
@@ -76,7 +76,7 @@ module GraphQL
|
|
76
76
|
|
77
77
|
def type
|
78
78
|
# TODO: Fix type indirection
|
79
|
-
@type ||= GraphQL::Client::QueryResult.wrap(self, definition_node, name: "#{name}.type")
|
79
|
+
@type ||= GraphQL::Client::QueryResult.wrap(self, definition_node, document_types[definition_node], name: "#{name}.type")
|
80
80
|
end
|
81
81
|
end
|
82
82
|
end
|
@@ -31,6 +31,9 @@ module GraphQL
|
|
31
31
|
visitor[GraphQL::Language::Nodes::FragmentDefinition] << ->(node, _parent) do
|
32
32
|
fields[node] = type_stack.object_types.last
|
33
33
|
end
|
34
|
+
visitor[GraphQL::Language::Nodes::InlineFragment] << ->(node, _parent) do
|
35
|
+
fields[node] = type_stack.object_types.last
|
36
|
+
end
|
34
37
|
visitor[GraphQL::Language::Nodes::Field] << ->(node, _parent) do
|
35
38
|
fields[node] = type_stack.field_definitions.last.type
|
36
39
|
end
|
@@ -22,41 +22,114 @@ module GraphQL
|
|
22
22
|
# Internal: Get QueryResult class for result of query.
|
23
23
|
#
|
24
24
|
# Returns subclass of QueryResult or nil.
|
25
|
-
def self.wrap(source_definition, node, name: nil)
|
26
|
-
|
25
|
+
def self.wrap(source_definition, node, type, name: nil)
|
26
|
+
case type
|
27
|
+
when GraphQL::NonNullType
|
28
|
+
NonNullWrapper.new(wrap(source_definition, node, type.of_type, name: name))
|
29
|
+
when GraphQL::ListType
|
30
|
+
ListWrapper.new(wrap(source_definition, node, type.of_type, name: name))
|
31
|
+
when GraphQL::ScalarType
|
32
|
+
ScalarWrapper.new(type)
|
33
|
+
when GraphQL::ObjectType, GraphQL::InterfaceType, GraphQL::UnionType
|
34
|
+
fields = {}
|
35
|
+
|
36
|
+
node.selections.each do |selection|
|
37
|
+
case selection
|
38
|
+
when Language::Nodes::FragmentSpread
|
39
|
+
nil
|
40
|
+
when Language::Nodes::Field
|
41
|
+
field_name = selection.alias || selection.name
|
42
|
+
selection_type = source_definition.document_types[selection]
|
43
|
+
selection_type = GraphQL::STRING_TYPE if field_name == "__typename"
|
44
|
+
field_klass = wrap(source_definition, selection, selection_type, name: "#{name}[:#{field_name}]")
|
45
|
+
fields[field_name] ? fields[field_name] |= field_klass : fields[field_name] = field_klass
|
46
|
+
when Language::Nodes::InlineFragment
|
47
|
+
selection_type = source_definition.document_types[selection]
|
48
|
+
wrap(source_definition, selection, selection_type, name: name).fields.each do |fragment_name, klass|
|
49
|
+
fields[fragment_name.to_s] ? fields[fragment_name.to_s] |= klass : fields[fragment_name.to_s] = klass
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
27
53
|
|
28
|
-
|
29
|
-
|
30
|
-
|
54
|
+
define(name: name, type: type, source_definition: source_definition, source_node: node, fields: fields)
|
55
|
+
else
|
56
|
+
raise TypeError, "unexpected #{type.class}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class ListWrapper
|
61
|
+
def initialize(type)
|
62
|
+
@of_klass = type
|
63
|
+
end
|
64
|
+
|
65
|
+
def cast(value, errors)
|
66
|
+
case value
|
67
|
+
when Array
|
68
|
+
List.new(value.each_with_index.map { |e, idx|
|
69
|
+
@of_klass.cast(e, errors.filter_by_path(idx))
|
70
|
+
}, errors)
|
71
|
+
else
|
72
|
+
raise ArgumentError, "expected list value to be an Array, but was #{value.class}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def |(other)
|
77
|
+
if self.class == other.class
|
78
|
+
self.of_klass | other.of_klass
|
79
|
+
else
|
80
|
+
raise TypeError, "expected other to be a #{self.class}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class NonNullWrapper
|
86
|
+
attr_reader :of_klass
|
87
|
+
|
88
|
+
def initialize(type)
|
89
|
+
@of_klass = type
|
90
|
+
end
|
91
|
+
|
92
|
+
def cast(value, errors)
|
93
|
+
case value
|
94
|
+
when NilClass
|
95
|
+
# TODO
|
96
|
+
# raise ArgumentError, "expected non-nullable value to be present"
|
31
97
|
nil
|
32
|
-
|
33
|
-
|
34
|
-
field_klass = nil
|
35
|
-
if selection.selections.any?
|
36
|
-
field_klass = wrap(source_definition, selection, name: "#{name}[:#{field_name}]")
|
37
|
-
end
|
38
|
-
fields[field_name] ? fields[field_name] |= field_klass : fields[field_name] = field_klass
|
39
|
-
when Language::Nodes::InlineFragment
|
40
|
-
wrap(source_definition, selection, name: name).fields.each do |fragment_name, klass|
|
41
|
-
fields[fragment_name.to_s] ? fields[fragment_name.to_s] |= klass : fields[fragment_name.to_s] = klass
|
42
|
-
end
|
98
|
+
else
|
99
|
+
@of_klass.cast(value, errors)
|
43
100
|
end
|
44
101
|
end
|
45
102
|
|
46
|
-
|
103
|
+
def |(other)
|
104
|
+
if self.class == other.class
|
105
|
+
self.of_klass | other.of_klass
|
106
|
+
else
|
107
|
+
raise TypeError, "expected other to be a #{self.class}"
|
108
|
+
end
|
109
|
+
end
|
47
110
|
end
|
48
111
|
|
49
112
|
# :nodoc:
|
50
|
-
class
|
113
|
+
class ScalarWrapper
|
51
114
|
def initialize(type)
|
52
115
|
@type = type
|
53
116
|
end
|
54
117
|
|
55
118
|
def cast(value, _errors = nil)
|
56
119
|
if value.is_a? Array
|
57
|
-
value.map { |item|
|
120
|
+
value.map { |item|
|
121
|
+
if @type.respond_to?(:coerce_isolated_input)
|
122
|
+
@type.coerce_isolated_input(item)
|
123
|
+
else
|
124
|
+
@type.coerce_input(item)
|
125
|
+
end
|
126
|
+
}
|
58
127
|
else
|
59
|
-
@type.
|
128
|
+
if @type.respond_to?(:coerce_isolated_input)
|
129
|
+
@type.coerce_isolated_input(value)
|
130
|
+
else
|
131
|
+
@type.coerce_input(value)
|
132
|
+
end
|
60
133
|
end
|
61
134
|
end
|
62
135
|
|
@@ -67,10 +140,7 @@ module GraphQL
|
|
67
140
|
end
|
68
141
|
|
69
142
|
# Internal
|
70
|
-
def self.define(name:, source_definition:, source_node:, fields: {})
|
71
|
-
type = source_definition.document_types[source_node]
|
72
|
-
type = type.unwrap if type
|
73
|
-
|
143
|
+
def self.define(name:, type:, source_definition:, source_node:, fields: {})
|
74
144
|
Class.new(self) do
|
75
145
|
@name = name
|
76
146
|
@type = type
|
@@ -81,13 +151,6 @@ module GraphQL
|
|
81
151
|
field_readers = Set.new
|
82
152
|
|
83
153
|
fields.each do |field, klass|
|
84
|
-
if @type.is_a?(GraphQL::ObjectType)
|
85
|
-
field_node = @type.get_field(field.to_s)
|
86
|
-
if field_node && field_node.type.unwrap.is_a?(GraphQL::ScalarType)
|
87
|
-
klass = Scalar.new(field_node.type.unwrap)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
154
|
@fields[field.to_sym] = klass
|
92
155
|
|
93
156
|
send :attr_reader, field
|
@@ -107,18 +170,12 @@ module GraphQL
|
|
107
170
|
end
|
108
171
|
|
109
172
|
assigns = @fields.map do |field, klass|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
RUBY
|
114
|
-
else
|
115
|
-
<<-RUBY
|
116
|
-
@#{field} = @data["#{field}"]
|
117
|
-
RUBY
|
118
|
-
end
|
173
|
+
<<-RUBY
|
174
|
+
@#{field} = self.class.fields[:#{field}].cast(@data["#{field}"], @errors.filter_by_path("#{field}"))
|
175
|
+
RUBY
|
119
176
|
end
|
120
177
|
|
121
|
-
if @type
|
178
|
+
if @type.is_a?(GraphQL::ObjectType)
|
122
179
|
assigns.unshift "@__typename = self.class.type.name"
|
123
180
|
end
|
124
181
|
|
@@ -177,12 +234,10 @@ module GraphQL
|
|
177
234
|
raise TypeError, "#{self.source_definition.name} is not included in #{obj.class.source_definition.name}"
|
178
235
|
end
|
179
236
|
cast(obj.to_h, obj.errors)
|
180
|
-
when Array
|
181
|
-
List.new(obj.each_with_index.map { |e, idx| cast(e, errors.filter_by_path(idx)) }, errors)
|
182
237
|
when NilClass
|
183
238
|
nil
|
184
239
|
else
|
185
|
-
raise TypeError, obj.
|
240
|
+
raise TypeError, "expected #{obj.inspect} to be a Hash"
|
186
241
|
end
|
187
242
|
end
|
188
243
|
|
@@ -219,7 +274,7 @@ module GraphQL
|
|
219
274
|
end
|
220
275
|
end
|
221
276
|
# TODO: Picking first source node seems error prone
|
222
|
-
define(name: self.name, source_definition: source_definition, source_node: source_node, fields: new_fields)
|
277
|
+
define(name: self.name, type: self.type, source_definition: source_definition, source_node: source_node, fields: new_fields)
|
223
278
|
end
|
224
279
|
|
225
280
|
# Public: Return errors associated with data.
|
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.8.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-04-
|
11
|
+
date: 2017-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|