graphql 2.4.5 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/analyzer.rb +2 -1
- data/lib/graphql/analysis/visitor.rb +37 -40
- data/lib/graphql/analysis.rb +12 -9
- data/lib/graphql/autoload.rb +1 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/current.rb +5 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/subscriptions.rb +96 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +158 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +64 -0
- data/lib/graphql/dataloader/active_record_source.rb +26 -0
- data/lib/graphql/dataloader/async_dataloader.rb +17 -5
- data/lib/graphql/dataloader/null_dataloader.rb +1 -1
- data/lib/graphql/dataloader/source.rb +2 -2
- data/lib/graphql/dataloader.rb +37 -5
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +11 -4
- data/lib/graphql/execution/interpreter/runtime.rb +71 -34
- data/lib/graphql/execution/interpreter.rb +12 -3
- data/lib/graphql/execution/multiplex.rb +1 -5
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +5 -15
- data/lib/graphql/language/lexer.rb +7 -3
- data/lib/graphql/language/nodes.rb +3 -0
- data/lib/graphql/language/parser.rb +15 -8
- data/lib/graphql/language/static_visitor.rb +37 -33
- data/lib/graphql/language/visitor.rb +59 -55
- data/lib/graphql/query.rb +7 -13
- data/lib/graphql/railtie.rb +1 -1
- data/lib/graphql/schema/argument.rb +7 -8
- data/lib/graphql/schema/build_from_definition.rb +99 -53
- data/lib/graphql/schema/directive.rb +1 -1
- data/lib/graphql/schema/enum.rb +36 -1
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/field.rb +2 -2
- data/lib/graphql/schema/input_object.rb +16 -16
- data/lib/graphql/schema/interface.rb +2 -1
- data/lib/graphql/schema/member/has_arguments.rb +13 -5
- data/lib/graphql/schema/member/has_dataloader.rb +60 -0
- data/lib/graphql/schema/member/has_directives.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +1 -1
- data/lib/graphql/schema/member/has_interfaces.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +1 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/object.rb +17 -8
- data/lib/graphql/schema/resolver.rb +6 -5
- data/lib/graphql/schema/subscription.rb +50 -4
- data/lib/graphql/schema/validator/required_validator.rb +23 -6
- data/lib/graphql/schema/visibility/migration.rb +1 -0
- data/lib/graphql/schema/visibility/profile.rb +11 -5
- data/lib/graphql/schema/visibility.rb +14 -9
- data/lib/graphql/schema/warden.rb +14 -1
- data/lib/graphql/schema.rb +63 -35
- data/lib/graphql/static_validation/all_rules.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/validator.rb +6 -1
- 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 -1
- data/lib/graphql/testing/helpers.rb +5 -2
- data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +9 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
- data/lib/graphql/tracing/appsignal_trace.rb +32 -55
- 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 +46 -158
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +93 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/monitor_trace.rb +285 -0
- data/lib/graphql/tracing/new_relic_trace.rb +47 -54
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +182 -34
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +734 -0
- data/lib/graphql/tracing/platform_trace.rb +5 -0
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
- data/lib/graphql/tracing/prometheus_trace.rb +72 -68
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -55
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +63 -94
- data/lib/graphql/tracing/statsd_trace.rb +33 -41
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +111 -1
- data/lib/graphql/tracing.rb +31 -30
- data/lib/graphql/types/relay/connection_behaviors.rb +1 -1
- data/lib/graphql/types/relay/edge_behaviors.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +4 -29
- metadata +144 -11
- 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
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
|
@@ -22,39 +22,6 @@ module GraphQL
|
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
# We don't use `alias` here because it breaks `super`
|
|
26
|
-
def self.make_visit_methods(ast_node_class)
|
|
27
|
-
node_method = ast_node_class.visit_method
|
|
28
|
-
children_of_type = ast_node_class.children_of_type
|
|
29
|
-
child_visit_method = :"#{node_method}_children"
|
|
30
|
-
|
|
31
|
-
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
|
32
|
-
# The default implementation for visiting an AST node.
|
|
33
|
-
# It doesn't _do_ anything, but it continues to visiting the node's children.
|
|
34
|
-
# To customize this hook, override one of its make_visit_methods (or the base method?)
|
|
35
|
-
# in your subclasses.
|
|
36
|
-
#
|
|
37
|
-
# @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
|
|
38
|
-
# @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
|
|
39
|
-
# @return [void]
|
|
40
|
-
def #{node_method}(node, parent)
|
|
41
|
-
#{
|
|
42
|
-
if method_defined?(child_visit_method)
|
|
43
|
-
"#{child_visit_method}(node)"
|
|
44
|
-
elsif children_of_type
|
|
45
|
-
children_of_type.map do |child_accessor, child_class|
|
|
46
|
-
"node.#{child_accessor}.each do |child_node|
|
|
47
|
-
#{child_class.visit_method}(child_node, node)
|
|
48
|
-
end"
|
|
49
|
-
end.join("\n")
|
|
50
|
-
else
|
|
51
|
-
""
|
|
52
|
-
end
|
|
53
|
-
}
|
|
54
|
-
end
|
|
55
|
-
RUBY
|
|
56
|
-
end
|
|
57
|
-
|
|
58
25
|
def on_document_children(document_node)
|
|
59
26
|
document_node.children.each do |child_node|
|
|
60
27
|
visit_method = child_node.visit_method
|
|
@@ -123,6 +90,41 @@ module GraphQL
|
|
|
123
90
|
end
|
|
124
91
|
end
|
|
125
92
|
|
|
93
|
+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
|
|
94
|
+
|
|
95
|
+
# We don't use `alias` here because it breaks `super`
|
|
96
|
+
def self.make_visit_methods(ast_node_class)
|
|
97
|
+
node_method = ast_node_class.visit_method
|
|
98
|
+
children_of_type = ast_node_class.children_of_type
|
|
99
|
+
child_visit_method = :"#{node_method}_children"
|
|
100
|
+
|
|
101
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
|
102
|
+
# The default implementation for visiting an AST node.
|
|
103
|
+
# It doesn't _do_ anything, but it continues to visiting the node's children.
|
|
104
|
+
# To customize this hook, override one of its make_visit_methods (or the base method?)
|
|
105
|
+
# in your subclasses.
|
|
106
|
+
#
|
|
107
|
+
# @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
|
|
108
|
+
# @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
|
|
109
|
+
# @return [void]
|
|
110
|
+
def #{node_method}(node, parent)
|
|
111
|
+
#{
|
|
112
|
+
if method_defined?(child_visit_method)
|
|
113
|
+
"#{child_visit_method}(node)"
|
|
114
|
+
elsif children_of_type
|
|
115
|
+
children_of_type.map do |child_accessor, child_class|
|
|
116
|
+
"node.#{child_accessor}.each do |child_node|
|
|
117
|
+
#{child_class.visit_method}(child_node, node)
|
|
118
|
+
end"
|
|
119
|
+
end.join("\n")
|
|
120
|
+
else
|
|
121
|
+
""
|
|
122
|
+
end
|
|
123
|
+
}
|
|
124
|
+
end
|
|
125
|
+
RUBY
|
|
126
|
+
end
|
|
127
|
+
|
|
126
128
|
[
|
|
127
129
|
Language::Nodes::Argument,
|
|
128
130
|
Language::Nodes::Directive,
|
|
@@ -162,6 +164,8 @@ module GraphQL
|
|
|
162
164
|
].each do |ast_node_class|
|
|
163
165
|
make_visit_methods(ast_node_class)
|
|
164
166
|
end
|
|
167
|
+
|
|
168
|
+
# rubocop:disable Development/NoEvalCop
|
|
165
169
|
end
|
|
166
170
|
end
|
|
167
171
|
end
|
|
@@ -61,61 +61,6 @@ module GraphQL
|
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
# We don't use `alias` here because it breaks `super`
|
|
65
|
-
def self.make_visit_methods(ast_node_class)
|
|
66
|
-
node_method = ast_node_class.visit_method
|
|
67
|
-
children_of_type = ast_node_class.children_of_type
|
|
68
|
-
child_visit_method = :"#{node_method}_children"
|
|
69
|
-
|
|
70
|
-
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
|
71
|
-
# The default implementation for visiting an AST node.
|
|
72
|
-
# It doesn't _do_ anything, but it continues to visiting the node's children.
|
|
73
|
-
# To customize this hook, override one of its make_visit_methods (or the base method?)
|
|
74
|
-
# in your subclasses.
|
|
75
|
-
#
|
|
76
|
-
# @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
|
|
77
|
-
# @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
|
|
78
|
-
# @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
|
|
79
|
-
def #{node_method}(node, parent)
|
|
80
|
-
if node.equal?(DELETE_NODE)
|
|
81
|
-
# This might be passed to `super(DELETE_NODE, ...)`
|
|
82
|
-
# by a user hook, don't want to keep visiting in that case.
|
|
83
|
-
[node, parent]
|
|
84
|
-
else
|
|
85
|
-
new_node = node
|
|
86
|
-
#{
|
|
87
|
-
if method_defined?(child_visit_method)
|
|
88
|
-
"new_node = #{child_visit_method}(new_node)"
|
|
89
|
-
elsif children_of_type
|
|
90
|
-
children_of_type.map do |child_accessor, child_class|
|
|
91
|
-
"node.#{child_accessor}.each do |child_node|
|
|
92
|
-
new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
|
|
93
|
-
# Reassign `node` in case the child hook makes a modification
|
|
94
|
-
if new_child_and_node.is_a?(Array)
|
|
95
|
-
new_node = new_child_and_node[1]
|
|
96
|
-
end
|
|
97
|
-
end"
|
|
98
|
-
end.join("\n")
|
|
99
|
-
else
|
|
100
|
-
""
|
|
101
|
-
end
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if new_node.equal?(node)
|
|
105
|
-
[node, parent]
|
|
106
|
-
else
|
|
107
|
-
[new_node, parent]
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def #{node_method}_with_modifications(node, parent)
|
|
113
|
-
new_node_and_new_parent = #{node_method}(node, parent)
|
|
114
|
-
apply_modifications(node, parent, new_node_and_new_parent)
|
|
115
|
-
end
|
|
116
|
-
RUBY
|
|
117
|
-
end
|
|
118
|
-
|
|
119
64
|
def on_document_children(document_node)
|
|
120
65
|
new_node = document_node
|
|
121
66
|
document_node.children.each do |child_node|
|
|
@@ -216,6 +161,63 @@ module GraphQL
|
|
|
216
161
|
new_node
|
|
217
162
|
end
|
|
218
163
|
|
|
164
|
+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
|
|
165
|
+
|
|
166
|
+
# We don't use `alias` here because it breaks `super`
|
|
167
|
+
def self.make_visit_methods(ast_node_class)
|
|
168
|
+
node_method = ast_node_class.visit_method
|
|
169
|
+
children_of_type = ast_node_class.children_of_type
|
|
170
|
+
child_visit_method = :"#{node_method}_children"
|
|
171
|
+
|
|
172
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
|
173
|
+
# The default implementation for visiting an AST node.
|
|
174
|
+
# It doesn't _do_ anything, but it continues to visiting the node's children.
|
|
175
|
+
# To customize this hook, override one of its make_visit_methods (or the base method?)
|
|
176
|
+
# in your subclasses.
|
|
177
|
+
#
|
|
178
|
+
# @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
|
|
179
|
+
# @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
|
|
180
|
+
# @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
|
|
181
|
+
def #{node_method}(node, parent)
|
|
182
|
+
if node.equal?(DELETE_NODE)
|
|
183
|
+
# This might be passed to `super(DELETE_NODE, ...)`
|
|
184
|
+
# by a user hook, don't want to keep visiting in that case.
|
|
185
|
+
[node, parent]
|
|
186
|
+
else
|
|
187
|
+
new_node = node
|
|
188
|
+
#{
|
|
189
|
+
if method_defined?(child_visit_method)
|
|
190
|
+
"new_node = #{child_visit_method}(new_node)"
|
|
191
|
+
elsif children_of_type
|
|
192
|
+
children_of_type.map do |child_accessor, child_class|
|
|
193
|
+
"node.#{child_accessor}.each do |child_node|
|
|
194
|
+
new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
|
|
195
|
+
# Reassign `node` in case the child hook makes a modification
|
|
196
|
+
if new_child_and_node.is_a?(Array)
|
|
197
|
+
new_node = new_child_and_node[1]
|
|
198
|
+
end
|
|
199
|
+
end"
|
|
200
|
+
end.join("\n")
|
|
201
|
+
else
|
|
202
|
+
""
|
|
203
|
+
end
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if new_node.equal?(node)
|
|
207
|
+
[node, parent]
|
|
208
|
+
else
|
|
209
|
+
[new_node, parent]
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def #{node_method}_with_modifications(node, parent)
|
|
215
|
+
new_node_and_new_parent = #{node_method}(node, parent)
|
|
216
|
+
apply_modifications(node, parent, new_node_and_new_parent)
|
|
217
|
+
end
|
|
218
|
+
RUBY
|
|
219
|
+
end
|
|
220
|
+
|
|
219
221
|
[
|
|
220
222
|
Language::Nodes::Argument,
|
|
221
223
|
Language::Nodes::Directive,
|
|
@@ -256,6 +258,8 @@ module GraphQL
|
|
|
256
258
|
make_visit_methods(ast_node_class)
|
|
257
259
|
end
|
|
258
260
|
|
|
261
|
+
# rubocop:enable Development/NoEvalCop
|
|
262
|
+
|
|
259
263
|
private
|
|
260
264
|
|
|
261
265
|
def apply_modifications(node, parent, new_node_and_new_parent)
|
data/lib/graphql/query.rb
CHANGED
|
@@ -97,21 +97,23 @@ module GraphQL
|
|
|
97
97
|
# @param root_value [Object] the object used to resolve fields on the root type
|
|
98
98
|
# @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
|
|
99
99
|
# @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
|
|
100
|
-
# @param visibility_profile [Symbol]
|
|
101
|
-
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, visibility_profile: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil, use_visibility_profile: nil)
|
|
100
|
+
# @param visibility_profile [Symbol] Another way to assign `context[:visibility_profile]`
|
|
101
|
+
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, multiplex: nil, validate: true, static_validator: nil, visibility_profile: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil, use_visibility_profile: nil)
|
|
102
102
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
|
103
103
|
variables ||= {}
|
|
104
|
+
@multiplex = multiplex
|
|
104
105
|
@schema = schema
|
|
105
106
|
@context = schema.context_class.new(query: self, values: context)
|
|
107
|
+
if visibility_profile
|
|
108
|
+
@context[:visibility_profile] ||= visibility_profile
|
|
109
|
+
end
|
|
106
110
|
|
|
107
111
|
if use_visibility_profile.nil?
|
|
108
112
|
use_visibility_profile = warden ? false : schema.use_visibility_profile?
|
|
109
113
|
end
|
|
110
114
|
|
|
111
|
-
@visibility_profile = visibility_profile
|
|
112
|
-
|
|
113
115
|
if use_visibility_profile
|
|
114
|
-
@visibility_profile = @schema.visibility.profile_for(@context
|
|
116
|
+
@visibility_profile = @schema.visibility.profile_for(@context)
|
|
115
117
|
@warden = Schema::Warden::NullWarden.new(context: @context, schema: @schema)
|
|
116
118
|
else
|
|
117
119
|
@visibility_profile = nil
|
|
@@ -127,14 +129,6 @@ module GraphQL
|
|
|
127
129
|
context_tracers = (context ? context.fetch(:tracers, []) : [])
|
|
128
130
|
@tracers = schema.tracers + context_tracers
|
|
129
131
|
|
|
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
132
|
if !context_tracers.empty? && !(schema.trace_class <= GraphQL::Tracing::CallLegacyTracers)
|
|
139
133
|
raise ArgumentError, "context[:tracers] are not supported without `trace_with(GraphQL::Tracing::CallLegacyTracers)` in the schema configuration, please add it."
|
|
140
134
|
end
|
data/lib/graphql/railtie.rb
CHANGED
|
@@ -53,6 +53,7 @@ module GraphQL
|
|
|
53
53
|
def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, comment: nil, ast_node: nil, default_value: NOT_CONFIGURED, as: nil, from_resolver: false, camelize: true, prepare: nil, owner:, validates: nil, directives: nil, deprecation_reason: nil, replace_null_with_default: false, &definition_block)
|
|
54
54
|
arg_name ||= name
|
|
55
55
|
@name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
|
|
56
|
+
NameValidator.validate!(@name)
|
|
56
57
|
@type_expr = type_expr || type
|
|
57
58
|
@description = desc || description
|
|
58
59
|
@comment = comment
|
|
@@ -89,11 +90,8 @@ module GraphQL
|
|
|
89
90
|
end
|
|
90
91
|
|
|
91
92
|
if definition_block
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
else
|
|
95
|
-
instance_eval(&definition_block)
|
|
96
|
-
end
|
|
93
|
+
# `self` will still be self, it will also be the first argument to the block:
|
|
94
|
+
instance_exec(self, &definition_block)
|
|
97
95
|
end
|
|
98
96
|
end
|
|
99
97
|
|
|
@@ -219,7 +217,7 @@ module GraphQL
|
|
|
219
217
|
# @api private
|
|
220
218
|
def prepare_value(obj, value, context: nil)
|
|
221
219
|
if type.unwrap.kind.input_object?
|
|
222
|
-
value = recursively_prepare_input_object(value, type)
|
|
220
|
+
value = recursively_prepare_input_object(value, type, context)
|
|
223
221
|
end
|
|
224
222
|
|
|
225
223
|
Schema::Validator.validate!(validators, obj, context, value)
|
|
@@ -400,15 +398,16 @@ module GraphQL
|
|
|
400
398
|
|
|
401
399
|
private
|
|
402
400
|
|
|
403
|
-
def recursively_prepare_input_object(value, type)
|
|
401
|
+
def recursively_prepare_input_object(value, type, context)
|
|
404
402
|
if type.non_null?
|
|
405
403
|
type = type.of_type
|
|
406
404
|
end
|
|
407
405
|
|
|
408
406
|
if type.list? && !value.nil?
|
|
409
407
|
inner_type = type.of_type
|
|
410
|
-
value.map { |v| recursively_prepare_input_object(v, inner_type) }
|
|
408
|
+
value.map { |v| recursively_prepare_input_object(v, inner_type, context) }
|
|
411
409
|
elsif value.is_a?(GraphQL::Schema::InputObject)
|
|
410
|
+
value.validate_for(context)
|
|
412
411
|
value.prepare
|
|
413
412
|
else
|
|
414
413
|
value
|
|
@@ -20,8 +20,8 @@ module GraphQL
|
|
|
20
20
|
from_document(schema_superclass, parser.parse_file(definition_path), **kwargs)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def from_document(schema_superclass, document, default_resolve:, using: {}, relay: false)
|
|
24
|
-
Builder.build(schema_superclass, document, default_resolve: default_resolve || {}, relay: relay, using: using)
|
|
23
|
+
def from_document(schema_superclass, document, default_resolve:, using: {}, base_types: {}, relay: false)
|
|
24
|
+
Builder.build(schema_superclass, document, default_resolve: default_resolve || {}, relay: relay, using: using, base_types: base_types)
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -30,9 +30,18 @@ module GraphQL
|
|
|
30
30
|
include GraphQL::EmptyObjects
|
|
31
31
|
extend self
|
|
32
32
|
|
|
33
|
-
def build(schema_superclass, document, default_resolve:, using: {}, relay:)
|
|
33
|
+
def build(schema_superclass, document, default_resolve:, using: {}, base_types: {}, relay:)
|
|
34
34
|
raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
|
|
35
35
|
|
|
36
|
+
base_types = {
|
|
37
|
+
object: GraphQL::Schema::Object,
|
|
38
|
+
interface: GraphQL::Schema::Interface,
|
|
39
|
+
union: GraphQL::Schema::Union,
|
|
40
|
+
scalar: GraphQL::Schema::Scalar,
|
|
41
|
+
enum: GraphQL::Schema::Enum,
|
|
42
|
+
input_object: GraphQL::Schema::InputObject,
|
|
43
|
+
}.merge!(base_types)
|
|
44
|
+
|
|
36
45
|
if default_resolve.is_a?(Hash)
|
|
37
46
|
default_resolve = ResolveMap.new(default_resolve)
|
|
38
47
|
end
|
|
@@ -53,7 +62,7 @@ module GraphQL
|
|
|
53
62
|
types[type_name] ||= begin
|
|
54
63
|
defn = document.definitions.find { |d| d.respond_to?(:name) && d.name == type_name }
|
|
55
64
|
if defn
|
|
56
|
-
build_definition_from_node(defn, directive_type_resolver, default_resolve)
|
|
65
|
+
build_definition_from_node(defn, directive_type_resolver, default_resolve, base_types)
|
|
57
66
|
elsif (built_in_defn = GraphQL::Schema::BUILT_IN_TYPES[type_name])
|
|
58
67
|
built_in_defn
|
|
59
68
|
else
|
|
@@ -77,14 +86,20 @@ module GraphQL
|
|
|
77
86
|
case definition
|
|
78
87
|
when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
|
|
79
88
|
nil # already handled
|
|
80
|
-
when GraphQL::Language::Nodes::SchemaExtension
|
|
89
|
+
when GraphQL::Language::Nodes::SchemaExtension,
|
|
90
|
+
GraphQL::Language::Nodes::ScalarTypeExtension,
|
|
91
|
+
GraphQL::Language::Nodes::ObjectTypeExtension,
|
|
92
|
+
GraphQL::Language::Nodes::InterfaceTypeExtension,
|
|
93
|
+
GraphQL::Language::Nodes::UnionTypeExtension,
|
|
94
|
+
GraphQL::Language::Nodes::EnumTypeExtension,
|
|
95
|
+
GraphQL::Language::Nodes::InputObjectTypeExtension
|
|
81
96
|
schema_extensions ||= []
|
|
82
97
|
schema_extensions << definition
|
|
83
98
|
else
|
|
84
99
|
# It's possible that this was already loaded by the directives
|
|
85
100
|
prev_type = types[definition.name]
|
|
86
101
|
if prev_type.nil? || prev_type.is_a?(Schema::LateBoundType)
|
|
87
|
-
types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve)
|
|
102
|
+
types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve, base_types)
|
|
88
103
|
end
|
|
89
104
|
end
|
|
90
105
|
end
|
|
@@ -124,6 +139,34 @@ module GraphQL
|
|
|
124
139
|
|
|
125
140
|
raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
|
|
126
141
|
|
|
142
|
+
schema_extensions&.each do |ext|
|
|
143
|
+
next if ext.is_a?(GraphQL::Language::Nodes::SchemaExtension)
|
|
144
|
+
|
|
145
|
+
built_type = types[ext.name]
|
|
146
|
+
|
|
147
|
+
case ext
|
|
148
|
+
when GraphQL::Language::Nodes::ScalarTypeExtension
|
|
149
|
+
build_directives(built_type, ext, type_resolver)
|
|
150
|
+
when GraphQL::Language::Nodes::ObjectTypeExtension
|
|
151
|
+
build_directives(built_type, ext, type_resolver)
|
|
152
|
+
build_fields(built_type, ext.fields, type_resolver, default_resolve: true)
|
|
153
|
+
build_interfaces(built_type, ext.interfaces, type_resolver)
|
|
154
|
+
when GraphQL::Language::Nodes::InterfaceTypeExtension
|
|
155
|
+
build_directives(built_type, ext, type_resolver)
|
|
156
|
+
build_fields(built_type, ext.fields, type_resolver, default_resolve: nil)
|
|
157
|
+
build_interfaces(built_type, ext.interfaces, type_resolver)
|
|
158
|
+
when GraphQL::Language::Nodes::UnionTypeExtension
|
|
159
|
+
build_directives(built_type, ext, type_resolver)
|
|
160
|
+
built_type.possible_types(*ext.types.map { |type_name| type_resolver.call(type_name) })
|
|
161
|
+
when GraphQL::Language::Nodes::EnumTypeExtension
|
|
162
|
+
build_directives(built_type, ext, type_resolver)
|
|
163
|
+
build_values(built_type, ext.values, type_resolver)
|
|
164
|
+
when GraphQL::Language::Nodes::InputObjectTypeExtension
|
|
165
|
+
build_directives(built_type, ext, type_resolver)
|
|
166
|
+
build_arguments(built_type, ext.fields, type_resolver)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
127
170
|
builder = self
|
|
128
171
|
|
|
129
172
|
found_types = types.values
|
|
@@ -192,8 +235,8 @@ module GraphQL
|
|
|
192
235
|
end
|
|
193
236
|
end
|
|
194
237
|
|
|
195
|
-
|
|
196
|
-
|
|
238
|
+
schema_extensions&.each do |ext|
|
|
239
|
+
if ext.is_a?(GraphQL::Language::Nodes::SchemaExtension)
|
|
197
240
|
build_directives(schema_class, ext, type_resolver)
|
|
198
241
|
end
|
|
199
242
|
end
|
|
@@ -205,20 +248,20 @@ module GraphQL
|
|
|
205
248
|
raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
|
|
206
249
|
}
|
|
207
250
|
|
|
208
|
-
def build_definition_from_node(definition, type_resolver, default_resolve)
|
|
251
|
+
def build_definition_from_node(definition, type_resolver, default_resolve, base_types)
|
|
209
252
|
case definition
|
|
210
253
|
when GraphQL::Language::Nodes::EnumTypeDefinition
|
|
211
|
-
build_enum_type(definition, type_resolver)
|
|
254
|
+
build_enum_type(definition, type_resolver, base_types[:enum])
|
|
212
255
|
when GraphQL::Language::Nodes::ObjectTypeDefinition
|
|
213
|
-
build_object_type(definition, type_resolver)
|
|
256
|
+
build_object_type(definition, type_resolver, base_types[:object])
|
|
214
257
|
when GraphQL::Language::Nodes::InterfaceTypeDefinition
|
|
215
|
-
build_interface_type(definition, type_resolver)
|
|
258
|
+
build_interface_type(definition, type_resolver, base_types[:interface])
|
|
216
259
|
when GraphQL::Language::Nodes::UnionTypeDefinition
|
|
217
|
-
build_union_type(definition, type_resolver)
|
|
260
|
+
build_union_type(definition, type_resolver, base_types[:union])
|
|
218
261
|
when GraphQL::Language::Nodes::ScalarTypeDefinition
|
|
219
|
-
build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
|
|
262
|
+
build_scalar_type(definition, type_resolver, base_types[:scalar], default_resolve: default_resolve)
|
|
220
263
|
when GraphQL::Language::Nodes::InputObjectTypeDefinition
|
|
221
|
-
build_input_object_type(definition, type_resolver)
|
|
264
|
+
build_input_object_type(definition, type_resolver, base_types[:input_object])
|
|
222
265
|
end
|
|
223
266
|
end
|
|
224
267
|
|
|
@@ -284,22 +327,26 @@ module GraphQL
|
|
|
284
327
|
end
|
|
285
328
|
end
|
|
286
329
|
|
|
287
|
-
def build_enum_type(enum_type_definition, type_resolver)
|
|
330
|
+
def build_enum_type(enum_type_definition, type_resolver, base_type)
|
|
288
331
|
builder = self
|
|
289
|
-
Class.new(
|
|
332
|
+
Class.new(base_type) do
|
|
290
333
|
graphql_name(enum_type_definition.name)
|
|
291
334
|
builder.build_directives(self, enum_type_definition, type_resolver)
|
|
292
335
|
description(enum_type_definition.description)
|
|
293
336
|
ast_node(enum_type_definition)
|
|
294
|
-
enum_type_definition.values
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
337
|
+
builder.build_values(self, enum_type_definition.values, type_resolver)
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def build_values(type_class, enum_value_definitions, type_resolver)
|
|
342
|
+
enum_value_definitions.each do |enum_value_definition|
|
|
343
|
+
type_class.value(enum_value_definition.name,
|
|
344
|
+
value: enum_value_definition.name,
|
|
345
|
+
deprecation_reason: build_deprecation_reason(enum_value_definition.directives),
|
|
346
|
+
description: enum_value_definition.description,
|
|
347
|
+
directives: prepare_directives(enum_value_definition, type_resolver),
|
|
348
|
+
ast_node: enum_value_definition,
|
|
349
|
+
)
|
|
303
350
|
end
|
|
304
351
|
end
|
|
305
352
|
|
|
@@ -313,9 +360,9 @@ module GraphQL
|
|
|
313
360
|
reason.value
|
|
314
361
|
end
|
|
315
362
|
|
|
316
|
-
def build_scalar_type(scalar_type_definition, type_resolver, default_resolve:)
|
|
363
|
+
def build_scalar_type(scalar_type_definition, type_resolver, base_type, default_resolve:)
|
|
317
364
|
builder = self
|
|
318
|
-
Class.new(
|
|
365
|
+
Class.new(base_type) do
|
|
319
366
|
graphql_name(scalar_type_definition.name)
|
|
320
367
|
description(scalar_type_definition.description)
|
|
321
368
|
ast_node(scalar_type_definition)
|
|
@@ -336,9 +383,9 @@ module GraphQL
|
|
|
336
383
|
end
|
|
337
384
|
end
|
|
338
385
|
|
|
339
|
-
def build_union_type(union_type_definition, type_resolver)
|
|
386
|
+
def build_union_type(union_type_definition, type_resolver, base_type)
|
|
340
387
|
builder = self
|
|
341
|
-
Class.new(
|
|
388
|
+
Class.new(base_type) do
|
|
342
389
|
graphql_name(union_type_definition.name)
|
|
343
390
|
description(union_type_definition.description)
|
|
344
391
|
possible_types(*union_type_definition.types.map { |type_name| type_resolver.call(type_name) })
|
|
@@ -347,27 +394,28 @@ module GraphQL
|
|
|
347
394
|
end
|
|
348
395
|
end
|
|
349
396
|
|
|
350
|
-
def build_object_type(object_type_definition, type_resolver)
|
|
397
|
+
def build_object_type(object_type_definition, type_resolver, base_type)
|
|
351
398
|
builder = self
|
|
352
399
|
|
|
353
|
-
Class.new(
|
|
400
|
+
Class.new(base_type) do
|
|
354
401
|
graphql_name(object_type_definition.name)
|
|
355
402
|
description(object_type_definition.description)
|
|
356
403
|
ast_node(object_type_definition)
|
|
357
404
|
builder.build_directives(self, object_type_definition, type_resolver)
|
|
358
|
-
|
|
359
|
-
object_type_definition.interfaces.each do |interface_name|
|
|
360
|
-
interface_defn = type_resolver.call(interface_name)
|
|
361
|
-
implements(interface_defn)
|
|
362
|
-
end
|
|
363
|
-
|
|
405
|
+
builder.build_interfaces(self, object_type_definition.interfaces, type_resolver)
|
|
364
406
|
builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true)
|
|
365
407
|
end
|
|
366
408
|
end
|
|
367
409
|
|
|
368
|
-
def
|
|
410
|
+
def build_interfaces(type_class, interface_names, type_resolver)
|
|
411
|
+
interface_names.each do |interface_name|
|
|
412
|
+
type_class.implements(type_resolver.call(interface_name))
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
def build_input_object_type(input_object_type_definition, type_resolver, base_type)
|
|
369
417
|
builder = self
|
|
370
|
-
Class.new(
|
|
418
|
+
Class.new(base_type) do
|
|
371
419
|
graphql_name(input_object_type_definition.name)
|
|
372
420
|
description(input_object_type_definition.description)
|
|
373
421
|
ast_node(input_object_type_definition)
|
|
@@ -427,16 +475,13 @@ module GraphQL
|
|
|
427
475
|
end
|
|
428
476
|
end
|
|
429
477
|
|
|
430
|
-
def build_interface_type(interface_type_definition, type_resolver)
|
|
478
|
+
def build_interface_type(interface_type_definition, type_resolver, base_type)
|
|
431
479
|
builder = self
|
|
432
480
|
Module.new do
|
|
433
|
-
include
|
|
481
|
+
include base_type
|
|
434
482
|
graphql_name(interface_type_definition.name)
|
|
435
483
|
description(interface_type_definition.description)
|
|
436
|
-
interface_type_definition.interfaces
|
|
437
|
-
interface_defn = type_resolver.call(interface_name)
|
|
438
|
-
implements(interface_defn)
|
|
439
|
-
end
|
|
484
|
+
builder.build_interfaces(self, interface_type_definition.interfaces, type_resolver)
|
|
440
485
|
ast_node(interface_type_definition)
|
|
441
486
|
builder.build_directives(self, interface_type_definition, type_resolver)
|
|
442
487
|
|
|
@@ -467,17 +512,18 @@ module GraphQL
|
|
|
467
512
|
|
|
468
513
|
# Don't do this for interfaces
|
|
469
514
|
if default_resolve
|
|
470
|
-
owner
|
|
471
|
-
# frozen_string_literal: true
|
|
472
|
-
def #{resolve_method_name}(**args)
|
|
473
|
-
field_instance = self.class.get_field("#{field_definition.name}")
|
|
474
|
-
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
|
475
|
-
end
|
|
476
|
-
RUBY
|
|
515
|
+
define_field_resolve_method(owner, resolve_method_name, field_definition.name)
|
|
477
516
|
end
|
|
478
517
|
end
|
|
479
518
|
end
|
|
480
519
|
|
|
520
|
+
def define_field_resolve_method(owner, method_name, field_name)
|
|
521
|
+
owner.define_method(method_name) { |**args|
|
|
522
|
+
field_instance = self.class.get_field(field_name)
|
|
523
|
+
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
|
524
|
+
}
|
|
525
|
+
end
|
|
526
|
+
|
|
481
527
|
def build_resolve_type(lookup_hash, directives, missing_type_handler)
|
|
482
528
|
resolve_type_proc = nil
|
|
483
529
|
resolve_type_proc = ->(ast_node) {
|