graphql 2.0.14 → 2.0.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/backtrace/table.rb +2 -2
- data/lib/graphql/dataloader.rb +4 -1
- data/lib/graphql/execution/interpreter/runtime.rb +23 -10
- data/lib/graphql/execution/interpreter.rb +4 -4
- data/lib/graphql/execution/lookahead.rb +15 -4
- data/lib/graphql/introspection.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +18 -18
- data/lib/graphql/language/printer.rb +20 -11
- data/lib/graphql/query/context.rb +41 -15
- data/lib/graphql/rake_task.rb +28 -1
- data/lib/graphql/schema/build_from_definition.rb +31 -15
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/field.rb +3 -3
- data/lib/graphql/schema/member/build_type.rb +1 -1
- data/lib/graphql/schema/member/has_directives.rb +71 -56
- data/lib/graphql/schema/resolver/has_payload_type.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +10 -1
- data/lib/graphql/schema.rb +31 -8
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
- data/lib/graphql/subscriptions.rb +5 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +4 -0
- data/lib/graphql/types/relay/default_relay.rb +7 -1
- data/lib/graphql/types/relay/edge_behaviors.rb +1 -0
- data/lib/graphql/types/relay/node_behaviors.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d626d72a5ae0bfb10f8fcdb9cbd781f04b5bb38b3f90b20de062a78679c254a8
|
4
|
+
data.tar.gz: 6793ba627f3f59a43426258e187567f391a44f8973816fb0b1e1eb7784ae19b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5958721b08e45d886036f8afe0a5942e443117d9aa71d94450b727ec20d13b63a945a97c247f8605d4eb1ae8631ba301599e95b938355f18dc7c5bf64e2b1b44
|
7
|
+
data.tar.gz: 9d029e7d0288c87cc9c09e627538b5e93b3d1ec7e785914b135088ec7bafcf8172458fa1d68a95a6385786d472c7260f6bc82b719e86743b5dac1f2a87501f7c
|
@@ -83,7 +83,7 @@ module GraphQL
|
|
83
83
|
value = if top && @override_value
|
84
84
|
@override_value
|
85
85
|
else
|
86
|
-
value_at(@context.query.context.namespace(:
|
86
|
+
value_at(@context.query.context.namespace(:interpreter_runtime)[:runtime], context_entry.path)
|
87
87
|
end
|
88
88
|
rows << [
|
89
89
|
"#{context_entry.ast_node ? context_entry.ast_node.position.join(":") : ""}",
|
@@ -112,7 +112,7 @@ module GraphQL
|
|
112
112
|
if object.is_a?(GraphQL::Schema::Object)
|
113
113
|
object = object.object
|
114
114
|
end
|
115
|
-
value = value_at(context_entry.namespace(:
|
115
|
+
value = value_at(context_entry.namespace(:interpreter_runtime)[:runtime], [])
|
116
116
|
rows << [
|
117
117
|
"#{position}",
|
118
118
|
"#{op_type}#{op_name ? " #{op_name}" : ""}",
|
data/lib/graphql/dataloader.rb
CHANGED
@@ -289,7 +289,10 @@ module GraphQL
|
|
289
289
|
fiber_locals = {}
|
290
290
|
|
291
291
|
Thread.current.keys.each do |fiber_var_key|
|
292
|
-
|
292
|
+
# This variable should be fresh in each new fiber
|
293
|
+
if fiber_var_key != :__graphql_runtime_info
|
294
|
+
fiber_locals[fiber_var_key] = Thread.current[fiber_var_key]
|
295
|
+
end
|
293
296
|
end
|
294
297
|
|
295
298
|
if @nonblocking
|
@@ -148,13 +148,23 @@ module GraphQL
|
|
148
148
|
# @return [GraphQL::Query::Context]
|
149
149
|
attr_reader :context
|
150
150
|
|
151
|
+
def thread_info
|
152
|
+
info = Thread.current[:__graphql_runtime_info]
|
153
|
+
if !info
|
154
|
+
new_ti = {}
|
155
|
+
info = Thread.current[:__graphql_runtime_info] = new_ti
|
156
|
+
end
|
157
|
+
info
|
158
|
+
end
|
159
|
+
|
151
160
|
def initialize(query:)
|
152
161
|
@query = query
|
153
162
|
@dataloader = query.multiplex.dataloader
|
154
163
|
@schema = query.schema
|
155
164
|
@context = query.context
|
156
165
|
@multiplex_context = query.multiplex.context
|
157
|
-
|
166
|
+
# Start this off empty:
|
167
|
+
Thread.current[:__graphql_runtime_info] = nil
|
158
168
|
@response = GraphQLResultHash.new(nil, nil)
|
159
169
|
# Identify runtime directives by checking which of this schema's directives have overridden `def self.resolve`
|
160
170
|
@runtime_directive_names = []
|
@@ -680,7 +690,11 @@ module GraphQL
|
|
680
690
|
|
681
691
|
case current_type.kind.name
|
682
692
|
when "SCALAR", "ENUM"
|
683
|
-
r =
|
693
|
+
r = begin
|
694
|
+
current_type.coerce_result(value, context)
|
695
|
+
rescue StandardError => err
|
696
|
+
schema.handle_or_reraise(context, err)
|
697
|
+
end
|
684
698
|
set_result(selection_result, result_name, r)
|
685
699
|
r
|
686
700
|
when "UNION", "INTERFACE"
|
@@ -870,17 +884,18 @@ module GraphQL
|
|
870
884
|
end
|
871
885
|
|
872
886
|
def set_all_interpreter_context(object, field, arguments, path)
|
887
|
+
ti = thread_info
|
873
888
|
if object
|
874
|
-
|
889
|
+
ti[:current_object] = object
|
875
890
|
end
|
876
891
|
if field
|
877
|
-
|
892
|
+
ti[:current_field] = field
|
878
893
|
end
|
879
894
|
if arguments
|
880
|
-
|
895
|
+
ti[:current_arguments] = arguments
|
881
896
|
end
|
882
897
|
if path
|
883
|
-
|
898
|
+
ti[:current_path] = path
|
884
899
|
end
|
885
900
|
end
|
886
901
|
|
@@ -940,13 +955,11 @@ module GraphQL
|
|
940
955
|
# Set this pair in the Query context, but also in the interpeter namespace,
|
941
956
|
# for compatibility.
|
942
957
|
def set_interpreter_context(key, value)
|
943
|
-
|
944
|
-
@context[key] = value
|
958
|
+
thread_info[key] = value
|
945
959
|
end
|
946
960
|
|
947
961
|
def delete_interpreter_context(key)
|
948
|
-
|
949
|
-
@context.delete(key)
|
962
|
+
(ti = thread_info) && ti.delete(key)
|
950
963
|
end
|
951
964
|
|
952
965
|
def resolve_type(type, value, path)
|
@@ -68,7 +68,7 @@ module GraphQL
|
|
68
68
|
# they also have another item of state, which is private to that query
|
69
69
|
# in particular, assign it here:
|
70
70
|
runtime = Runtime.new(query: query)
|
71
|
-
query.context.namespace(:
|
71
|
+
query.context.namespace(:interpreter_runtime)[:runtime] = runtime
|
72
72
|
|
73
73
|
query.trace("execute_query", {query: query}) do
|
74
74
|
runtime.run_eager
|
@@ -90,7 +90,7 @@ module GraphQL
|
|
90
90
|
query = multiplex.queries.length == 1 ? multiplex.queries[0] : nil
|
91
91
|
queries = multiplex ? multiplex.queries : [query]
|
92
92
|
final_values = queries.map do |query|
|
93
|
-
runtime = query.context.namespace(:
|
93
|
+
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
94
94
|
# it might not be present if the query has an error
|
95
95
|
runtime ? runtime.final_result : nil
|
96
96
|
end
|
@@ -99,7 +99,7 @@ module GraphQL
|
|
99
99
|
Interpreter::Resolve.resolve_all(final_values, multiplex.dataloader)
|
100
100
|
end
|
101
101
|
queries.each do |query|
|
102
|
-
runtime = query.context.namespace(:
|
102
|
+
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
103
103
|
if runtime
|
104
104
|
runtime.delete_interpreter_context(:current_path)
|
105
105
|
runtime.delete_interpreter_context(:current_field)
|
@@ -123,7 +123,7 @@ module GraphQL
|
|
123
123
|
end
|
124
124
|
else
|
125
125
|
result = {
|
126
|
-
"data" => query.context.namespace(:
|
126
|
+
"data" => query.context.namespace(:interpreter_runtime)[:runtime].final_result
|
127
127
|
}
|
128
128
|
|
129
129
|
if query.context.errors.any?
|
@@ -76,8 +76,8 @@ module GraphQL
|
|
76
76
|
# @param field_name [String, Symbol]
|
77
77
|
# @param arguments [Hash] Arguments which must match in the selection
|
78
78
|
# @return [Boolean]
|
79
|
-
def selects?(field_name, arguments: nil)
|
80
|
-
selection(field_name, arguments: arguments).selected?
|
79
|
+
def selects?(field_name, selected_type: @selected_type, arguments: nil)
|
80
|
+
selection(field_name, selected_type: selected_type, arguments: arguments).selected?
|
81
81
|
end
|
82
82
|
|
83
83
|
# @return [Boolean] True if this lookahead represents a field that was requested
|
@@ -95,11 +95,22 @@ module GraphQL
|
|
95
95
|
@query.get_field(selected_type, field_name)
|
96
96
|
when Symbol
|
97
97
|
# Try to avoid the `.to_s` below, if possible
|
98
|
-
all_fields =
|
98
|
+
all_fields = if selected_type.kind.fields?
|
99
|
+
@query.warden.fields(selected_type)
|
100
|
+
else
|
101
|
+
# Handle unions by checking possible
|
102
|
+
@query.warden
|
103
|
+
.possible_types(selected_type)
|
104
|
+
.map { |t| @query.warden.fields(t) }
|
105
|
+
.flatten
|
106
|
+
end
|
107
|
+
|
99
108
|
if (match_by_orig_name = all_fields.find { |f| f.original_name == field_name })
|
100
109
|
match_by_orig_name
|
101
110
|
else
|
102
|
-
|
111
|
+
# Symbol#name is only present on 3.0+
|
112
|
+
sym_s = field_name.respond_to?(:name) ? field_name.name : field_name.to_s
|
113
|
+
guessed_name = Schema::Member::BuildType.camelize(sym_s)
|
103
114
|
@query.get_field(selected_type, guessed_name)
|
104
115
|
end
|
105
116
|
end
|
@@ -4,7 +4,7 @@ module GraphQL
|
|
4
4
|
def self.query(include_deprecated_args: false, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
|
5
5
|
# The introspection query to end all introspection queries, copied from
|
6
6
|
# https://github.com/graphql/graphql-js/blob/master/src/utilities/introspectionQuery.js
|
7
|
-
<<-QUERY
|
7
|
+
<<-QUERY.gsub(/\n{2,}/, "\n")
|
8
8
|
query IntrospectionQuery {
|
9
9
|
__schema {
|
10
10
|
#{include_schema_description ? "description" : ""}
|
@@ -44,16 +44,18 @@ module GraphQL
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def build_schema_node
|
47
|
-
|
48
|
-
query: (q = warden.root_type_for_operation("query")) && q.graphql_name,
|
49
|
-
mutation: (m = warden.root_type_for_operation("mutation")) && m.graphql_name,
|
50
|
-
subscription: (s = warden.root_type_for_operation("subscription")) && s.graphql_name,
|
51
|
-
# This only supports directives from parsing,
|
52
|
-
# use a custom printer to add to this list.
|
53
|
-
#
|
47
|
+
schema_options = {
|
54
48
|
# `@schema.directives` is covered by `build_definition_nodes`
|
55
|
-
directives:
|
56
|
-
|
49
|
+
directives: definition_directives(@schema, :schema_directives),
|
50
|
+
}
|
51
|
+
if !schema_respects_root_name_conventions?(@schema)
|
52
|
+
schema_options.merge!({
|
53
|
+
query: (q = warden.root_type_for_operation("query")) && q.graphql_name,
|
54
|
+
mutation: (m = warden.root_type_for_operation("mutation")) && m.graphql_name,
|
55
|
+
subscription: (s = warden.root_type_for_operation("subscription")) && s.graphql_name,
|
56
|
+
})
|
57
|
+
end
|
58
|
+
GraphQL::Language::Nodes::SchemaDefinition.new(schema_options)
|
57
59
|
end
|
58
60
|
|
59
61
|
def build_object_type_node(object_type)
|
@@ -283,7 +285,9 @@ module GraphQL
|
|
283
285
|
private
|
284
286
|
|
285
287
|
def include_schema_node?
|
286
|
-
always_include_schema ||
|
288
|
+
always_include_schema ||
|
289
|
+
!schema_respects_root_name_conventions?(schema) ||
|
290
|
+
!schema.schema_directives.empty?
|
287
291
|
end
|
288
292
|
|
289
293
|
def schema_respects_root_name_conventions?(schema)
|
@@ -293,14 +297,14 @@ module GraphQL
|
|
293
297
|
end
|
294
298
|
|
295
299
|
def directives(member)
|
296
|
-
definition_directives(member)
|
300
|
+
definition_directives(member, :directives)
|
297
301
|
end
|
298
302
|
|
299
|
-
def definition_directives(member)
|
300
|
-
dirs = if !member.respond_to?(
|
303
|
+
def definition_directives(member, directives_method)
|
304
|
+
dirs = if !member.respond_to?(directives_method) || member.directives.empty?
|
301
305
|
[]
|
302
306
|
else
|
303
|
-
member.
|
307
|
+
member.public_send(directives_method).map do |dir|
|
304
308
|
args = []
|
305
309
|
dir.arguments.argument_values.each_value do |arg_value| # rubocop:disable Development/ContextIsPassedCop -- directive instance method
|
306
310
|
arg_defn = arg_value.definition
|
@@ -324,10 +328,6 @@ module GraphQL
|
|
324
328
|
dirs
|
325
329
|
end
|
326
330
|
|
327
|
-
def ast_directives(member)
|
328
|
-
member.ast_node ? member.ast_node.directives : []
|
329
|
-
end
|
330
|
-
|
331
331
|
attr_reader :schema, :warden, :always_include_schema,
|
332
332
|
:include_introspection_types, :include_built_in_directives, :include_built_in_scalars
|
333
333
|
end
|
@@ -132,10 +132,11 @@ module GraphQL
|
|
132
132
|
end
|
133
133
|
|
134
134
|
def print_schema_definition(schema)
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
135
|
+
has_conventional_names = (schema.query.nil? || schema.query == 'Query') &&
|
136
|
+
(schema.mutation.nil? || schema.mutation == 'Mutation') &&
|
137
|
+
(schema.subscription.nil? || schema.subscription == 'Subscription')
|
138
|
+
|
139
|
+
if has_conventional_names && schema.directives.empty?
|
139
140
|
return
|
140
141
|
end
|
141
142
|
|
@@ -145,14 +146,22 @@ module GraphQL
|
|
145
146
|
out << "\n "
|
146
147
|
out << print_node(dir)
|
147
148
|
end
|
148
|
-
|
149
|
-
|
150
|
-
|
149
|
+
if !has_conventional_names
|
150
|
+
out << "\n"
|
151
|
+
end
|
151
152
|
end
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
153
|
+
|
154
|
+
if !has_conventional_names
|
155
|
+
if schema.directives.empty?
|
156
|
+
out << " "
|
157
|
+
end
|
158
|
+
out << "{\n"
|
159
|
+
out << " query: #{schema.query}\n" if schema.query
|
160
|
+
out << " mutation: #{schema.mutation}\n" if schema.mutation
|
161
|
+
out << " subscription: #{schema.subscription}\n" if schema.subscription
|
162
|
+
out << "}"
|
163
|
+
end
|
164
|
+
out
|
156
165
|
end
|
157
166
|
|
158
167
|
def print_scalar_type_definition(scalar_type)
|
@@ -93,7 +93,7 @@ module GraphQL
|
|
93
93
|
class ScopedContext
|
94
94
|
def initialize(query_context)
|
95
95
|
@query_context = query_context
|
96
|
-
@
|
96
|
+
@scoped_contexts = {}
|
97
97
|
@no_path = [].freeze
|
98
98
|
end
|
99
99
|
|
@@ -106,12 +106,17 @@ module GraphQL
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def merge!(hash)
|
109
|
-
|
110
|
-
|
109
|
+
ctx = @scoped_contexts
|
110
|
+
current_path.each do |path_part|
|
111
|
+
ctx = ctx[path_part] ||= { parent: ctx }
|
112
|
+
end
|
113
|
+
this_scoped_ctx = ctx[:scoped_context] ||= {}
|
114
|
+
this_scoped_ctx.merge!(hash)
|
111
115
|
end
|
112
116
|
|
113
117
|
def current_path
|
114
|
-
|
118
|
+
thread_info = Thread.current[:__graphql_runtime_info]
|
119
|
+
(thread_info && thread_info[:current_path]) || @no_path
|
115
120
|
end
|
116
121
|
|
117
122
|
def key?(key)
|
@@ -151,16 +156,20 @@ module GraphQL
|
|
151
156
|
# Start at the current location,
|
152
157
|
# but look up the tree for previously-assigned scoped values
|
153
158
|
def each_present_path_ctx
|
154
|
-
|
155
|
-
|
156
|
-
|
159
|
+
ctx = @scoped_contexts
|
160
|
+
current_path.each do |path_part|
|
161
|
+
if ctx.key?(path_part)
|
162
|
+
ctx = ctx[path_part]
|
163
|
+
else
|
164
|
+
break
|
165
|
+
end
|
157
166
|
end
|
158
167
|
|
159
|
-
while
|
160
|
-
|
161
|
-
|
162
|
-
yield(search_path_ctx)
|
168
|
+
while ctx
|
169
|
+
if (scoped_ctx = ctx[:scoped_context])
|
170
|
+
yield(scoped_ctx)
|
163
171
|
end
|
172
|
+
ctx = ctx[:parent]
|
164
173
|
end
|
165
174
|
end
|
166
175
|
end
|
@@ -189,6 +198,7 @@ module GraphQL
|
|
189
198
|
|
190
199
|
def_delegators :@query, :trace, :interpreter?
|
191
200
|
|
201
|
+
RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path])
|
192
202
|
# @!method []=(key, value)
|
193
203
|
# Reassign `key` to the hash passed to {Schema#execute} as `context:`
|
194
204
|
|
@@ -196,8 +206,14 @@ module GraphQL
|
|
196
206
|
def [](key)
|
197
207
|
if @scoped_context.key?(key)
|
198
208
|
@scoped_context[key]
|
199
|
-
|
209
|
+
elsif @provided_values.key?(key)
|
200
210
|
@provided_values[key]
|
211
|
+
elsif RUNTIME_METADATA_KEYS.include?(key)
|
212
|
+
thread_info = Thread.current[:__graphql_runtime_info]
|
213
|
+
thread_info && thread_info[key]
|
214
|
+
else
|
215
|
+
# not found
|
216
|
+
nil
|
201
217
|
end
|
202
218
|
end
|
203
219
|
|
@@ -212,7 +228,10 @@ module GraphQL
|
|
212
228
|
UNSPECIFIED_FETCH_DEFAULT = Object.new
|
213
229
|
|
214
230
|
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
215
|
-
if
|
231
|
+
if RUNTIME_METADATA_KEYS.include?(key)
|
232
|
+
(thread_info = Thread.current[:__graphql_runtime_info]) &&
|
233
|
+
thread_info[key]
|
234
|
+
elsif @scoped_context.key?(key)
|
216
235
|
scoped_context[key]
|
217
236
|
elsif @provided_values.key?(key)
|
218
237
|
@provided_values[key]
|
@@ -226,7 +245,10 @@ module GraphQL
|
|
226
245
|
end
|
227
246
|
|
228
247
|
def dig(key, *other_keys)
|
229
|
-
if
|
248
|
+
if RUNTIME_METADATA_KEYS.include?(key)
|
249
|
+
(thread_info = Thread.current[:__graphql_runtime_info]).key?(key) &&
|
250
|
+
thread_info.dig(key, *other_keys)
|
251
|
+
elsif @scoped_context.key?(key)
|
230
252
|
@scoped_context.dig(key, *other_keys)
|
231
253
|
else
|
232
254
|
@provided_values.dig(key, *other_keys)
|
@@ -259,7 +281,11 @@ module GraphQL
|
|
259
281
|
# @param ns [Object] a usage-specific namespace identifier
|
260
282
|
# @return [Hash] namespaced storage
|
261
283
|
def namespace(ns)
|
262
|
-
|
284
|
+
if ns == :interpreter
|
285
|
+
self
|
286
|
+
else
|
287
|
+
@storage[ns]
|
288
|
+
end
|
263
289
|
end
|
264
290
|
|
265
291
|
# @return [Boolean] true if this namespace was accessed before
|
data/lib/graphql/rake_task.rb
CHANGED
@@ -23,6 +23,10 @@ module GraphQL
|
|
23
23
|
# @example Invoking the task from Ruby
|
24
24
|
# require "rake"
|
25
25
|
# Rake::Task["graphql:schema:dump"].invoke
|
26
|
+
#
|
27
|
+
# @example Providing arguments to build the introspection query
|
28
|
+
# require "graphql/rake_task"
|
29
|
+
# GraphQL::RakeTask.new(schema_name: "MySchema", include_is_one_of: true)
|
26
30
|
class RakeTask
|
27
31
|
include Rake::DSL
|
28
32
|
|
@@ -37,6 +41,11 @@ module GraphQL
|
|
37
41
|
directory: ".",
|
38
42
|
idl_outfile: "schema.graphql",
|
39
43
|
json_outfile: "schema.json",
|
44
|
+
include_deprecated_args: true,
|
45
|
+
include_schema_description: false,
|
46
|
+
include_is_repeatable: false,
|
47
|
+
include_specified_by_url: false,
|
48
|
+
include_is_one_of: false
|
40
49
|
}
|
41
50
|
|
42
51
|
# @return [String] Namespace for generated tasks
|
@@ -74,6 +83,10 @@ module GraphQL
|
|
74
83
|
# @return [String] directory for IDL & JSON files
|
75
84
|
attr_accessor :directory
|
76
85
|
|
86
|
+
# @return [Boolean] Options for additional fields in the introspection query JSON response
|
87
|
+
# @see GraphQL::Schema.as_json
|
88
|
+
attr_accessor :include_deprecated_args, :include_schema_description, :include_is_repeatable, :include_specified_by_url, :include_is_one_of
|
89
|
+
|
77
90
|
# Set the parameters of this task by passing keyword arguments
|
78
91
|
# or assigning attributes inside the block
|
79
92
|
def initialize(options = {})
|
@@ -96,7 +109,21 @@ module GraphQL
|
|
96
109
|
def write_outfile(method_name, file)
|
97
110
|
schema = @load_schema.call(self)
|
98
111
|
context = @load_context.call(self)
|
99
|
-
result =
|
112
|
+
result = case method_name
|
113
|
+
when :to_json
|
114
|
+
schema.to_json(
|
115
|
+
include_is_one_of: include_is_one_of,
|
116
|
+
include_deprecated_args: include_deprecated_args,
|
117
|
+
include_is_repeatable: include_is_repeatable,
|
118
|
+
include_specified_by_url: include_specified_by_url,
|
119
|
+
include_schema_description: include_schema_description,
|
120
|
+
only: @only, except: @except, context: context
|
121
|
+
)
|
122
|
+
when :to_definition
|
123
|
+
schema.to_definition(only: @only, except: @except, context: context)
|
124
|
+
else
|
125
|
+
raise ArgumentError, "Unexpected schema dump method: #{method_name.inspect}"
|
126
|
+
end
|
100
127
|
dir = File.dirname(file)
|
101
128
|
FileUtils.mkdir_p(dir)
|
102
129
|
if !result.end_with?("\n")
|
@@ -6,16 +6,16 @@ module GraphQL
|
|
6
6
|
module BuildFromDefinition
|
7
7
|
class << self
|
8
8
|
# @see {Schema.from_definition}
|
9
|
-
def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs)
|
10
|
-
from_document(parser.parse(definition_string), **kwargs)
|
9
|
+
def from_definition(schema_superclass, definition_string, parser: GraphQL.default_parser, **kwargs)
|
10
|
+
from_document(schema_superclass, parser.parse(definition_string), **kwargs)
|
11
11
|
end
|
12
12
|
|
13
|
-
def from_definition_path(definition_path, parser: GraphQL.default_parser, **kwargs)
|
14
|
-
from_document(parser.parse_file(definition_path), **kwargs)
|
13
|
+
def from_definition_path(schema_superclass, definition_path, parser: GraphQL.default_parser, **kwargs)
|
14
|
+
from_document(schema_superclass, parser.parse_file(definition_path), **kwargs)
|
15
15
|
end
|
16
16
|
|
17
|
-
def from_document(document, default_resolve:, using: {}, relay: false)
|
18
|
-
Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using)
|
17
|
+
def from_document(schema_superclass, document, default_resolve:, using: {}, relay: false)
|
18
|
+
Builder.build(schema_superclass, document, default_resolve: default_resolve || {}, relay: relay, using: using)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -23,7 +23,7 @@ module GraphQL
|
|
23
23
|
module Builder
|
24
24
|
extend self
|
25
25
|
|
26
|
-
def build(document, default_resolve:, using: {}, relay:)
|
26
|
+
def build(schema_superclass, document, default_resolve:, using: {}, relay:)
|
27
27
|
raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
|
28
28
|
|
29
29
|
if default_resolve.is_a?(Hash)
|
@@ -36,7 +36,7 @@ module GraphQL
|
|
36
36
|
end
|
37
37
|
schema_definition = schema_defns.first
|
38
38
|
types = {}
|
39
|
-
directives =
|
39
|
+
directives = schema_superclass.directives.dup
|
40
40
|
type_resolver = build_resolve_type(types, directives, ->(type_name) { types[type_name] ||= Schema::LateBoundType.new(type_name)})
|
41
41
|
# Make a different type resolver because we need to coerce directive arguments
|
42
42
|
# _while_ building the schema.
|
@@ -65,10 +65,14 @@ module GraphQL
|
|
65
65
|
# In case any directives referenced built-in types for their arguments:
|
66
66
|
replace_late_bound_types_with_built_in(types)
|
67
67
|
|
68
|
+
schema_extensions = nil
|
68
69
|
document.definitions.each do |definition|
|
69
70
|
case definition
|
70
71
|
when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
|
71
72
|
nil # already handled
|
73
|
+
when GraphQL::Language::Nodes::SchemaExtension
|
74
|
+
schema_extensions ||= []
|
75
|
+
schema_extensions << definition
|
72
76
|
else
|
73
77
|
# It's possible that this was already loaded by the directives
|
74
78
|
prev_type = types[definition.name]
|
@@ -103,7 +107,7 @@ module GraphQL
|
|
103
107
|
|
104
108
|
raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
|
105
109
|
|
106
|
-
Class.new(
|
110
|
+
schema_class = Class.new(schema_superclass) do
|
107
111
|
begin
|
108
112
|
# Add these first so that there's some chance of resolving late-bound types
|
109
113
|
orphan_types types.values
|
@@ -157,6 +161,14 @@ module GraphQL
|
|
157
161
|
child_class.definition_default_resolve = self.definition_default_resolve
|
158
162
|
end
|
159
163
|
end
|
164
|
+
|
165
|
+
if schema_extensions
|
166
|
+
schema_extensions.each do |ext|
|
167
|
+
build_directives(schema_class, ext, type_resolver)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
schema_class
|
160
172
|
end
|
161
173
|
|
162
174
|
NullResolveType = ->(type, obj, ctx) {
|
@@ -196,13 +208,18 @@ module GraphQL
|
|
196
208
|
|
197
209
|
def build_directives(definition, ast_node, type_resolver)
|
198
210
|
dirs = prepare_directives(ast_node, type_resolver)
|
199
|
-
dirs.each do |dir_class, options|
|
200
|
-
definition.
|
211
|
+
dirs.each do |(dir_class, options)|
|
212
|
+
if definition.respond_to?(:schema_directive)
|
213
|
+
# it's a schema
|
214
|
+
definition.schema_directive(dir_class, **options)
|
215
|
+
else
|
216
|
+
definition.directive(dir_class, **options)
|
217
|
+
end
|
201
218
|
end
|
202
219
|
end
|
203
220
|
|
204
221
|
def prepare_directives(ast_node, type_resolver)
|
205
|
-
dirs =
|
222
|
+
dirs = []
|
206
223
|
ast_node.directives.each do |dir_node|
|
207
224
|
if dir_node.name == "deprecated"
|
208
225
|
# This is handled using `deprecation_reason`
|
@@ -210,10 +227,10 @@ module GraphQL
|
|
210
227
|
else
|
211
228
|
dir_class = type_resolver.call(dir_node.name)
|
212
229
|
if dir_class.nil?
|
213
|
-
raise ArgumentError, "No definition for @#{dir_node.name} on #{ast_node.name} at #{ast_node.line}:#{ast_node.col}"
|
230
|
+
raise ArgumentError, "No definition for @#{dir_node.name} #{ast_node.respond_to?(:name) ? "on #{ast_node.name} " : ""}at #{ast_node.line}:#{ast_node.col}"
|
214
231
|
end
|
215
232
|
options = args_to_kwargs(dir_class, dir_node)
|
216
|
-
dirs[dir_class
|
233
|
+
dirs << [dir_class, options]
|
217
234
|
end
|
218
235
|
end
|
219
236
|
dirs
|
@@ -389,7 +406,6 @@ module GraphQL
|
|
389
406
|
graphql_name(interface_type_definition.name)
|
390
407
|
description(interface_type_definition.description)
|
391
408
|
interface_type_definition.interfaces.each do |interface_name|
|
392
|
-
"Implements: #{interface_type_definition} -> #{interface_name}"
|
393
409
|
interface_defn = type_resolver.call(interface_name)
|
394
410
|
implements(interface_defn)
|
395
411
|
end
|
@@ -39,7 +39,7 @@ module GraphQL
|
|
39
39
|
transform_name = arguments[:by]
|
40
40
|
if TRANSFORMS.include?(transform_name) && return_value.respond_to?(transform_name)
|
41
41
|
return_value = return_value.public_send(transform_name)
|
42
|
-
response = context.namespace(:
|
42
|
+
response = context.namespace(:interpreter_runtime)[:runtime].final_result
|
43
43
|
*keys, last = path
|
44
44
|
keys.each do |key|
|
45
45
|
if response && (response = response[key])
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -129,10 +129,10 @@ module GraphQL
|
|
129
129
|
def connection?
|
130
130
|
if @connection.nil?
|
131
131
|
# Provide default based on type name
|
132
|
-
return_type_name = if @
|
133
|
-
Member::BuildType.to_type_name(@resolver_class.type)
|
134
|
-
elsif @return_type_expr
|
132
|
+
return_type_name = if @return_type_expr
|
135
133
|
Member::BuildType.to_type_name(@return_type_expr)
|
134
|
+
elsif @resolver_class && @resolver_class.type
|
135
|
+
Member::BuildType.to_type_name(@resolver_class.type)
|
136
136
|
else
|
137
137
|
# As a last ditch, try to force loading the return type:
|
138
138
|
type.unwrap.name
|
@@ -120,7 +120,7 @@ module GraphQL
|
|
120
120
|
def camelize(string)
|
121
121
|
return string if string == '_'
|
122
122
|
return string unless string.include?("_")
|
123
|
-
camelized = string.split('_').
|
123
|
+
camelized = string.split('_').each(&:capitalize!).join
|
124
124
|
camelized[0] = camelized[0].downcase
|
125
125
|
if (match_data = string.match(/\A(_+)/))
|
126
126
|
camelized = "#{match_data[0]}#{camelized}"
|
@@ -11,8 +11,7 @@ module GraphQL
|
|
11
11
|
# @return [void]
|
12
12
|
def directive(dir_class, **options)
|
13
13
|
@own_directives ||= []
|
14
|
-
|
15
|
-
@own_directives << dir_class.new(self, **options)
|
14
|
+
HasDirectives.add_directive(self, @own_directives, dir_class, options)
|
16
15
|
nil
|
17
16
|
end
|
18
17
|
|
@@ -20,78 +19,94 @@ module GraphQL
|
|
20
19
|
# @param dir_class [Class<GraphQL::Schema::Directive>]
|
21
20
|
# @return [viod]
|
22
21
|
def remove_directive(dir_class)
|
23
|
-
@own_directives
|
22
|
+
HasDirectives.remove_directive(@own_directives, dir_class)
|
24
23
|
nil
|
25
24
|
end
|
26
25
|
|
27
26
|
NO_DIRECTIVES = [].freeze
|
28
27
|
|
29
28
|
def directives
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
29
|
+
HasDirectives.get_directives(self, @own_directives, :directives)
|
30
|
+
end
|
31
|
+
|
32
|
+
class << self
|
33
|
+
def add_directive(schema_member, directives, directive_class, directive_options)
|
34
|
+
remove_directive(directives, directive_class) unless directive_class.repeatable?
|
35
|
+
directives << directive_class.new(schema_member, **directive_options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def remove_directive(directives, directive_class)
|
39
|
+
directives && directives.reject! { |d| d.is_a?(directive_class) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_directives(schema_member, directives, directives_method)
|
43
|
+
case schema_member
|
44
|
+
when Class
|
45
|
+
inherited_directives = if schema_member.superclass.respond_to?(directives_method)
|
46
|
+
get_directives(schema_member.superclass, schema_member.superclass.public_send(directives_method), directives_method)
|
47
|
+
else
|
48
|
+
NO_DIRECTIVES
|
49
|
+
end
|
50
|
+
if inherited_directives.any? && directives
|
51
|
+
dirs = []
|
52
|
+
merge_directives(dirs, inherited_directives)
|
53
|
+
merge_directives(dirs, directives)
|
54
|
+
dirs
|
55
|
+
elsif directives
|
56
|
+
directives
|
57
|
+
elsif inherited_directives.any?
|
58
|
+
inherited_directives
|
59
|
+
else
|
60
|
+
NO_DIRECTIVES
|
61
|
+
end
|
62
|
+
when Module
|
63
|
+
dirs = nil
|
64
|
+
schema_member.ancestors.reverse_each do |ancestor|
|
65
|
+
if ancestor.respond_to?(:own_directives) &&
|
66
|
+
(anc_dirs = ancestor.own_directives).any?
|
67
|
+
dirs ||= []
|
68
|
+
merge_directives(dirs, anc_dirs)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
if directives
|
54
72
|
dirs ||= []
|
55
|
-
merge_directives(dirs,
|
73
|
+
merge_directives(dirs, directives)
|
56
74
|
end
|
75
|
+
dirs || NO_DIRECTIVES
|
76
|
+
when HasDirectives
|
77
|
+
directives || NO_DIRECTIVES
|
78
|
+
else
|
79
|
+
raise "Invariant: how could #{schema_member} not be a Class, Module, or instance of HasDirectives?"
|
57
80
|
end
|
58
|
-
|
59
|
-
|
60
|
-
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# Modify `target` by adding items from `dirs` such that:
|
86
|
+
# - Any name conflict is overriden by the incoming member of `dirs`
|
87
|
+
# - Any other member of `dirs` is appended
|
88
|
+
# @param target [Array<GraphQL::Schema::Directive>]
|
89
|
+
# @param dirs [Array<GraphQL::Schema::Directive>]
|
90
|
+
# @return [void]
|
91
|
+
def merge_directives(target, dirs)
|
92
|
+
dirs.each do |dir|
|
93
|
+
if (idx = target.find_index { |d| d.graphql_name == dir.graphql_name })
|
94
|
+
target.slice!(idx)
|
95
|
+
target.insert(idx, dir)
|
96
|
+
else
|
97
|
+
target << dir
|
98
|
+
end
|
61
99
|
end
|
62
|
-
|
63
|
-
when HasDirectives
|
64
|
-
@own_directives || NO_DIRECTIVES
|
65
|
-
else
|
66
|
-
raise "Invariant: how could #{self} not be a Class, Module, or instance of HasDirectives?"
|
100
|
+
nil
|
67
101
|
end
|
68
102
|
end
|
69
103
|
|
104
|
+
|
70
105
|
protected
|
71
106
|
|
72
107
|
def own_directives
|
73
108
|
@own_directives
|
74
109
|
end
|
75
|
-
|
76
|
-
private
|
77
|
-
|
78
|
-
# Modify `target` by adding items from `dirs` such that:
|
79
|
-
# - Any name conflict is overriden by the incoming member of `dirs`
|
80
|
-
# - Any other member of `dirs` is appended
|
81
|
-
# @param target [Array<GraphQL::Schema::Directive>]
|
82
|
-
# @param dirs [Array<GraphQL::Schema::Directive>]
|
83
|
-
# @return [void]
|
84
|
-
def merge_directives(target, dirs)
|
85
|
-
dirs.each do |dir|
|
86
|
-
if (idx = target.find_index { |d| d.graphql_name == dir.graphql_name })
|
87
|
-
target.slice!(idx)
|
88
|
-
target.insert(idx, dir)
|
89
|
-
else
|
90
|
-
target << dir
|
91
|
-
end
|
92
|
-
end
|
93
|
-
nil
|
94
|
-
end
|
95
110
|
end
|
96
111
|
end
|
97
112
|
end
|
@@ -91,7 +91,7 @@ module GraphQL
|
|
91
91
|
resolver_fields = all_field_definitions
|
92
92
|
Class.new(object_class) do
|
93
93
|
graphql_name("#{resolver_name}Payload")
|
94
|
-
description("Autogenerated return type of #{resolver_name}")
|
94
|
+
description("Autogenerated return type of #{resolver_name}.")
|
95
95
|
resolver_fields.each do |f|
|
96
96
|
# Reattach the already-defined field here
|
97
97
|
# (The field's `.owner` will still point to the mutation, not the object type, I think)
|
@@ -11,6 +11,9 @@ module GraphQL
|
|
11
11
|
# @return [Class<GraphQL::Schema::Union>, Module<GraphQL::Schema::Interface>]
|
12
12
|
attr_reader :abstract_type
|
13
13
|
|
14
|
+
# @return [Hash]
|
15
|
+
attr_reader :options
|
16
|
+
|
14
17
|
# Called when an object is hooked up to an abstract type, such as {Schema::Union.possible_types}
|
15
18
|
# or {Schema::Object.implements} (for interfaces).
|
16
19
|
#
|
data/lib/graphql/schema/union.rb
CHANGED
@@ -70,9 +70,18 @@ module GraphQL
|
|
70
70
|
private
|
71
71
|
|
72
72
|
def assert_valid_union_member(type_defn)
|
73
|
-
|
73
|
+
case type_defn
|
74
|
+
when Class
|
75
|
+
if !type_defn.kind.object?
|
76
|
+
raise ArgumentError, "Union possible_types can only be object types (not #{type_defn.kind.name}, #{type_defn.inspect})"
|
77
|
+
end
|
78
|
+
when Module
|
74
79
|
# it's an interface type, defined as a module
|
75
80
|
raise ArgumentError, "Union possible_types can only be object types (not interface types), remove #{type_defn.graphql_name} (#{type_defn.inspect})"
|
81
|
+
when String, GraphQL::Schema::LateBoundType
|
82
|
+
# Ok - assume it will get checked later
|
83
|
+
else
|
84
|
+
raise ArgumentError, "Union possible_types can only be class-based GraphQL types (not #{type_defn.inspect} (#{type_defn.class.name}))."
|
76
85
|
end
|
77
86
|
end
|
78
87
|
end
|
data/lib/graphql/schema.rb
CHANGED
@@ -110,9 +110,10 @@ module GraphQL
|
|
110
110
|
# @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
|
111
111
|
# @return [Class] the schema described by `document`
|
112
112
|
def from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
|
113
|
-
# If the file ends in `.graphql`, treat it like a filepath
|
114
|
-
if definition_or_path.end_with?(".graphql")
|
113
|
+
# If the file ends in `.graphql` or `.graphqls`, treat it like a filepath
|
114
|
+
if definition_or_path.end_with?(".graphql") || definition_or_path.end_with?(".graphqls")
|
115
115
|
GraphQL::Schema::BuildFromDefinition.from_definition_path(
|
116
|
+
self,
|
116
117
|
definition_or_path,
|
117
118
|
default_resolve: default_resolve,
|
118
119
|
parser: parser,
|
@@ -120,6 +121,7 @@ module GraphQL
|
|
120
121
|
)
|
121
122
|
else
|
122
123
|
GraphQL::Schema::BuildFromDefinition.from_definition(
|
124
|
+
self,
|
123
125
|
definition_or_path,
|
124
126
|
default_resolve: default_resolve,
|
125
127
|
parser: parser,
|
@@ -152,9 +154,22 @@ module GraphQL
|
|
152
154
|
# @param context [Hash]
|
153
155
|
# @param only [<#call(member, ctx)>]
|
154
156
|
# @param except [<#call(member, ctx)>]
|
157
|
+
# @param include_deprecated_args [Boolean] If true, deprecated arguments will be included in the JSON response
|
158
|
+
# @param include_schema_description [Boolean] If true, the schema's description will be queried and included in the response
|
159
|
+
# @param include_is_repeatable [Boolean] If true, `isRepeatable: true|false` will be included with the schema's directives
|
160
|
+
# @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
|
161
|
+
# @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
|
155
162
|
# @return [Hash] GraphQL result
|
156
|
-
def as_json(only: nil, except: nil, context: {})
|
157
|
-
|
163
|
+
def as_json(only: nil, except: nil, context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
|
164
|
+
introspection_query = Introspection.query(
|
165
|
+
include_deprecated_args: include_deprecated_args,
|
166
|
+
include_schema_description: include_schema_description,
|
167
|
+
include_is_repeatable: include_is_repeatable,
|
168
|
+
include_is_one_of: include_is_one_of,
|
169
|
+
include_specified_by_url: include_specified_by_url,
|
170
|
+
)
|
171
|
+
|
172
|
+
execute(introspection_query, only: only, except: except, context: context).to_h
|
158
173
|
end
|
159
174
|
|
160
175
|
# Return the GraphQL IDL for the schema
|
@@ -738,11 +753,10 @@ module GraphQL
|
|
738
753
|
def handle_or_reraise(context, err)
|
739
754
|
handler = Execution::Errors.find_handler_for(self, err.class)
|
740
755
|
if handler
|
741
|
-
|
742
|
-
|
743
|
-
args = runtime_info[:current_arguments]
|
756
|
+
obj = context[:current_object]
|
757
|
+
args = context[:current_arguments]
|
744
758
|
args = args && args.keyword_arguments
|
745
|
-
field =
|
759
|
+
field = context[:current_field]
|
746
760
|
if obj.is_a?(GraphQL::Schema::Object)
|
747
761
|
obj = obj.object
|
748
762
|
end
|
@@ -816,6 +830,15 @@ module GraphQL
|
|
816
830
|
member.accessible?(ctx)
|
817
831
|
end
|
818
832
|
|
833
|
+
def schema_directive(dir_class, **options)
|
834
|
+
@own_schema_directives ||= []
|
835
|
+
Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
|
836
|
+
end
|
837
|
+
|
838
|
+
def schema_directives
|
839
|
+
Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
|
840
|
+
end
|
841
|
+
|
819
842
|
# This hook is called when a client tries to access one or more
|
820
843
|
# fields that fail the `accessible?` check.
|
821
844
|
#
|
@@ -127,8 +127,14 @@ module GraphQL
|
|
127
127
|
# same name as if they were the same name. If _any_ of the fragments
|
128
128
|
# with that name has a dependency, we record it.
|
129
129
|
independent_fragment_nodes = @defdep_fragment_definitions.values.flatten - @defdep_immediate_dependencies.keys
|
130
|
-
|
130
|
+
visited_fragment_names = Set.new
|
131
131
|
while fragment_node = independent_fragment_nodes.pop
|
132
|
+
if visited_fragment_names.add?(fragment_node.name)
|
133
|
+
# this is a new fragment name
|
134
|
+
else
|
135
|
+
# this is a duplicate fragment name
|
136
|
+
next
|
137
|
+
end
|
132
138
|
loops += 1
|
133
139
|
if loops > max_loops
|
134
140
|
raise("Resolution loops exceeded the number of definitions; infinite loop detected. (Max: #{max_loops}, Current: #{loops})")
|
@@ -91,7 +91,13 @@ module GraphQL
|
|
91
91
|
# A per-process map of subscriptions to deliver.
|
92
92
|
# This is provided by Rails, so let's use it
|
93
93
|
@subscriptions = Concurrent::Map.new
|
94
|
-
@events = Concurrent::Map.new
|
94
|
+
@events = Concurrent::Map.new do |h, k|
|
95
|
+
h.compute_if_absent(k) do
|
96
|
+
Concurrent::Map.new do |h2, k2|
|
97
|
+
h2.compute_if_absent(k2) { Concurrent::Array.new }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
95
101
|
@action_cable = action_cable
|
96
102
|
@action_cable_coder = action_cable_coder
|
97
103
|
@serializer = serializer
|
@@ -90,6 +90,7 @@ module GraphQL
|
|
90
90
|
arguments: normalized_args,
|
91
91
|
field: field,
|
92
92
|
scope: scope,
|
93
|
+
context: context,
|
93
94
|
)
|
94
95
|
execute_all(event, object)
|
95
96
|
end
|
@@ -124,6 +125,10 @@ module GraphQL
|
|
124
125
|
variables: variables,
|
125
126
|
root_value: object,
|
126
127
|
}
|
128
|
+
|
129
|
+
# merge event's and query's context together
|
130
|
+
context.merge!(event.context) unless event.context.nil? || context.nil?
|
131
|
+
|
127
132
|
execute_options[:validate] = validate_update?(**execute_options)
|
128
133
|
result = @schema.execute(**execute_options)
|
129
134
|
subscriptions_context = result.context.namespace(:subscriptions)
|
@@ -50,6 +50,8 @@ module GraphQL
|
|
50
50
|
null: edges_nullable,
|
51
51
|
description: "A list of edges.",
|
52
52
|
connection: false,
|
53
|
+
# Assume that the connection was scoped before this step:
|
54
|
+
scope: false,
|
53
55
|
}
|
54
56
|
|
55
57
|
if field_options
|
@@ -135,6 +137,8 @@ module GraphQL
|
|
135
137
|
null: nullable,
|
136
138
|
description: "A list of nodes.",
|
137
139
|
connection: false,
|
140
|
+
# Assume that the connection was scoped before this step:
|
141
|
+
scope: false,
|
138
142
|
}
|
139
143
|
if field_options
|
140
144
|
base_field_options.merge!(field_options)
|
@@ -13,7 +13,13 @@ module GraphQL
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def default_relay?
|
16
|
-
|
16
|
+
if defined?(@default_relay)
|
17
|
+
@default_relay
|
18
|
+
elsif self.is_a?(Class)
|
19
|
+
superclass.respond_to?(:default_relay?) && superclass.default_relay?
|
20
|
+
else
|
21
|
+
false
|
22
|
+
end
|
17
23
|
end
|
18
24
|
end
|
19
25
|
end
|
@@ -8,6 +8,7 @@ module GraphQL
|
|
8
8
|
child_class.description("An edge in a connection.")
|
9
9
|
child_class.field(:cursor, String, null: false, description: "A cursor for use in pagination.")
|
10
10
|
child_class.extend(ClassMethods)
|
11
|
+
child_class.extend(GraphQL::Types::Relay::DefaultRelay)
|
11
12
|
child_class.node_nullable(true)
|
12
13
|
end
|
13
14
|
|
data/lib/graphql/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -597,7 +597,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
597
597
|
- !ruby/object:Gem::Version
|
598
598
|
version: '0'
|
599
599
|
requirements: []
|
600
|
-
rubygems_version: 3.
|
600
|
+
rubygems_version: 3.3.3
|
601
601
|
signing_key:
|
602
602
|
specification_version: 4
|
603
603
|
summary: A GraphQL language and runtime for Ruby
|