graphql-client 0.14.0 → 0.15.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/README.md +10 -1
- data/lib/graphql/client.rb +8 -21
- data/lib/graphql/client/definition.rb +51 -19
- data/lib/graphql/client/schema.rb +19 -19
- data/lib/graphql/client/schema/enum_type.rb +32 -8
- data/lib/graphql/client/schema/interface_type.rb +6 -4
- data/lib/graphql/client/schema/object_type.rb +125 -22
- data/lib/graphql/client/schema/scalar_type.rb +1 -1
- data/lib/graphql/client/schema/union_type.rb +6 -4
- metadata +5 -19
- data/lib/graphql/language/nodes/deep_freeze_ext.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f7ced5b5ef5fb8e496d8c221867165c4629670a5f8ecf1e44f8c523e5774ae2
|
4
|
+
data.tar.gz: 49453ec41a714dca5774c32b24139527beb7623a8c99a2368e789f9b1443c79a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b69902cbed392a6ad77d5e124db8196439b17750ecb369fc3189a93593857f5e1cf80ade820edb5abc0e11cade056832c733726e2e4202207496d7435eb6ebfa
|
7
|
+
data.tar.gz: a918d43558b2f75ce3627a7dd003ba76e083b9c087f15c36e4df7e571d5eef71a4760fe929a7d6d93eb78a22b4f310c8ef75f9737a719a516c659eb70117026e
|
data/README.md
CHANGED
@@ -1,9 +1,18 @@
|
|
1
|
-
# graphql-client
|
1
|
+
# graphql-client [](https://badge.fury.io/rb/graphql-client) [](https://travis-ci.org/github/graphql-client)
|
2
2
|
|
3
3
|
GraphQL Client is a Ruby library for declaring, composing and executing GraphQL queries.
|
4
4
|
|
5
5
|
## Usage
|
6
6
|
|
7
|
+
### Installation
|
8
|
+
|
9
|
+
Add `graphql-client` to your Gemfile and then run `bundle install`.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
# Gemfile
|
13
|
+
gem 'graphql-client'
|
14
|
+
```
|
15
|
+
|
7
16
|
### Configuration
|
8
17
|
|
9
18
|
Sample configuration for a GraphQL Client to query from the [SWAPI GraphQL Wrapper](https://github.com/graphql/swapi-graphql).
|
data/lib/graphql/client.rb
CHANGED
@@ -12,8 +12,8 @@ require "graphql/client/operation_definition"
|
|
12
12
|
require "graphql/client/query_typename"
|
13
13
|
require "graphql/client/response"
|
14
14
|
require "graphql/client/schema"
|
15
|
-
require "graphql/language/nodes/deep_freeze_ext"
|
16
15
|
require "json"
|
16
|
+
require "delegate"
|
17
17
|
|
18
18
|
module GraphQL
|
19
19
|
# GraphQL Client helps build and execute queries against a GraphQL backend.
|
@@ -67,9 +67,9 @@ module GraphQL
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
IntrospectionDocument = GraphQL.parse(GraphQL::Introspection::INTROSPECTION_QUERY)
|
70
|
+
IntrospectionDocument = GraphQL.parse(GraphQL::Introspection::INTROSPECTION_QUERY)
|
71
71
|
|
72
|
-
def self.dump_schema(schema, io = nil)
|
72
|
+
def self.dump_schema(schema, io = nil, context: {})
|
73
73
|
unless schema.respond_to?(:execute)
|
74
74
|
raise TypeError, "expected schema to respond to #execute(), but was #{schema.class}"
|
75
75
|
end
|
@@ -78,7 +78,7 @@ module GraphQL
|
|
78
78
|
document: IntrospectionDocument,
|
79
79
|
operation_name: "IntrospectionQuery",
|
80
80
|
variables: {},
|
81
|
-
context:
|
81
|
+
context: context
|
82
82
|
).to_h
|
83
83
|
|
84
84
|
if io
|
@@ -202,19 +202,10 @@ module GraphQL
|
|
202
202
|
|
203
203
|
definitions = {}
|
204
204
|
doc.definitions.each do |node|
|
205
|
-
irep_node = case node
|
206
|
-
when GraphQL::Language::Nodes::OperationDefinition
|
207
|
-
errors[:irep].operation_definitions[node.name]
|
208
|
-
when GraphQL::Language::Nodes::FragmentDefinition
|
209
|
-
errors[:irep].fragment_definitions[node.name]
|
210
|
-
else
|
211
|
-
raise TypeError, "unexpected #{node.class}"
|
212
|
-
end
|
213
|
-
|
214
205
|
sliced_document = Language::DefinitionSlice.slice(document_dependencies, node.name)
|
215
206
|
definition = Definition.for(
|
216
207
|
client: self,
|
217
|
-
|
208
|
+
ast_node: node,
|
218
209
|
document: sliced_document,
|
219
210
|
source_document: doc,
|
220
211
|
source_location: source_location
|
@@ -229,10 +220,6 @@ module GraphQL
|
|
229
220
|
visitor[Language::Nodes::FragmentSpread].leave << name_hook.method(:rename_node)
|
230
221
|
visitor.visit
|
231
222
|
|
232
|
-
if !doc.respond_to?(:merge)
|
233
|
-
doc.deep_freeze # 1.9 introduced immutable AST nodes, so we skip this on 1.9+
|
234
|
-
end
|
235
|
-
|
236
223
|
if document_tracking_enabled
|
237
224
|
if @document.respond_to?(:merge) # GraphQL 1.9+
|
238
225
|
@document = @document.merge(definitions: @document.definitions + doc.definitions)
|
@@ -261,7 +248,7 @@ module GraphQL
|
|
261
248
|
definition = @definitions[node.name]
|
262
249
|
if definition
|
263
250
|
node.extend(LazyName)
|
264
|
-
node.
|
251
|
+
node._definition = definition
|
265
252
|
end
|
266
253
|
end
|
267
254
|
end
|
@@ -384,10 +371,10 @@ module GraphQL
|
|
384
371
|
# name to point to a lazily defined Proc instead of a static string.
|
385
372
|
module LazyName
|
386
373
|
def name
|
387
|
-
@
|
374
|
+
@_definition.definition_name
|
388
375
|
end
|
389
376
|
|
390
|
-
attr_writer :
|
377
|
+
attr_writer :_definition
|
391
378
|
end
|
392
379
|
|
393
380
|
private
|
@@ -14,24 +14,46 @@ module GraphQL
|
|
14
14
|
#
|
15
15
|
# Definitions MUST be assigned to a constant.
|
16
16
|
class Definition < Module
|
17
|
-
def self.for(
|
18
|
-
case
|
17
|
+
def self.for(ast_node:, **kargs)
|
18
|
+
case ast_node
|
19
19
|
when Language::Nodes::OperationDefinition
|
20
|
-
OperationDefinition.new(
|
20
|
+
OperationDefinition.new(ast_node: ast_node, **kargs)
|
21
21
|
when Language::Nodes::FragmentDefinition
|
22
|
-
FragmentDefinition.new(
|
22
|
+
FragmentDefinition.new(ast_node: ast_node, **kargs)
|
23
23
|
else
|
24
|
-
raise TypeError, "expected node to be a definition type, but was #{
|
24
|
+
raise TypeError, "expected node to be a definition type, but was #{ast_node.class}"
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
def initialize(client:, document:, source_document:,
|
28
|
+
def initialize(client:, document:, source_document:, ast_node:, source_location:)
|
29
29
|
@client = client
|
30
30
|
@document = document
|
31
31
|
@source_document = source_document
|
32
|
-
@definition_node =
|
32
|
+
@definition_node = ast_node
|
33
33
|
@source_location = source_location
|
34
|
-
|
34
|
+
|
35
|
+
definition_type = case ast_node
|
36
|
+
when GraphQL::Language::Nodes::OperationDefinition
|
37
|
+
case ast_node.operation_type
|
38
|
+
when "mutation"
|
39
|
+
@client.schema.mutation
|
40
|
+
when "subscription"
|
41
|
+
@client.schema.subscription
|
42
|
+
when "query", nil
|
43
|
+
@client.schema.query
|
44
|
+
else
|
45
|
+
raise "Unexpected operation_type: #{ast_node.operation_type}"
|
46
|
+
end
|
47
|
+
when GraphQL::Language::Nodes::FragmentDefinition
|
48
|
+
@client.schema.types[ast_node.type.name]
|
49
|
+
else
|
50
|
+
raise "Unexpected ast_node: #{ast_node}"
|
51
|
+
end
|
52
|
+
|
53
|
+
@schema_class = client.types.define_class(self, [ast_node], definition_type)
|
54
|
+
|
55
|
+
# Clear cache only needed during initialization
|
56
|
+
@indexes = nil
|
35
57
|
end
|
36
58
|
|
37
59
|
# Internal: Get associated owner GraphQL::Client instance.
|
@@ -89,9 +111,9 @@ module GraphQL
|
|
89
111
|
when GraphQL::Client::Schema::PossibleTypes
|
90
112
|
case obj
|
91
113
|
when NilClass
|
92
|
-
|
114
|
+
obj
|
93
115
|
else
|
94
|
-
|
116
|
+
cast_object(obj)
|
95
117
|
end
|
96
118
|
when GraphQL::Client::Schema::ObjectType
|
97
119
|
case obj
|
@@ -100,14 +122,7 @@ module GraphQL
|
|
100
122
|
when Hash
|
101
123
|
schema_class.new(obj, errors)
|
102
124
|
else
|
103
|
-
|
104
|
-
unless obj.class._spreads.include?(definition_node.name)
|
105
|
-
raise TypeError, "#{definition_node.name} is not included in #{obj.class.source_definition.name}"
|
106
|
-
end
|
107
|
-
schema_class.cast(obj.to_h, obj.errors)
|
108
|
-
else
|
109
|
-
raise TypeError, "unexpected #{obj.class}"
|
110
|
-
end
|
125
|
+
cast_object(obj)
|
111
126
|
end
|
112
127
|
else
|
113
128
|
raise TypeError, "unexpected #{schema_class}"
|
@@ -126,9 +141,26 @@ module GraphQL
|
|
126
141
|
end
|
127
142
|
|
128
143
|
private
|
144
|
+
|
145
|
+
def cast_object(obj)
|
146
|
+
if obj.class.is_a?(GraphQL::Client::Schema::ObjectType)
|
147
|
+
unless obj.class._spreads.include?(definition_node.name)
|
148
|
+
raise TypeError, "#{definition_node.name} is not included in #{obj.class.source_definition.name}"
|
149
|
+
end
|
150
|
+
schema_class.cast(obj.to_h, obj.errors)
|
151
|
+
else
|
152
|
+
raise TypeError, "unexpected #{obj.class}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
EMPTY_SET = Set.new.freeze
|
157
|
+
|
129
158
|
def index_spreads(visitor)
|
130
159
|
spreads = {}
|
131
|
-
on_node = ->(node, _parent)
|
160
|
+
on_node = ->(node, _parent) do
|
161
|
+
node_spreads = flatten_spreads(node).map(&:name)
|
162
|
+
spreads[node] = node_spreads.empty? ? EMPTY_SET : Set.new(node_spreads).freeze
|
163
|
+
end
|
132
164
|
|
133
165
|
visitor[GraphQL::Language::Nodes::Field] << on_node
|
134
166
|
visitor[GraphQL::Language::Nodes::FragmentDefinition] << on_node
|
@@ -15,23 +15,25 @@ module GraphQL
|
|
15
15
|
class Client
|
16
16
|
module Schema
|
17
17
|
module ClassMethods
|
18
|
-
def define_class(definition,
|
19
|
-
|
18
|
+
def define_class(definition, ast_nodes, type)
|
19
|
+
type_class = case type
|
20
20
|
when GraphQL::NonNullType
|
21
|
-
define_class(definition,
|
21
|
+
define_class(definition, ast_nodes, type.of_type).to_non_null_type
|
22
22
|
when GraphQL::ListType
|
23
|
-
define_class(definition,
|
23
|
+
define_class(definition, ast_nodes, type.of_type).to_list_type
|
24
24
|
else
|
25
|
-
get_class(type.name).define_class(definition,
|
25
|
+
get_class(type.name).define_class(definition, ast_nodes)
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
directive.
|
31
|
-
|
32
|
-
|
28
|
+
ast_nodes.each do |ast_node|
|
29
|
+
ast_node.directives.each do |directive|
|
30
|
+
if directive = self.directives[directive.name.to_sym]
|
31
|
+
type_class = directive.new(type_class)
|
32
|
+
end
|
33
33
|
end
|
34
34
|
end
|
35
|
+
|
36
|
+
type_class
|
35
37
|
end
|
36
38
|
|
37
39
|
def get_class(type_name)
|
@@ -50,6 +52,13 @@ module GraphQL
|
|
50
52
|
const_set(class_name, klass)
|
51
53
|
end
|
52
54
|
|
55
|
+
DIRECTIVES = { include: IncludeDirective,
|
56
|
+
skip: SkipDirective }.freeze
|
57
|
+
|
58
|
+
def directives
|
59
|
+
DIRECTIVES
|
60
|
+
end
|
61
|
+
|
53
62
|
private
|
54
63
|
|
55
64
|
def normalize_type_name(type_name)
|
@@ -61,10 +70,6 @@ module GraphQL
|
|
61
70
|
mod = Module.new
|
62
71
|
mod.extend ClassMethods
|
63
72
|
|
64
|
-
mod.define_singleton_method :schema do
|
65
|
-
schema
|
66
|
-
end
|
67
|
-
|
68
73
|
cache = {}
|
69
74
|
schema.types.each do |name, type|
|
70
75
|
next if name.start_with?("__")
|
@@ -74,11 +79,6 @@ module GraphQL
|
|
74
79
|
end
|
75
80
|
end
|
76
81
|
|
77
|
-
directives = {}
|
78
|
-
mod.define_singleton_method(:directives) { directives }
|
79
|
-
directives[:include] = IncludeDirective
|
80
|
-
directives[:skip] = SkipDirective
|
81
|
-
|
82
82
|
mod
|
83
83
|
end
|
84
84
|
|
@@ -9,6 +9,34 @@ module GraphQL
|
|
9
9
|
class EnumType < Module
|
10
10
|
include BaseType
|
11
11
|
|
12
|
+
class EnumValue < String
|
13
|
+
def initialize(obj, enum_value, enum)
|
14
|
+
super(obj)
|
15
|
+
@enum_value = enum_value
|
16
|
+
@enum = enum
|
17
|
+
end
|
18
|
+
|
19
|
+
def respond_to_missing?(method_name, include_private = false)
|
20
|
+
if method_name[-1] == "?" && @enum.include?(method_name[0..-2])
|
21
|
+
true
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def method_missing(method_name, *args)
|
28
|
+
if method_name[-1] == "?"
|
29
|
+
queried_value = method_name[0..-2]
|
30
|
+
if @enum.include?(queried_value)
|
31
|
+
raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0)" unless args.empty?
|
32
|
+
return @enum_value == queried_value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
super
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
12
40
|
# Internal: Construct enum wrapper from another GraphQL::EnumType.
|
13
41
|
#
|
14
42
|
# type - GraphQL::EnumType instance
|
@@ -21,22 +49,18 @@ module GraphQL
|
|
21
49
|
@values = {}
|
22
50
|
|
23
51
|
all_values = type.values.keys
|
52
|
+
comparison_set = all_values.map { |s| -s.downcase }.to_set
|
24
53
|
|
25
54
|
all_values.each do |value|
|
26
|
-
str = value.
|
27
|
-
all_values.each do |v|
|
28
|
-
str.define_singleton_method("#{v.downcase}?") { false }
|
29
|
-
end
|
30
|
-
str.define_singleton_method("#{value.downcase}?") { true }
|
31
|
-
str.freeze
|
55
|
+
str = EnumValue.new(-value, -value.downcase, comparison_set).freeze
|
32
56
|
const_set(value, str) if value =~ /^[A-Z]/
|
33
|
-
@values[str] = str
|
57
|
+
@values[str.to_s] = str
|
34
58
|
end
|
35
59
|
|
36
60
|
@values.freeze
|
37
61
|
end
|
38
62
|
|
39
|
-
def define_class(definition,
|
63
|
+
def define_class(definition, ast_nodes)
|
40
64
|
self
|
41
65
|
end
|
42
66
|
|
@@ -20,10 +20,12 @@ module GraphQL
|
|
20
20
|
PossibleTypes.new(type, types)
|
21
21
|
end
|
22
22
|
|
23
|
-
def define_class(definition,
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
def define_class(definition, ast_nodes)
|
24
|
+
possible_type_names = definition.client.schema.possible_types(type).map(&:graphql_name)
|
25
|
+
possible_types = possible_type_names.map { |concrete_type_name|
|
26
|
+
schema_module.get_class(concrete_type_name).define_class(definition, ast_nodes)
|
27
|
+
}
|
28
|
+
new(possible_types)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
2
|
require "active_support/inflector"
|
4
3
|
require "graphql/client/error"
|
5
4
|
require "graphql/client/errors"
|
@@ -20,37 +19,83 @@ module GraphQL
|
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
23
|
-
def define_class(definition,
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
22
|
+
def define_class(definition, ast_nodes)
|
23
|
+
# First, gather all the ast nodes representing a certain selection, by name.
|
24
|
+
# We gather AST nodes into arrays so that multiple selections can be grouped, for example:
|
25
|
+
#
|
26
|
+
# {
|
27
|
+
# f1 { a b }
|
28
|
+
# f1 { b c }
|
29
|
+
# }
|
30
|
+
#
|
31
|
+
# should be treated like `f1 { a b c }`
|
32
|
+
field_nodes = {}
|
33
|
+
ast_nodes.each do |ast_node|
|
34
|
+
ast_node.selections.each do |selected_ast_node|
|
35
|
+
gather_selections(field_nodes, definition, selected_ast_node)
|
30
36
|
end
|
31
|
-
|
32
|
-
}
|
37
|
+
end
|
33
38
|
|
34
|
-
|
35
|
-
|
39
|
+
# After gathering all the nodes by name, prepare to create methods and classes for them.
|
40
|
+
field_classes = {}
|
41
|
+
field_nodes.each do |result_name, field_ast_nodes|
|
42
|
+
# `result_name` might be an alias, so make sure to get the proper name
|
43
|
+
field_name = field_ast_nodes.first.name
|
44
|
+
field_definition = definition.client.schema.get_field(type.name, field_name)
|
45
|
+
field_return_type = field_definition.type
|
46
|
+
field_classes[result_name.to_sym] = schema_module.define_class(definition, field_ast_nodes, field_return_type)
|
47
|
+
end
|
36
48
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
49
|
+
klass = Class.new(self)
|
50
|
+
klass.define_fields(field_classes)
|
51
|
+
klass.instance_variable_set(:@source_definition, definition)
|
52
|
+
klass.instance_variable_set(:@_spreads, definition.indexes[:spreads][ast_nodes.first])
|
53
|
+
|
54
|
+
if definition.client.enforce_collocated_callers
|
55
|
+
keys = field_classes.keys.map { |key| ActiveSupport::Inflector.underscore(key) }
|
56
|
+
Client.enforce_collocated_callers(klass, keys, definition.source_location[0])
|
57
|
+
end
|
58
|
+
|
59
|
+
klass
|
60
|
+
end
|
61
|
+
|
62
|
+
PREDICATE_CACHE = Hash.new { |h, name|
|
63
|
+
h[name] = -> { @data[name] ? true : false }
|
64
|
+
}
|
41
65
|
|
42
|
-
|
43
|
-
|
44
|
-
|
66
|
+
METHOD_CACHE = Hash.new { |h, key|
|
67
|
+
h[key] = -> {
|
68
|
+
name = key.to_s
|
69
|
+
type = self.class::FIELDS[key]
|
70
|
+
@casted_data.fetch(name) do
|
71
|
+
@casted_data[name] = type.cast(@data[name], @errors.filter_by_path(name))
|
45
72
|
end
|
73
|
+
}
|
74
|
+
}
|
46
75
|
|
47
|
-
|
48
|
-
|
76
|
+
MODULE_CACHE = Hash.new do |h, fields|
|
77
|
+
h[fields] = Module.new do
|
78
|
+
fields.each do |name|
|
79
|
+
GraphQL::Client::Schema::ObjectType.define_cached_field(name, self)
|
80
|
+
end
|
49
81
|
end
|
50
82
|
end
|
51
83
|
|
84
|
+
FIELDS_CACHE = Hash.new { |h, k| h[k] = k }
|
85
|
+
|
52
86
|
def define_fields(fields)
|
53
|
-
|
87
|
+
const_set :FIELDS, FIELDS_CACHE[fields]
|
88
|
+
mod = MODULE_CACHE[fields.keys.sort]
|
89
|
+
include mod
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.define_cached_field(name, ctx)
|
93
|
+
key = name
|
94
|
+
name = -name.to_s
|
95
|
+
method_name = ActiveSupport::Inflector.underscore(name)
|
96
|
+
|
97
|
+
ctx.send(:define_method, method_name, &METHOD_CACHE[key])
|
98
|
+
ctx.send(:define_method, "#{method_name}?", &PREDICATE_CACHE[name])
|
54
99
|
end
|
55
100
|
|
56
101
|
def define_field(name, type)
|
@@ -78,9 +123,67 @@ module GraphQL
|
|
78
123
|
raise InvariantError, "expected value to be a Hash, but was #{value.class}"
|
79
124
|
end
|
80
125
|
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
# Given an AST selection on this object, gather it into `fields` if it applies.
|
130
|
+
# If it's a fragment, continue recursively checking the selections on the fragment.
|
131
|
+
def gather_selections(fields, definition, selected_ast_node)
|
132
|
+
case selected_ast_node
|
133
|
+
when GraphQL::Language::Nodes::InlineFragment
|
134
|
+
continue_selection = if selected_ast_node.type.nil?
|
135
|
+
true
|
136
|
+
else
|
137
|
+
schema = definition.client.schema
|
138
|
+
type_condition = schema.types[selected_ast_node.type.name]
|
139
|
+
applicable_types = schema.possible_types(type_condition)
|
140
|
+
# continue if this object type is one of the types matching the fragment condition
|
141
|
+
applicable_types.include?(type)
|
142
|
+
end
|
143
|
+
|
144
|
+
if continue_selection
|
145
|
+
selected_ast_node.selections.each do |next_selected_ast_node|
|
146
|
+
gather_selections(fields, definition, next_selected_ast_node)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
when GraphQL::Language::Nodes::FragmentSpread
|
150
|
+
fragment_definition = definition.document.definitions.find do |defn|
|
151
|
+
defn.is_a?(GraphQL::Language::Nodes::FragmentDefinition) && defn.name == selected_ast_node.name
|
152
|
+
end
|
153
|
+
|
154
|
+
schema = definition.client.schema
|
155
|
+
type_condition = schema.types[fragment_definition.type.name]
|
156
|
+
applicable_types = schema.possible_types(type_condition)
|
157
|
+
# continue if this object type is one of the types matching the fragment condition
|
158
|
+
continue_selection = applicable_types.include?(type)
|
159
|
+
|
160
|
+
if continue_selection
|
161
|
+
fragment_definition.selections.each do |next_selected_ast_node|
|
162
|
+
gather_selections(fields, definition, next_selected_ast_node)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
when GraphQL::Language::Nodes::Field
|
166
|
+
operation_definition_for_field = definition.indexes[:definitions][selected_ast_node]
|
167
|
+
# Ignore fields defined in other documents.
|
168
|
+
if definition.source_document.definitions.include?(operation_definition_for_field)
|
169
|
+
field_method_name = selected_ast_node.alias || selected_ast_node.name
|
170
|
+
ast_nodes = fields[field_method_name] ||= []
|
171
|
+
ast_nodes << selected_ast_node
|
172
|
+
end
|
173
|
+
else
|
174
|
+
raise "Unexpected selection node: #{selected_ast_node}"
|
175
|
+
end
|
176
|
+
end
|
81
177
|
end
|
82
178
|
|
83
179
|
class ObjectClass
|
180
|
+
module ClassMethods
|
181
|
+
attr_reader :source_definition
|
182
|
+
attr_reader :_spreads
|
183
|
+
end
|
184
|
+
|
185
|
+
extend ClassMethods
|
186
|
+
|
84
187
|
def initialize(data = {}, errors = Errors.new)
|
85
188
|
@data = data
|
86
189
|
@casted_data = {}
|
@@ -20,10 +20,12 @@ module GraphQL
|
|
20
20
|
PossibleTypes.new(type, types)
|
21
21
|
end
|
22
22
|
|
23
|
-
def define_class(definition,
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
def define_class(definition, ast_nodes)
|
24
|
+
possible_type_names = definition.client.schema.possible_types(type).map(&:graphql_name)
|
25
|
+
possible_types = possible_type_names.map { |concrete_type_name|
|
26
|
+
schema_module.get_class(concrete_type_name).define_class(definition, ast_nodes)
|
27
|
+
}
|
28
|
+
new(possible_types)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
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.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -17,9 +17,6 @@ dependencies:
|
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '3.0'
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '6.0'
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -27,23 +24,20 @@ dependencies:
|
|
27
24
|
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '3.0'
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '6.0'
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: graphql
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
36
30
|
requirements:
|
37
31
|
- - "~>"
|
38
32
|
- !ruby/object:Gem::Version
|
39
|
-
version: '1.
|
33
|
+
version: '1.8'
|
40
34
|
type: :runtime
|
41
35
|
prerelease: false
|
42
36
|
version_requirements: !ruby/object:Gem::Requirement
|
43
37
|
requirements:
|
44
38
|
- - "~>"
|
45
39
|
- !ruby/object:Gem::Version
|
46
|
-
version: '1.
|
40
|
+
version: '1.8'
|
47
41
|
- !ruby/object:Gem::Dependency
|
48
42
|
name: actionpack
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -51,9 +45,6 @@ dependencies:
|
|
51
45
|
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: 3.2.22
|
54
|
-
- - "<"
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
version: '6.0'
|
57
48
|
type: :development
|
58
49
|
prerelease: false
|
59
50
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -61,9 +52,6 @@ dependencies:
|
|
61
52
|
- - ">="
|
62
53
|
- !ruby/object:Gem::Version
|
63
54
|
version: 3.2.22
|
64
|
-
- - "<"
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version: '6.0'
|
67
55
|
- !ruby/object:Gem::Dependency
|
68
56
|
name: erubi
|
69
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -189,7 +177,6 @@ files:
|
|
189
177
|
- lib/graphql/client/schema/skip_directive.rb
|
190
178
|
- lib/graphql/client/schema/union_type.rb
|
191
179
|
- lib/graphql/client/view_module.rb
|
192
|
-
- lib/graphql/language/nodes/deep_freeze_ext.rb
|
193
180
|
- lib/rubocop/cop/graphql/heredoc.rb
|
194
181
|
- lib/rubocop/cop/graphql/overfetch.rb
|
195
182
|
homepage: https://github.com/github/graphql-client
|
@@ -211,8 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
211
198
|
- !ruby/object:Gem::Version
|
212
199
|
version: '0'
|
213
200
|
requirements: []
|
214
|
-
|
215
|
-
rubygems_version: 2.7.6
|
201
|
+
rubygems_version: 3.0.3
|
216
202
|
signing_key:
|
217
203
|
specification_version: 4
|
218
204
|
summary: GraphQL Client
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require "graphql"
|
3
|
-
|
4
|
-
module GraphQL
|
5
|
-
module Language
|
6
|
-
module Nodes
|
7
|
-
# :nodoc:
|
8
|
-
class AbstractNode
|
9
|
-
# Public: Freeze entire Node tree
|
10
|
-
#
|
11
|
-
# Returns self Node.
|
12
|
-
def deep_freeze
|
13
|
-
scalars # load internal state
|
14
|
-
children.each(&:deep_freeze)
|
15
|
-
scalars.each { |s| s && s.freeze }
|
16
|
-
freeze
|
17
|
-
self
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|