graphql 2.0.14 → 2.0.16
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.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- 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
|