graphql 2.0.14 → 2.0.15
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 +19 -5
- 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.rb +16 -6
- data/lib/graphql/tracing/instrumentation_tracing.rb +83 -0
- data/lib/graphql/types/relay/node_behaviors.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46b43157a331eae41dd54897d24dbc3adac190910237c7c1c158fc2bc32b6616
|
4
|
+
data.tar.gz: 118ac97b740ba1340d3e6b9aee5fa2f81ca25dc8769a98ec0d8e25d63e839711
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be38356ecdff7f8a9627bb021e83d13ea92e951b287386e76fd6e42ff05ef0a5a37ce9c98e6e4bf1834459989558f6c8b512c98e7642bef2c624578c1db24932
|
7
|
+
data.tar.gz: b0b75f342dca7a731b1b59e6399d364184152ceb0c5deb9fb4338a3582b3b6e38bf789a53839f6def9eb4b9c079c45e74675fb608a184dff4e6aeaf0ce052dfd
|
@@ -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)
|
@@ -111,7 +111,7 @@ module GraphQL
|
|
111
111
|
end
|
112
112
|
|
113
113
|
def current_path
|
114
|
-
@query_context
|
114
|
+
@query_context[:current_path] || @no_path
|
115
115
|
end
|
116
116
|
|
117
117
|
def key?(key)
|
@@ -189,12 +189,16 @@ module GraphQL
|
|
189
189
|
|
190
190
|
def_delegators :@query, :trace, :interpreter?
|
191
191
|
|
192
|
+
RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path])
|
192
193
|
# @!method []=(key, value)
|
193
194
|
# Reassign `key` to the hash passed to {Schema#execute} as `context:`
|
194
195
|
|
195
196
|
# Lookup `key` from the hash passed to {Schema#execute} as `context:`
|
196
197
|
def [](key)
|
197
|
-
if
|
198
|
+
if RUNTIME_METADATA_KEYS.include?(key)
|
199
|
+
thread_info = Thread.current[:__graphql_runtime_info]
|
200
|
+
thread_info && thread_info[key]
|
201
|
+
elsif @scoped_context.key?(key)
|
198
202
|
@scoped_context[key]
|
199
203
|
else
|
200
204
|
@provided_values[key]
|
@@ -212,7 +216,10 @@ module GraphQL
|
|
212
216
|
UNSPECIFIED_FETCH_DEFAULT = Object.new
|
213
217
|
|
214
218
|
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
215
|
-
if
|
219
|
+
if RUNTIME_METADATA_KEYS.include?(key)
|
220
|
+
(thread_info = Thread.current[:__graphql_runtime_info]) &&
|
221
|
+
thread_info[key]
|
222
|
+
elsif @scoped_context.key?(key)
|
216
223
|
scoped_context[key]
|
217
224
|
elsif @provided_values.key?(key)
|
218
225
|
@provided_values[key]
|
@@ -226,7 +233,10 @@ module GraphQL
|
|
226
233
|
end
|
227
234
|
|
228
235
|
def dig(key, *other_keys)
|
229
|
-
if
|
236
|
+
if RUNTIME_METADATA_KEYS.include?(key)
|
237
|
+
(thread_info = Thread.current[:__graphql_runtime_info]).key?(key) &&
|
238
|
+
thread_info.dig(key)
|
239
|
+
elsif @scoped_context.key?(key)
|
230
240
|
@scoped_context.dig(key, *other_keys)
|
231
241
|
else
|
232
242
|
@provided_values.dig(key, *other_keys)
|
@@ -259,7 +269,11 @@ module GraphQL
|
|
259
269
|
# @param ns [Object] a usage-specific namespace identifier
|
260
270
|
# @return [Hash] namespaced storage
|
261
271
|
def namespace(ns)
|
262
|
-
|
272
|
+
if ns == :interpreter
|
273
|
+
self
|
274
|
+
else
|
275
|
+
@storage[ns]
|
276
|
+
end
|
263
277
|
end
|
264
278
|
|
265
279
|
# @return [Boolean] true if this namespace was accessed before
|
@@ -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.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,
|
@@ -738,11 +740,10 @@ module GraphQL
|
|
738
740
|
def handle_or_reraise(context, err)
|
739
741
|
handler = Execution::Errors.find_handler_for(self, err.class)
|
740
742
|
if handler
|
741
|
-
|
742
|
-
|
743
|
-
args = runtime_info[:current_arguments]
|
743
|
+
obj = context[:current_object]
|
744
|
+
args = context[:current_arguments]
|
744
745
|
args = args && args.keyword_arguments
|
745
|
-
field =
|
746
|
+
field = context[:current_field]
|
746
747
|
if obj.is_a?(GraphQL::Schema::Object)
|
747
748
|
obj = obj.object
|
748
749
|
end
|
@@ -816,6 +817,15 @@ module GraphQL
|
|
816
817
|
member.accessible?(ctx)
|
817
818
|
end
|
818
819
|
|
820
|
+
def schema_directive(dir_class, **options)
|
821
|
+
@own_schema_directives ||= []
|
822
|
+
Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
|
823
|
+
end
|
824
|
+
|
825
|
+
def schema_directives
|
826
|
+
Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
|
827
|
+
end
|
828
|
+
|
819
829
|
# This hook is called when a client tries to access one or more
|
820
830
|
# fields that fail the `accessible?` check.
|
821
831
|
#
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module Tracing
|
3
|
+
class InstrumentationTracing
|
4
|
+
def initialize(schema)
|
5
|
+
@schema = schema
|
6
|
+
end
|
7
|
+
|
8
|
+
def trace(event, data)
|
9
|
+
instrumenters = nil
|
10
|
+
query_instrumenters = nil
|
11
|
+
case event
|
12
|
+
when "execute_multiplex"
|
13
|
+
instrumenters = @schema.instrumenters
|
14
|
+
multiplex_instrumenters = instrumenters[:multiplex]
|
15
|
+
query_instrumenters = instrumenters[:query]
|
16
|
+
call_hooks(multiplex_instrumenters, data[:multiplex], :before_multiplex, :after_multiplex) {
|
17
|
+
each_query_call_hooks(query_instrumenters, data[:multiplex].queries) {
|
18
|
+
yield
|
19
|
+
}
|
20
|
+
}
|
21
|
+
else
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Call the before_ hooks of each query,
|
29
|
+
# Then yield if no errors.
|
30
|
+
# `call_hooks` takes care of appropriate cleanup.
|
31
|
+
def each_query_call_hooks(instrumenters, queries, i = 0)
|
32
|
+
if i >= queries.length
|
33
|
+
yield
|
34
|
+
else
|
35
|
+
query = queries[i]
|
36
|
+
call_hooks(instrumenters, query, :before_query, :after_query) {
|
37
|
+
each_query_call_hooks(instrumenters, queries, i + 1) {
|
38
|
+
yield
|
39
|
+
}
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Call each before hook, and if they all succeed, yield.
|
45
|
+
# If they don't all succeed, call after_ for each one that succeeded.
|
46
|
+
def call_hooks(instrumenters, object, before_hook_name, after_hook_name)
|
47
|
+
begin
|
48
|
+
successful = []
|
49
|
+
instrumenters.each do |instrumenter|
|
50
|
+
instrumenter.public_send(before_hook_name, object)
|
51
|
+
successful << instrumenter
|
52
|
+
end
|
53
|
+
|
54
|
+
# if any before hooks raise an exception, quit calling before hooks,
|
55
|
+
# but call the after hooks on anything that succeeded but also
|
56
|
+
# raise the exception that came from the before hook.
|
57
|
+
rescue GraphQL::ExecutionError => err
|
58
|
+
object.context.errors << err
|
59
|
+
rescue => e
|
60
|
+
raise call_after_hooks(successful, object, after_hook_name, e)
|
61
|
+
end
|
62
|
+
|
63
|
+
begin
|
64
|
+
yield # Call the user code
|
65
|
+
ensure
|
66
|
+
ex = call_after_hooks(successful, object, after_hook_name, nil)
|
67
|
+
raise ex if ex
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def call_after_hooks(instrumenters, object, after_hook_name, ex)
|
72
|
+
instrumenters.reverse_each do |instrumenter|
|
73
|
+
begin
|
74
|
+
instrumenter.public_send(after_hook_name, object)
|
75
|
+
rescue => e
|
76
|
+
ex = e
|
77
|
+
end
|
78
|
+
end
|
79
|
+
ex
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
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.15
|
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-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -538,6 +538,7 @@ files:
|
|
538
538
|
- lib/graphql/tracing/appoptics_tracing.rb
|
539
539
|
- lib/graphql/tracing/appsignal_tracing.rb
|
540
540
|
- lib/graphql/tracing/data_dog_tracing.rb
|
541
|
+
- lib/graphql/tracing/instrumentation_tracing.rb
|
541
542
|
- lib/graphql/tracing/new_relic_tracing.rb
|
542
543
|
- lib/graphql/tracing/notifications_tracing.rb
|
543
544
|
- lib/graphql/tracing/platform_tracing.rb
|