graphql 2.4.7 → 2.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql/backtrace/table.rb +95 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +11 -4
- data/lib/graphql/execution/interpreter/runtime.rb +34 -26
- data/lib/graphql/execution/interpreter.rb +3 -1
- data/lib/graphql/execution/multiplex.rb +0 -4
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/query.rb +0 -8
- data/lib/graphql/schema/build_from_definition.rb +1 -0
- data/lib/graphql/schema/enum.rb +21 -1
- data/lib/graphql/schema/resolver.rb +1 -0
- data/lib/graphql/schema/subscription.rb +50 -4
- data/lib/graphql/schema/validator/required_validator.rb +23 -6
- data/lib/graphql/schema/visibility/profile.rb +1 -1
- data/lib/graphql/schema.rb +8 -24
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +12 -1
- data/lib/graphql/subscriptions/serialize.rb +1 -3
- data/lib/graphql/tracing/active_support_notifications_trace.rb +1 -1
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +2 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -0
- data/lib/graphql/tracing/appsignal_trace.rb +2 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +2 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/new_relic_trace.rb +2 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
- data/lib/graphql/tracing/prometheus_trace.rb +5 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +2 -0
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +2 -0
- data/lib/graphql/tracing/statsd_trace.rb +2 -0
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +4 -1
- data/lib/graphql/tracing.rb +28 -30
- data/lib/graphql/version.rb +1 -1
- metadata +103 -9
- data/lib/graphql/backtrace/inspect_result.rb +0 -38
- data/lib/graphql/backtrace/trace.rb +0 -93
- data/lib/graphql/backtrace/tracer.rb +0 -80
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 687da1733554d6abed2daad506c7f9d55d9126e373274572af5b255c3d7b4918
|
4
|
+
data.tar.gz: c2d2f58175df62c91ab31c3216b970a0bc09d1752250fc8192d1faa958cf1fe9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4001700112f8ed43e78b4c739daac90973f08035bef426d5611d91248dd60d4d0070f8fff7042ac57b0549ddac62ac1111262fe0a47c10a83cd3c7a9a0612b8
|
7
|
+
data.tar.gz: a6a1aaacf19bba38d2e0ee55ac9cdfa0d46b915706557c2dbac533d8fc58319d7c4ff8509019789fb39c46d6c01767f6cd27a02917fc7a3a7bdc30fc81eca5e4
|
@@ -36,7 +36,70 @@ module GraphQL
|
|
36
36
|
private
|
37
37
|
|
38
38
|
def rows
|
39
|
-
@rows ||=
|
39
|
+
@rows ||= begin
|
40
|
+
query = @context.query
|
41
|
+
query_ctx = @context
|
42
|
+
runtime_inst = query_ctx.namespace(:interpreter_runtime)[:runtime]
|
43
|
+
result = runtime_inst.instance_variable_get(:@response)
|
44
|
+
rows = []
|
45
|
+
result_path = []
|
46
|
+
last_part = nil
|
47
|
+
path = @context.current_path
|
48
|
+
path.each do |path_part|
|
49
|
+
value = value_at(runtime_inst, result_path)
|
50
|
+
|
51
|
+
if result_path.empty?
|
52
|
+
name = query.selected_operation.operation_type || "query"
|
53
|
+
if (n = query.selected_operation_name)
|
54
|
+
name += " #{n}"
|
55
|
+
end
|
56
|
+
args = query.variables
|
57
|
+
else
|
58
|
+
name = result.graphql_field.path
|
59
|
+
args = result.graphql_arguments
|
60
|
+
end
|
61
|
+
|
62
|
+
object = result.graphql_parent ? result.graphql_parent.graphql_application_value : result.graphql_application_value
|
63
|
+
object = object.object.inspect
|
64
|
+
|
65
|
+
rows << [
|
66
|
+
result.ast_node.position.join(":"),
|
67
|
+
name,
|
68
|
+
"#{object}",
|
69
|
+
args.to_h.inspect,
|
70
|
+
inspect_result(value),
|
71
|
+
]
|
72
|
+
|
73
|
+
result_path << path_part
|
74
|
+
if path_part == path.last
|
75
|
+
last_part = path_part
|
76
|
+
else
|
77
|
+
result = result[path_part]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
object = result.graphql_application_value.object.inspect
|
83
|
+
ast_node = result.graphql_selections.find { |s| s.alias == last_part || s.name == last_part }
|
84
|
+
field_defn = query.get_field(result.graphql_result_type, ast_node.name)
|
85
|
+
args = query.arguments_for(ast_node, field_defn).to_h
|
86
|
+
field_path = field_defn.path
|
87
|
+
if ast_node.alias
|
88
|
+
field_path += " as #{ast_node.alias}"
|
89
|
+
end
|
90
|
+
|
91
|
+
rows << [
|
92
|
+
ast_node.position.join(":"),
|
93
|
+
field_path,
|
94
|
+
"#{object}",
|
95
|
+
args.inspect,
|
96
|
+
inspect_result(@override_value)
|
97
|
+
]
|
98
|
+
|
99
|
+
rows << HEADERS
|
100
|
+
rows.reverse!
|
101
|
+
rows
|
102
|
+
end
|
40
103
|
end
|
41
104
|
|
42
105
|
# @return [String]
|
@@ -75,67 +138,44 @@ module GraphQL
|
|
75
138
|
table
|
76
139
|
end
|
77
140
|
|
78
|
-
# @return [Array] 5 items for a backtrace table (not `key`)
|
79
|
-
def build_rows(context_entry, rows:, top: false)
|
80
|
-
case context_entry
|
81
|
-
when Backtrace::Frame
|
82
|
-
field_alias = context_entry.ast_node.respond_to?(:alias) && context_entry.ast_node.alias
|
83
|
-
value = if top && @override_value
|
84
|
-
@override_value
|
85
|
-
else
|
86
|
-
value_at(@context.query.context.namespace(:interpreter_runtime)[:runtime], context_entry.path)
|
87
|
-
end
|
88
|
-
rows << [
|
89
|
-
"#{context_entry.ast_node ? context_entry.ast_node.position.join(":") : ""}",
|
90
|
-
"#{context_entry.field.path}#{field_alias ? " as #{field_alias}" : ""}",
|
91
|
-
"#{context_entry.object.object.inspect}",
|
92
|
-
context_entry.arguments.to_h.inspect, # rubocop:disable Development/ContextIsPassedCop -- unrelated method
|
93
|
-
Backtrace::InspectResult.inspect_result(value),
|
94
|
-
]
|
95
|
-
if (parent = context_entry.parent_frame)
|
96
|
-
build_rows(parent, rows: rows)
|
97
|
-
else
|
98
|
-
rows
|
99
|
-
end
|
100
|
-
when GraphQL::Query::Context
|
101
|
-
query = context_entry.query
|
102
|
-
op = query.selected_operation
|
103
|
-
if op
|
104
|
-
op_type = op.operation_type
|
105
|
-
position = "#{op.line}:#{op.col}"
|
106
|
-
else
|
107
|
-
op_type = "query"
|
108
|
-
position = "?:?"
|
109
|
-
end
|
110
|
-
op_name = query.selected_operation_name
|
111
|
-
object = query.root_value
|
112
|
-
if object.is_a?(GraphQL::Schema::Object)
|
113
|
-
object = object.object
|
114
|
-
end
|
115
|
-
value = value_at(context_entry.namespace(:interpreter_runtime)[:runtime], [])
|
116
|
-
rows << [
|
117
|
-
"#{position}",
|
118
|
-
"#{op_type}#{op_name ? " #{op_name}" : ""}",
|
119
|
-
"#{object.inspect}",
|
120
|
-
query.variables.to_h.inspect,
|
121
|
-
Backtrace::InspectResult.inspect_result(value),
|
122
|
-
]
|
123
|
-
else
|
124
|
-
raise "Unexpected get_rows subject #{context_entry.class} (#{context_entry.inspect})"
|
125
|
-
end
|
126
|
-
end
|
127
141
|
|
128
142
|
def value_at(runtime, path)
|
129
143
|
response = runtime.final_result
|
130
144
|
path.each do |key|
|
131
|
-
|
132
|
-
next
|
133
|
-
else
|
134
|
-
break
|
135
|
-
end
|
145
|
+
response && (response = response[key])
|
136
146
|
end
|
137
147
|
response
|
138
148
|
end
|
149
|
+
|
150
|
+
def inspect_result(obj)
|
151
|
+
case obj
|
152
|
+
when Hash
|
153
|
+
"{" +
|
154
|
+
obj.map do |key, val|
|
155
|
+
"#{key}: #{inspect_truncated(val)}"
|
156
|
+
end.join(", ") +
|
157
|
+
"}"
|
158
|
+
when Array
|
159
|
+
"[" +
|
160
|
+
obj.map { |v| inspect_truncated(v) }.join(", ") +
|
161
|
+
"]"
|
162
|
+
else
|
163
|
+
inspect_truncated(obj)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def inspect_truncated(obj)
|
168
|
+
case obj
|
169
|
+
when Hash
|
170
|
+
"{...}"
|
171
|
+
when Array
|
172
|
+
"[...]"
|
173
|
+
when GraphQL::Execution::Lazy
|
174
|
+
"(unresolved)"
|
175
|
+
else
|
176
|
+
"#{obj.inspect}"
|
177
|
+
end
|
178
|
+
end
|
139
179
|
end
|
140
180
|
end
|
141
181
|
end
|
data/lib/graphql/backtrace.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require "graphql/backtrace/inspect_result"
|
3
2
|
require "graphql/backtrace/table"
|
4
3
|
require "graphql/backtrace/traced_error"
|
5
|
-
require "graphql/backtrace/tracer"
|
6
|
-
require "graphql/backtrace/trace"
|
7
4
|
module GraphQL
|
8
5
|
# Wrap unhandled errors with {TracedError}.
|
9
6
|
#
|
@@ -24,7 +21,7 @@ module GraphQL
|
|
24
21
|
def_delegators :to_a, :each, :[]
|
25
22
|
|
26
23
|
def self.use(schema_defn)
|
27
|
-
schema_defn.
|
24
|
+
schema_defn.using_backtrace = true
|
28
25
|
end
|
29
26
|
|
30
27
|
def initialize(context, value: nil)
|
@@ -40,20 +37,5 @@ module GraphQL
|
|
40
37
|
def to_a
|
41
38
|
@table.to_backtrace
|
42
39
|
end
|
43
|
-
|
44
|
-
# Used for internal bookkeeping
|
45
|
-
# @api private
|
46
|
-
class Frame
|
47
|
-
attr_reader :path, :query, :ast_node, :object, :field, :arguments, :parent_frame
|
48
|
-
def initialize(path:, query:, ast_node:, object:, field:, arguments:, parent_frame:)
|
49
|
-
@path = path
|
50
|
-
@query = query
|
51
|
-
@ast_node = ast_node
|
52
|
-
@field = field
|
53
|
-
@object = object
|
54
|
-
@arguments = arguments
|
55
|
-
@parent_frame = parent_frame
|
56
|
-
end
|
57
|
-
end
|
58
40
|
end
|
59
41
|
end
|
@@ -5,7 +5,10 @@ module GraphQL
|
|
5
5
|
class Interpreter
|
6
6
|
class Runtime
|
7
7
|
module GraphQLResult
|
8
|
-
def initialize(result_name, result_type, application_value, parent_result, is_non_null_in_parent, selections, is_eager)
|
8
|
+
def initialize(result_name, result_type, application_value, parent_result, is_non_null_in_parent, selections, is_eager, ast_node, graphql_arguments, graphql_field) # rubocop:disable Metrics/ParameterLists
|
9
|
+
@ast_node = ast_node
|
10
|
+
@graphql_arguments = graphql_arguments
|
11
|
+
@graphql_field = graphql_field
|
9
12
|
@graphql_parent = parent_result
|
10
13
|
@graphql_application_value = application_value
|
11
14
|
@graphql_result_type = result_type
|
@@ -31,14 +34,14 @@ module GraphQL
|
|
31
34
|
|
32
35
|
attr_accessor :graphql_dead
|
33
36
|
attr_reader :graphql_parent, :graphql_result_name, :graphql_is_non_null_in_parent,
|
34
|
-
:graphql_application_value, :graphql_result_type, :graphql_selections, :graphql_is_eager
|
37
|
+
:graphql_application_value, :graphql_result_type, :graphql_selections, :graphql_is_eager, :ast_node, :graphql_arguments, :graphql_field
|
35
38
|
|
36
39
|
# @return [Hash] Plain-Ruby result data (`@graphql_metadata` contains Result wrapper objects)
|
37
40
|
attr_accessor :graphql_result_data
|
38
41
|
end
|
39
42
|
|
40
43
|
class GraphQLResultHash
|
41
|
-
def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager)
|
44
|
+
def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager, _ast_node, _graphql_arguments, graphql_field) # rubocop:disable Metrics/ParameterLists
|
42
45
|
super
|
43
46
|
@graphql_result_data = {}
|
44
47
|
end
|
@@ -126,7 +129,7 @@ module GraphQL
|
|
126
129
|
class GraphQLResultArray
|
127
130
|
include GraphQLResult
|
128
131
|
|
129
|
-
def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager)
|
132
|
+
def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager, _ast_node, _graphql_arguments, graphql_field) # rubocop:disable Metrics/ParameterLists
|
130
133
|
super
|
131
134
|
@graphql_result_data = []
|
132
135
|
end
|
@@ -168,6 +171,10 @@ module GraphQL
|
|
168
171
|
def values
|
169
172
|
(@graphql_metadata || @graphql_result_data)
|
170
173
|
end
|
174
|
+
|
175
|
+
def [](idx)
|
176
|
+
(@graphql_metadata || @graphql_result_data)[idx]
|
177
|
+
end
|
171
178
|
end
|
172
179
|
end
|
173
180
|
end
|
@@ -74,7 +74,7 @@ module GraphQL
|
|
74
74
|
runtime_object = root_type.wrap(query.root_value, context)
|
75
75
|
runtime_object = schema.sync_lazy(runtime_object)
|
76
76
|
is_eager = root_op_type == "mutation"
|
77
|
-
@response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, root_operation.selections, is_eager)
|
77
|
+
@response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, root_operation.selections, is_eager, root_operation, nil, nil)
|
78
78
|
st = get_current_runtime_state
|
79
79
|
st.current_result = @response
|
80
80
|
|
@@ -85,7 +85,7 @@ module GraphQL
|
|
85
85
|
call_method_on_directives(:resolve, runtime_object, root_operation.directives) do # execute query level directives
|
86
86
|
each_gathered_selections(@response) do |selections, is_selection_array|
|
87
87
|
if is_selection_array
|
88
|
-
selection_response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, selections, is_eager)
|
88
|
+
selection_response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, selections, is_eager, root_operation, nil, nil)
|
89
89
|
final_response = @response
|
90
90
|
else
|
91
91
|
selection_response = @response
|
@@ -574,7 +574,7 @@ module GraphQL
|
|
574
574
|
r = begin
|
575
575
|
current_type.coerce_result(value, context)
|
576
576
|
rescue StandardError => err
|
577
|
-
|
577
|
+
query.handle_or_reraise(err)
|
578
578
|
end
|
579
579
|
set_result(selection_result, result_name, r, false, is_non_null)
|
580
580
|
r
|
@@ -609,11 +609,11 @@ module GraphQL
|
|
609
609
|
after_lazy(object_proxy, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |inner_object, runtime_state|
|
610
610
|
continue_value = continue_value(inner_object, field, is_non_null, ast_node, result_name, selection_result)
|
611
611
|
if HALT != continue_value
|
612
|
-
response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, next_selections, false)
|
612
|
+
response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
|
613
613
|
set_result(selection_result, result_name, response_hash, true, is_non_null)
|
614
614
|
each_gathered_selections(response_hash) do |selections, is_selection_array|
|
615
615
|
if is_selection_array
|
616
|
-
this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, selections, false)
|
616
|
+
this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, selections, false, ast_node, arguments, field)
|
617
617
|
final_result = response_hash
|
618
618
|
else
|
619
619
|
this_result = response_hash
|
@@ -634,35 +634,43 @@ module GraphQL
|
|
634
634
|
# This is true for objects, unions, and interfaces
|
635
635
|
use_dataloader_job = !inner_type.unwrap.kind.input?
|
636
636
|
inner_type_non_null = inner_type.non_null?
|
637
|
-
response_list = GraphQLResultArray.new(result_name, current_type, owner_object, selection_result, is_non_null, next_selections, false)
|
637
|
+
response_list = GraphQLResultArray.new(result_name, current_type, owner_object, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
|
638
638
|
set_result(selection_result, result_name, response_list, true, is_non_null)
|
639
639
|
idx = nil
|
640
640
|
list_value = begin
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
641
|
+
begin
|
642
|
+
value.each do |inner_value|
|
643
|
+
idx ||= 0
|
644
|
+
this_idx = idx
|
645
|
+
idx += 1
|
646
|
+
if use_dataloader_job
|
647
|
+
@dataloader.append_job do
|
648
|
+
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
|
649
|
+
end
|
650
|
+
else
|
647
651
|
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
|
648
652
|
end
|
649
|
-
else
|
650
|
-
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
|
651
653
|
end
|
652
|
-
end
|
653
654
|
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
655
|
+
response_list
|
656
|
+
rescue NoMethodError => err
|
657
|
+
# Ruby 2.2 doesn't have NoMethodError#receiver, can't check that one in this case. (It's been EOL since 2017.)
|
658
|
+
if err.name == :each && (err.respond_to?(:receiver) ? err.receiver == value : true)
|
659
|
+
# This happens when the GraphQL schema doesn't match the implementation. Help the dev debug.
|
660
|
+
raise ListResultFailedError.new(value: value, field: field, path: current_path)
|
661
|
+
else
|
662
|
+
# This was some other NoMethodError -- let it bubble to reveal the real error.
|
663
|
+
raise
|
664
|
+
end
|
665
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
666
|
+
ex_err
|
667
|
+
rescue StandardError => err
|
668
|
+
begin
|
669
|
+
query.handle_or_reraise(err)
|
670
|
+
rescue GraphQL::ExecutionError => ex_err
|
671
|
+
ex_err
|
672
|
+
end
|
663
673
|
end
|
664
|
-
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
665
|
-
ex_err
|
666
674
|
rescue StandardError => err
|
667
675
|
begin
|
668
676
|
query.handle_or_reraise(err)
|
@@ -53,7 +53,9 @@ module GraphQL
|
|
53
53
|
results = []
|
54
54
|
queries.each_with_index do |query, idx|
|
55
55
|
if query.subscription? && !query.subscription_update?
|
56
|
-
query.context.namespace(:subscriptions)
|
56
|
+
subs_namespace = query.context.namespace(:subscriptions)
|
57
|
+
subs_namespace[:events] = []
|
58
|
+
subs_namespace[:subscriptions] = {}
|
57
59
|
end
|
58
60
|
multiplex.dataloader.append_job {
|
59
61
|
operation = query.selected_operation
|
@@ -35,10 +35,6 @@ module GraphQL
|
|
35
35
|
@current_trace = @context[:trace] || schema.new_trace(multiplex: self)
|
36
36
|
@dataloader = @context[:dataloader] ||= @schema.dataloader_class.new
|
37
37
|
@tracers = schema.tracers + (context[:tracers] || [])
|
38
|
-
# Support `context: {backtrace: true}`
|
39
|
-
if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
|
40
|
-
@tracers << GraphQL::Backtrace::Tracer
|
41
|
-
end
|
42
38
|
@max_complexity = max_complexity
|
43
39
|
end
|
44
40
|
end
|
@@ -7,7 +7,7 @@ module GraphQL
|
|
7
7
|
"a __DirectiveLocation describes one such possible adjacencies."
|
8
8
|
|
9
9
|
GraphQL::Schema::Directive::LOCATIONS.each do |location|
|
10
|
-
value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location)
|
10
|
+
value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location, value_method: false)
|
11
11
|
end
|
12
12
|
introspection true
|
13
13
|
end
|
data/lib/graphql/query.rb
CHANGED
@@ -127,14 +127,6 @@ module GraphQL
|
|
127
127
|
context_tracers = (context ? context.fetch(:tracers, []) : [])
|
128
128
|
@tracers = schema.tracers + context_tracers
|
129
129
|
|
130
|
-
# Support `ctx[:backtrace] = true` for wrapping backtraces
|
131
|
-
if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
|
132
|
-
if schema.trace_class <= GraphQL::Tracing::CallLegacyTracers
|
133
|
-
context_tracers += [GraphQL::Backtrace::Tracer]
|
134
|
-
@tracers << GraphQL::Backtrace::Tracer
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
130
|
if !context_tracers.empty? && !(schema.trace_class <= GraphQL::Tracing::CallLegacyTracers)
|
139
131
|
raise ArgumentError, "context[:tracers] are not supported without `trace_with(GraphQL::Tracing::CallLegacyTracers)` in the schema configuration, please add it."
|
140
132
|
end
|
@@ -298,6 +298,7 @@ module GraphQL
|
|
298
298
|
description: enum_value_definition.description,
|
299
299
|
directives: builder.prepare_directives(enum_value_definition, type_resolver),
|
300
300
|
ast_node: enum_value_definition,
|
301
|
+
value_method: GraphQL::Schema::Enum.respond_to?(enum_value_definition.name.downcase) ? false : nil,
|
301
302
|
)
|
302
303
|
end
|
303
304
|
end
|
data/lib/graphql/schema/enum.rb
CHANGED
@@ -61,12 +61,17 @@ module GraphQL
|
|
61
61
|
# @option kwargs [String] :description, the GraphQL description for this value, present in documentation
|
62
62
|
# @option kwargs [String] :comment, the GraphQL comment for this value, present in documentation
|
63
63
|
# @option kwargs [::Object] :value the translated Ruby value for this object (defaults to `graphql_name`)
|
64
|
+
# @option kwargs [::Object] :value_method, the method name to fetch `graphql_name` (defaults to `graphql_name.downcase`)
|
64
65
|
# @option kwargs [String] :deprecation_reason if this object is deprecated, include a message here
|
66
|
+
# @param value_method [Symbol, false] A method to generate for this value, or `false` to skip generation
|
65
67
|
# @return [void]
|
66
68
|
# @see {Schema::EnumValue} which handles these inputs by default
|
67
|
-
def value(*args, **kwargs, &block)
|
69
|
+
def value(*args, value_method: nil, **kwargs, &block)
|
68
70
|
kwargs[:owner] = self
|
69
71
|
value = enum_value_class.new(*args, **kwargs, &block)
|
72
|
+
|
73
|
+
generate_value_method(value, value_method)
|
74
|
+
|
70
75
|
key = value.graphql_name
|
71
76
|
prev_value = own_values[key]
|
72
77
|
case prev_value
|
@@ -223,6 +228,21 @@ module GraphQL
|
|
223
228
|
def own_values
|
224
229
|
@own_values ||= {}
|
225
230
|
end
|
231
|
+
|
232
|
+
def generate_value_method(value, configured_value_method)
|
233
|
+
return if configured_value_method == false
|
234
|
+
|
235
|
+
value_method_name = configured_value_method || value.graphql_name.downcase
|
236
|
+
|
237
|
+
if respond_to?(value_method_name.to_sym)
|
238
|
+
warn "Failed to define value method for :#{value_method_name}, because " \
|
239
|
+
"#{value.owner.name || value.owner.graphql_name} already responds to that method. Use `value_method:` to override the method name " \
|
240
|
+
"or `value_method: false` to disable Enum value method generation."
|
241
|
+
return
|
242
|
+
end
|
243
|
+
|
244
|
+
instance_eval("def #{value_method_name}; #{value.graphql_name.inspect}; end;")
|
245
|
+
end
|
226
246
|
end
|
227
247
|
|
228
248
|
enum_value_class(GraphQL::Schema::EnumValue)
|
@@ -22,6 +22,7 @@ module GraphQL
|
|
22
22
|
include Schema::Member::GraphQLTypeNames
|
23
23
|
# Really we only need description & comment from here, but:
|
24
24
|
extend Schema::Member::BaseDSLMethods
|
25
|
+
extend Member::BaseDSLMethods::ConfigurationExtension
|
25
26
|
extend GraphQL::Schema::Member::HasArguments
|
26
27
|
extend GraphQL::Schema::Member::HasValidators
|
27
28
|
include Schema::Member::HasPath
|
@@ -19,13 +19,22 @@ module GraphQL
|
|
19
19
|
# propagate null.
|
20
20
|
null false
|
21
21
|
|
22
|
+
# @api private
|
22
23
|
def initialize(object:, context:, field:)
|
23
24
|
super
|
24
25
|
# Figure out whether this is an update or an initial subscription
|
25
26
|
@mode = context.query.subscription_update? ? :update : :subscribe
|
27
|
+
@subscription_written = false
|
28
|
+
@original_arguments = nil
|
29
|
+
if (subs_ns = context.namespace(:subscriptions)) &&
|
30
|
+
(sub_insts = subs_ns[:subscriptions])
|
31
|
+
sub_insts[context.current_path] = self
|
32
|
+
end
|
26
33
|
end
|
27
34
|
|
35
|
+
# @api private
|
28
36
|
def resolve_with_support(**args)
|
37
|
+
@original_arguments = args # before `loads:` have been run
|
29
38
|
result = nil
|
30
39
|
unsubscribed = true
|
31
40
|
unsubscribed_result = catch :graphql_subscription_unsubscribed do
|
@@ -46,7 +55,9 @@ module GraphQL
|
|
46
55
|
end
|
47
56
|
end
|
48
57
|
|
49
|
-
# Implement the {Resolve} API
|
58
|
+
# Implement the {Resolve} API.
|
59
|
+
# You can implement this if you want code to run for _both_ the initial subscription
|
60
|
+
# and for later updates. Or, implement {#subscribe} and {#update}
|
50
61
|
def resolve(**args)
|
51
62
|
# Dispatch based on `@mode`, which will raise a `NoMethodError` if we ever
|
52
63
|
# have an unexpected `@mode`
|
@@ -54,6 +65,7 @@ module GraphQL
|
|
54
65
|
end
|
55
66
|
|
56
67
|
# Wrap the user-defined `#subscribe` hook
|
68
|
+
# @api private
|
57
69
|
def resolve_subscribe(**args)
|
58
70
|
ret_val = !args.empty? ? subscribe(**args) : subscribe
|
59
71
|
if ret_val == :no_response
|
@@ -71,6 +83,7 @@ module GraphQL
|
|
71
83
|
end
|
72
84
|
|
73
85
|
# Wrap the user-provided `#update` hook
|
86
|
+
# @api private
|
74
87
|
def resolve_update(**args)
|
75
88
|
ret_val = !args.empty? ? update(**args) : update
|
76
89
|
if ret_val == NO_UPDATE
|
@@ -106,14 +119,13 @@ module GraphQL
|
|
106
119
|
throw :graphql_subscription_unsubscribed, update_value
|
107
120
|
end
|
108
121
|
|
109
|
-
READING_SCOPE = ::Object.new
|
110
122
|
# Call this method to provide a new subscription_scope; OR
|
111
123
|
# call it without an argument to get the subscription_scope
|
112
124
|
# @param new_scope [Symbol]
|
113
125
|
# @param optional [Boolean] If true, then don't require `scope:` to be provided to updates to this subscription.
|
114
126
|
# @return [Symbol]
|
115
|
-
def self.subscription_scope(new_scope =
|
116
|
-
if new_scope !=
|
127
|
+
def self.subscription_scope(new_scope = NOT_CONFIGURED, optional: false)
|
128
|
+
if new_scope != NOT_CONFIGURED
|
117
129
|
@subscription_scope = new_scope
|
118
130
|
@subscription_scope_optional = optional
|
119
131
|
elsif defined?(@subscription_scope)
|
@@ -150,6 +162,40 @@ module GraphQL
|
|
150
162
|
def self.topic_for(arguments:, field:, scope:)
|
151
163
|
Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments])
|
152
164
|
end
|
165
|
+
|
166
|
+
# Calls through to `schema.subscriptions` to register this subscription with the backend.
|
167
|
+
# This is automatically called by GraphQL-Ruby after a query finishes successfully,
|
168
|
+
# but if you need to commit the subscription during `#subscribe`, you can call it there.
|
169
|
+
# (This method also sets a flag showing that this subscription was already written.)
|
170
|
+
#
|
171
|
+
# If you call this method yourself, you may also need to {#unsubscribe}
|
172
|
+
# or call `subscriptions.delete_subscription` to clean up the database if the query crashes with an error
|
173
|
+
# later in execution.
|
174
|
+
# @return [void]
|
175
|
+
def write_subscription
|
176
|
+
if subscription_written?
|
177
|
+
raise GraphQL::Error, "`write_subscription` was called but `#{self.class}#subscription_written?` is already true. Remove a call to `write subscription`."
|
178
|
+
else
|
179
|
+
@subscription_written = true
|
180
|
+
context.schema.subscriptions.write_subscription(context.query, [event])
|
181
|
+
end
|
182
|
+
nil
|
183
|
+
end
|
184
|
+
|
185
|
+
# @return [Boolean] `true` if {#write_subscription} was called already
|
186
|
+
def subscription_written?
|
187
|
+
@subscription_written
|
188
|
+
end
|
189
|
+
|
190
|
+
# @return [Subscriptions::Event] This object is used as a representation of this subscription for the backend
|
191
|
+
def event
|
192
|
+
@event ||= Subscriptions::Event.new(
|
193
|
+
name: field.name,
|
194
|
+
arguments: @original_arguments,
|
195
|
+
context: context,
|
196
|
+
field: field,
|
197
|
+
)
|
198
|
+
end
|
153
199
|
end
|
154
200
|
end
|
155
201
|
end
|
@@ -51,19 +51,36 @@ module GraphQL
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def validate(_object, context, value)
|
54
|
-
|
54
|
+
fully_matched_conditions = 0
|
55
|
+
partially_matched_conditions = 0
|
55
56
|
|
56
57
|
if !value.nil?
|
57
58
|
@one_of.each do |one_of_condition|
|
58
59
|
case one_of_condition
|
59
60
|
when Symbol
|
60
61
|
if value.key?(one_of_condition)
|
61
|
-
|
62
|
+
fully_matched_conditions += 1
|
62
63
|
end
|
63
64
|
when Array
|
64
|
-
|
65
|
-
|
66
|
-
|
65
|
+
any_match = false
|
66
|
+
full_match = true
|
67
|
+
|
68
|
+
one_of_condition.each do |k|
|
69
|
+
if value.key?(k)
|
70
|
+
any_match = true
|
71
|
+
else
|
72
|
+
full_match = false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
partial_match = !full_match && any_match
|
77
|
+
|
78
|
+
if full_match
|
79
|
+
fully_matched_conditions += 1
|
80
|
+
end
|
81
|
+
|
82
|
+
if partial_match
|
83
|
+
partially_matched_conditions += 1
|
67
84
|
end
|
68
85
|
else
|
69
86
|
raise ArgumentError, "Unknown one_of condition: #{one_of_condition.inspect}"
|
@@ -71,7 +88,7 @@ module GraphQL
|
|
71
88
|
end
|
72
89
|
end
|
73
90
|
|
74
|
-
if
|
91
|
+
if fully_matched_conditions == 1 && partially_matched_conditions == 0
|
75
92
|
nil # OK
|
76
93
|
else
|
77
94
|
@message || build_message(context)
|