graphql 2.4.3 → 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 +38 -41
- data/lib/graphql/analysis.rb +15 -12
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/current.rb +6 -1
- 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 +21 -9
- data/lib/graphql/dataloader/null_dataloader.rb +1 -1
- data/lib/graphql/dataloader/source.rb +3 -3
- data/lib/graphql/dataloader.rb +43 -14
- data/lib/graphql/execution/interpreter/resolve.rb +3 -3
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +11 -4
- data/lib/graphql/execution/interpreter/runtime.rb +78 -41
- data/lib/graphql/execution/interpreter.rb +16 -7
- 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/cache.rb +13 -0
- data/lib/graphql/language/document_from_schema_definition.rb +8 -7
- data/lib/graphql/language/lexer.rb +11 -4
- data/lib/graphql/language/nodes.rb +3 -0
- data/lib/graphql/language/parser.rb +15 -8
- data/lib/graphql/language/printer.rb +8 -8
- data/lib/graphql/language/static_visitor.rb +37 -33
- data/lib/graphql/language/visitor.rb +59 -55
- data/lib/graphql/pagination/connection.rb +1 -1
- data/lib/graphql/query/context/scoped_context.rb +1 -1
- data/lib/graphql/query/context.rb +6 -5
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query.rb +19 -23
- data/lib/graphql/railtie.rb +7 -0
- data/lib/graphql/schema/addition.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/flagged.rb +1 -1
- data/lib/graphql/schema/directive.rb +2 -2
- data/lib/graphql/schema/enum.rb +36 -1
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +12 -12
- data/lib/graphql/schema/field_extension.rb +1 -1
- data/lib/graphql/schema/has_single_input_argument.rb +3 -1
- data/lib/graphql/schema/input_object.rb +76 -39
- data/lib/graphql/schema/interface.rb +3 -2
- data/lib/graphql/schema/loader.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +25 -17
- data/lib/graphql/schema/member/has_dataloader.rb +60 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +19 -1
- data/lib/graphql/schema/member/has_interfaces.rb +5 -5
- data/lib/graphql/schema/member/has_validators.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 +25 -8
- data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
- data/lib/graphql/schema/resolver.rb +11 -10
- data/lib/graphql/schema/subscription.rb +52 -6
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/validator/required_validator.rb +23 -6
- data/lib/graphql/schema/validator.rb +1 -1
- data/lib/graphql/schema/visibility/migration.rb +1 -0
- data/lib/graphql/schema/visibility/profile.rb +69 -237
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +169 -28
- data/lib/graphql/schema/warden.rb +18 -5
- data/lib/graphql/schema.rb +93 -44
- data/lib/graphql/static_validation/all_rules.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +1 -0
- data/lib/graphql/static_validation/validator.rb +6 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -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/subscriptions.rb +1 -1
- data/lib/graphql/testing/helpers.rb +7 -4
- 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 +3 -3
- data/lib/graphql/types/relay/edge_behaviors.rb +2 -2
- data/lib/graphql/types.rb +18 -11
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +55 -47
- metadata +146 -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
|
@@ -5,12 +5,25 @@ require 'digest/sha2'
|
|
|
5
5
|
|
|
6
6
|
module GraphQL
|
|
7
7
|
module Language
|
|
8
|
+
# This cache is used by {GraphQL::Language::Parser.parse_file} when it's enabled.
|
|
9
|
+
#
|
|
10
|
+
# With Rails, parser caching may enabled by setting `config.graphql.parser_cache = true` in your Rails application.
|
|
11
|
+
#
|
|
12
|
+
# The cache may be manually built by assigning `GraphQL::Language::Parser.cache = GraphQL::Language::Cache.new("some_dir")`.
|
|
13
|
+
# This will create a directory (`tmp/cache/graphql` by default) that stores a cache of parsed files.
|
|
14
|
+
#
|
|
15
|
+
# Much like [bootsnap](https://github.com/Shopify/bootsnap), the parser cache needs to be cleaned up manually.
|
|
16
|
+
# You will need to clear the cache directory for each new deployment of your application.
|
|
17
|
+
# Also note that the parser cache will grow as your schema is loaded, so the cache directory must be writable.
|
|
18
|
+
#
|
|
19
|
+
# @see GraphQL::Railtie for simple Rails integration
|
|
8
20
|
class Cache
|
|
9
21
|
def initialize(path)
|
|
10
22
|
@path = path
|
|
11
23
|
end
|
|
12
24
|
|
|
13
25
|
DIGEST = Digest::SHA256.new << GraphQL::VERSION
|
|
26
|
+
|
|
14
27
|
def fetch(filename)
|
|
15
28
|
hash = DIGEST.dup << filename
|
|
16
29
|
begin
|
|
@@ -52,7 +52,7 @@ module GraphQL
|
|
|
52
52
|
|
|
53
53
|
def build_object_type_node(object_type)
|
|
54
54
|
ints = @types.interfaces(object_type)
|
|
55
|
-
if ints.
|
|
55
|
+
if !ints.empty?
|
|
56
56
|
ints.sort_by!(&:graphql_name)
|
|
57
57
|
ints.map! { |iface| build_type_name_node(iface) }
|
|
58
58
|
end
|
|
@@ -247,7 +247,7 @@ module GraphQL
|
|
|
247
247
|
end
|
|
248
248
|
|
|
249
249
|
def build_argument_nodes(arguments)
|
|
250
|
-
if arguments.
|
|
250
|
+
if !arguments.empty?
|
|
251
251
|
nodes = arguments.map { |arg| build_argument_node(arg) }
|
|
252
252
|
nodes.sort_by!(&:name)
|
|
253
253
|
nodes
|
|
@@ -271,7 +271,7 @@ module GraphQL
|
|
|
271
271
|
all_types = @types.all_types
|
|
272
272
|
type_nodes = build_type_definition_nodes(all_types)
|
|
273
273
|
|
|
274
|
-
if (ex_t = schema.extra_types).
|
|
274
|
+
if !(ex_t = schema.extra_types).empty?
|
|
275
275
|
dummy_query = Class.new(GraphQL::Schema::Object) do
|
|
276
276
|
graphql_name "DummyQuery"
|
|
277
277
|
(all_types + ex_t).each_with_index do |type, idx|
|
|
@@ -346,10 +346,11 @@ module GraphQL
|
|
|
346
346
|
end
|
|
347
347
|
|
|
348
348
|
def definition_directives(member, directives_method)
|
|
349
|
-
|
|
349
|
+
if !member.respond_to?(directives_method) || member.directives.empty?
|
|
350
350
|
EmptyObjects::EMPTY_ARRAY
|
|
351
351
|
else
|
|
352
|
-
member.public_send(directives_method).
|
|
352
|
+
visible_directives = member.public_send(directives_method).select { |dir| @types.directive_exists?(dir.graphql_name) }
|
|
353
|
+
visible_directives.map! do |dir|
|
|
353
354
|
args = []
|
|
354
355
|
dir.arguments.argument_values.each_value do |arg_value| # rubocop:disable Development/ContextIsPassedCop -- directive instance method
|
|
355
356
|
arg_defn = arg_value.definition
|
|
@@ -373,9 +374,9 @@ module GraphQL
|
|
|
373
374
|
arguments: args
|
|
374
375
|
)
|
|
375
376
|
end
|
|
376
|
-
end
|
|
377
377
|
|
|
378
|
-
|
|
378
|
+
visible_directives
|
|
379
|
+
end
|
|
379
380
|
end
|
|
380
381
|
|
|
381
382
|
attr_reader :schema, :always_include_schema,
|
|
@@ -13,17 +13,21 @@ module GraphQL
|
|
|
13
13
|
@pos = nil
|
|
14
14
|
@max_tokens = max_tokens || Float::INFINITY
|
|
15
15
|
@tokens_count = 0
|
|
16
|
+
@finished = false
|
|
16
17
|
end
|
|
17
18
|
|
|
18
|
-
def
|
|
19
|
-
@
|
|
19
|
+
def finished?
|
|
20
|
+
@finished
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
attr_reader :pos, :tokens_count
|
|
23
24
|
|
|
24
25
|
def advance
|
|
25
26
|
@scanner.skip(IGNORE_REGEXP)
|
|
26
|
-
|
|
27
|
+
if @scanner.eos?
|
|
28
|
+
@finished = true
|
|
29
|
+
return false
|
|
30
|
+
end
|
|
27
31
|
@tokens_count += 1
|
|
28
32
|
if @tokens_count > @max_tokens
|
|
29
33
|
raise_parse_error("This query is too large to execute.")
|
|
@@ -72,7 +76,10 @@ module GraphQL
|
|
|
72
76
|
# Check for a matched decimal:
|
|
73
77
|
@scanner[1] ? :FLOAT : :INT
|
|
74
78
|
else
|
|
75
|
-
|
|
79
|
+
# Attempt to find the part after the `-`
|
|
80
|
+
value = @scanner.scan(/-\s?[a-z0-9]*/i)
|
|
81
|
+
invalid_byte_for_number_error_message = "Expected type 'number', but it was malformed#{value.nil? ? "" : ": #{value.inspect}"}."
|
|
82
|
+
raise_parse_error(invalid_byte_for_number_error_message)
|
|
76
83
|
end
|
|
77
84
|
when ByteFor::ELLIPSIS
|
|
78
85
|
if @string.getbyte(@pos + 1) != 46 || @string.getbyte(@pos + 2) != 46
|
|
@@ -141,6 +141,8 @@ module GraphQL
|
|
|
141
141
|
end
|
|
142
142
|
|
|
143
143
|
class << self
|
|
144
|
+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
|
|
145
|
+
|
|
144
146
|
# Add a default `#visit_method` and `#children_method_name` using the class name
|
|
145
147
|
def inherited(child_class)
|
|
146
148
|
super
|
|
@@ -343,6 +345,7 @@ module GraphQL
|
|
|
343
345
|
RUBY
|
|
344
346
|
end
|
|
345
347
|
end
|
|
348
|
+
# rubocop:enable Development/NoEvalCop
|
|
346
349
|
end
|
|
347
350
|
end
|
|
348
351
|
|
|
@@ -110,7 +110,7 @@ module GraphQL
|
|
|
110
110
|
# Only ignored characters is not a valid document
|
|
111
111
|
raise GraphQL::ParseError.new("Unexpected end of document", nil, nil, @graphql_str)
|
|
112
112
|
end
|
|
113
|
-
while !@lexer.
|
|
113
|
+
while !@lexer.finished?
|
|
114
114
|
defns << definition
|
|
115
115
|
end
|
|
116
116
|
Document.new(pos: 0, definitions: defns, filename: @filename, source: self)
|
|
@@ -161,7 +161,7 @@ module GraphQL
|
|
|
161
161
|
expect_token(:VAR_SIGN)
|
|
162
162
|
var_name = parse_name
|
|
163
163
|
expect_token(:COLON)
|
|
164
|
-
var_type = self.type
|
|
164
|
+
var_type = self.type || raise_parse_error("Missing type definition for variable: $#{var_name}")
|
|
165
165
|
default_value = if at?(:EQUALS)
|
|
166
166
|
advance_token
|
|
167
167
|
value
|
|
@@ -488,26 +488,33 @@ module GraphQL
|
|
|
488
488
|
end
|
|
489
489
|
|
|
490
490
|
def type
|
|
491
|
-
|
|
491
|
+
parsed_type = case token_name
|
|
492
492
|
when :IDENTIFIER
|
|
493
493
|
parse_type_name
|
|
494
494
|
when :LBRACKET
|
|
495
495
|
list_type
|
|
496
|
+
else
|
|
497
|
+
nil
|
|
496
498
|
end
|
|
497
499
|
|
|
498
|
-
if at?(:BANG)
|
|
499
|
-
|
|
500
|
+
if at?(:BANG) && parsed_type
|
|
501
|
+
parsed_type = Nodes::NonNullType.new(pos: pos, of_type: parsed_type, source: self)
|
|
500
502
|
expect_token(:BANG)
|
|
501
503
|
end
|
|
502
|
-
|
|
504
|
+
parsed_type
|
|
503
505
|
end
|
|
504
506
|
|
|
505
507
|
def list_type
|
|
506
508
|
loc = pos
|
|
507
509
|
expect_token(:LBRACKET)
|
|
508
|
-
|
|
510
|
+
inner_type = self.type
|
|
511
|
+
parsed_list_type = if inner_type
|
|
512
|
+
Nodes::ListType.new(pos: loc, of_type: inner_type, source: self)
|
|
513
|
+
else
|
|
514
|
+
nil
|
|
515
|
+
end
|
|
509
516
|
expect_token(:RBRACKET)
|
|
510
|
-
|
|
517
|
+
parsed_list_type
|
|
511
518
|
end
|
|
512
519
|
|
|
513
520
|
def parse_operation_type
|
|
@@ -92,7 +92,7 @@ module GraphQL
|
|
|
92
92
|
print_string("@")
|
|
93
93
|
print_string(directive.name)
|
|
94
94
|
|
|
95
|
-
if directive.arguments.
|
|
95
|
+
if !directive.arguments.empty?
|
|
96
96
|
print_string("(")
|
|
97
97
|
directive.arguments.each_with_index do |a, i|
|
|
98
98
|
print_argument(a)
|
|
@@ -117,7 +117,7 @@ module GraphQL
|
|
|
117
117
|
print_string(": ")
|
|
118
118
|
end
|
|
119
119
|
print_string(field.name)
|
|
120
|
-
if field.arguments.
|
|
120
|
+
if !field.arguments.empty?
|
|
121
121
|
print_string("(")
|
|
122
122
|
field.arguments.each_with_index do |a, i|
|
|
123
123
|
print_argument(a)
|
|
@@ -182,7 +182,7 @@ module GraphQL
|
|
|
182
182
|
print_string(operation_definition.name)
|
|
183
183
|
end
|
|
184
184
|
|
|
185
|
-
if operation_definition.variables.
|
|
185
|
+
if !operation_definition.variables.empty?
|
|
186
186
|
print_string("(")
|
|
187
187
|
operation_definition.variables.each_with_index do |v, i|
|
|
188
188
|
print_variable_definition(v)
|
|
@@ -230,7 +230,7 @@ module GraphQL
|
|
|
230
230
|
|
|
231
231
|
extension ? print_string("extend schema") : print_string("schema")
|
|
232
232
|
|
|
233
|
-
if schema.directives.
|
|
233
|
+
if !schema.directives.empty?
|
|
234
234
|
schema.directives.each do |dir|
|
|
235
235
|
print_string("\n ")
|
|
236
236
|
print_node(dir)
|
|
@@ -332,7 +332,7 @@ module GraphQL
|
|
|
332
332
|
extension ? print_string("extend ") : print_description_and_comment(interface_type)
|
|
333
333
|
print_string("interface ")
|
|
334
334
|
print_string(interface_type.name)
|
|
335
|
-
print_implements(interface_type) if interface_type.interfaces.
|
|
335
|
+
print_implements(interface_type) if !interface_type.interfaces.empty?
|
|
336
336
|
print_directives(interface_type.directives)
|
|
337
337
|
print_field_definitions(interface_type.fields)
|
|
338
338
|
end
|
|
@@ -342,7 +342,7 @@ module GraphQL
|
|
|
342
342
|
print_string("union ")
|
|
343
343
|
print_string(union_type.name)
|
|
344
344
|
print_directives(union_type.directives)
|
|
345
|
-
if union_type.types.
|
|
345
|
+
if !union_type.types.empty?
|
|
346
346
|
print_string(" = ")
|
|
347
347
|
i = 0
|
|
348
348
|
union_type.types.each do |t|
|
|
@@ -360,7 +360,7 @@ module GraphQL
|
|
|
360
360
|
print_string("enum ")
|
|
361
361
|
print_string(enum_type.name)
|
|
362
362
|
print_directives(enum_type.directives)
|
|
363
|
-
if enum_type.values.
|
|
363
|
+
if !enum_type.values.empty?
|
|
364
364
|
print_string(" {\n")
|
|
365
365
|
enum_type.values.each.with_index do |value, i|
|
|
366
366
|
print_description(value, indent: " ", first_in_block: i == 0)
|
|
@@ -401,7 +401,7 @@ module GraphQL
|
|
|
401
401
|
print_string("directive @")
|
|
402
402
|
print_string(directive.name)
|
|
403
403
|
|
|
404
|
-
if directive.arguments.
|
|
404
|
+
if !directive.arguments.empty?
|
|
405
405
|
print_arguments(directive.arguments)
|
|
406
406
|
end
|
|
407
407
|
|
|
@@ -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)
|
|
@@ -223,7 +223,7 @@ module GraphQL
|
|
|
223
223
|
|
|
224
224
|
def detect_was_authorized_by_scope_items
|
|
225
225
|
if @context &&
|
|
226
|
-
(current_runtime_state =
|
|
226
|
+
(current_runtime_state = Fiber[:__graphql_runtime_info]) &&
|
|
227
227
|
(query_runtime_state = current_runtime_state[@context.query])
|
|
228
228
|
query_runtime_state.was_authorized_by_scope_items
|
|
229
229
|
else
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require "graphql/query/context/scoped_context"
|
|
3
2
|
|
|
4
3
|
module GraphQL
|
|
5
4
|
class Query
|
|
@@ -104,7 +103,7 @@ module GraphQL
|
|
|
104
103
|
if key == :current_path
|
|
105
104
|
current_path
|
|
106
105
|
else
|
|
107
|
-
(current_runtime_state =
|
|
106
|
+
(current_runtime_state = Fiber[:__graphql_runtime_info]) &&
|
|
108
107
|
(query_runtime_state = current_runtime_state[@query]) &&
|
|
109
108
|
(query_runtime_state.public_send(key))
|
|
110
109
|
end
|
|
@@ -144,7 +143,7 @@ module GraphQL
|
|
|
144
143
|
end
|
|
145
144
|
|
|
146
145
|
def current_path
|
|
147
|
-
current_runtime_state =
|
|
146
|
+
current_runtime_state = Fiber[:__graphql_runtime_info]
|
|
148
147
|
query_runtime_state = current_runtime_state && current_runtime_state[@query]
|
|
149
148
|
|
|
150
149
|
path = query_runtime_state &&
|
|
@@ -169,7 +168,7 @@ module GraphQL
|
|
|
169
168
|
|
|
170
169
|
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
|
171
170
|
if RUNTIME_METADATA_KEYS.include?(key)
|
|
172
|
-
(runtime =
|
|
171
|
+
(runtime = Fiber[:__graphql_runtime_info]) &&
|
|
173
172
|
(query_runtime_state = runtime[@query]) &&
|
|
174
173
|
(query_runtime_state.public_send(key))
|
|
175
174
|
elsif @scoped_context.key?(key)
|
|
@@ -187,7 +186,7 @@ module GraphQL
|
|
|
187
186
|
|
|
188
187
|
def dig(key, *other_keys)
|
|
189
188
|
if RUNTIME_METADATA_KEYS.include?(key)
|
|
190
|
-
(current_runtime_state =
|
|
189
|
+
(current_runtime_state = Fiber[:__graphql_runtime_info]) &&
|
|
191
190
|
(query_runtime_state = current_runtime_state[@query]) &&
|
|
192
191
|
(obj = query_runtime_state.public_send(key)) &&
|
|
193
192
|
if other_keys.empty?
|
|
@@ -289,3 +288,5 @@ module GraphQL
|
|
|
289
288
|
end
|
|
290
289
|
end
|
|
291
290
|
end
|
|
291
|
+
|
|
292
|
+
require "graphql/query/context/scoped_context"
|
data/lib/graphql/query.rb
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require "graphql/query/context"
|
|
3
|
-
require "graphql/query/fingerprint"
|
|
4
|
-
require "graphql/query/null_context"
|
|
5
|
-
require "graphql/query/result"
|
|
6
|
-
require "graphql/query/variables"
|
|
7
|
-
require "graphql/query/input_validation_result"
|
|
8
|
-
require "graphql/query/variable_validation_error"
|
|
9
|
-
require "graphql/query/validation_pipeline"
|
|
10
2
|
|
|
11
3
|
module GraphQL
|
|
12
4
|
# A combination of query string and {Schema} instance which can be reduced to a {#result}.
|
|
13
5
|
class Query
|
|
6
|
+
extend Autoload
|
|
14
7
|
include Tracing::Traceable
|
|
15
8
|
extend Forwardable
|
|
16
9
|
|
|
10
|
+
autoload :Context, "graphql/query/context"
|
|
11
|
+
autoload :Fingerprint, "graphql/query/fingerprint"
|
|
12
|
+
autoload :NullContext, "graphql/query/null_context"
|
|
13
|
+
autoload :Result, "graphql/query/result"
|
|
14
|
+
autoload :Variables, "graphql/query/variables"
|
|
15
|
+
autoload :InputValidationResult, "graphql/query/input_validation_result"
|
|
16
|
+
autoload :VariableValidationError, "graphql/query/variable_validation_error"
|
|
17
|
+
autoload :ValidationPipeline, "graphql/query/validation_pipeline"
|
|
18
|
+
|
|
17
19
|
class OperationNameMissingError < GraphQL::ExecutionError
|
|
18
20
|
def initialize(name)
|
|
19
21
|
msg = if name.nil?
|
|
@@ -95,21 +97,23 @@ module GraphQL
|
|
|
95
97
|
# @param root_value [Object] the object used to resolve fields on the root type
|
|
96
98
|
# @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
|
|
97
99
|
# @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
|
|
98
|
-
# @param visibility_profile [Symbol]
|
|
99
|
-
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)
|
|
100
102
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
|
101
103
|
variables ||= {}
|
|
104
|
+
@multiplex = multiplex
|
|
102
105
|
@schema = schema
|
|
103
106
|
@context = schema.context_class.new(query: self, values: context)
|
|
107
|
+
if visibility_profile
|
|
108
|
+
@context[:visibility_profile] ||= visibility_profile
|
|
109
|
+
end
|
|
104
110
|
|
|
105
111
|
if use_visibility_profile.nil?
|
|
106
112
|
use_visibility_profile = warden ? false : schema.use_visibility_profile?
|
|
107
113
|
end
|
|
108
114
|
|
|
109
|
-
@visibility_profile = visibility_profile
|
|
110
|
-
|
|
111
115
|
if use_visibility_profile
|
|
112
|
-
@visibility_profile = @schema.visibility.profile_for(@context
|
|
116
|
+
@visibility_profile = @schema.visibility.profile_for(@context)
|
|
113
117
|
@warden = Schema::Warden::NullWarden.new(context: @context, schema: @schema)
|
|
114
118
|
else
|
|
115
119
|
@visibility_profile = nil
|
|
@@ -125,15 +129,7 @@ module GraphQL
|
|
|
125
129
|
context_tracers = (context ? context.fetch(:tracers, []) : [])
|
|
126
130
|
@tracers = schema.tracers + context_tracers
|
|
127
131
|
|
|
128
|
-
|
|
129
|
-
if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
|
|
130
|
-
if schema.trace_class <= GraphQL::Tracing::CallLegacyTracers
|
|
131
|
-
context_tracers += [GraphQL::Backtrace::Tracer]
|
|
132
|
-
@tracers << GraphQL::Backtrace::Tracer
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
if context_tracers.any? && !(schema.trace_class <= GraphQL::Tracing::CallLegacyTracers)
|
|
132
|
+
if !context_tracers.empty? && !(schema.trace_class <= GraphQL::Tracing::CallLegacyTracers)
|
|
137
133
|
raise ArgumentError, "context[:tracers] are not supported without `trace_with(GraphQL::Tracing::CallLegacyTracers)` in the schema configuration, please add it."
|
|
138
134
|
end
|
|
139
135
|
|
|
@@ -479,7 +475,7 @@ module GraphQL
|
|
|
479
475
|
@mutation = false
|
|
480
476
|
@subscription = false
|
|
481
477
|
operation_name_error = nil
|
|
482
|
-
if
|
|
478
|
+
if !@operations.empty?
|
|
483
479
|
@selected_operation = find_operation(@operations, @operation_name)
|
|
484
480
|
if @selected_operation.nil?
|
|
485
481
|
operation_name_error = GraphQL::Query::OperationNameMissingError.new(@operation_name)
|
data/lib/graphql/railtie.rb
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module GraphQL
|
|
4
|
+
# Support {GraphQL::Parser::Cache} and {GraphQL.eager_load!}
|
|
5
|
+
#
|
|
6
|
+
# @example Enable the parser cache with default directory
|
|
7
|
+
#
|
|
8
|
+
# config.graphql.parser_cache = true
|
|
9
|
+
#
|
|
4
10
|
class Railtie < Rails::Railtie
|
|
5
11
|
config.graphql = ActiveSupport::OrderedOptions.new
|
|
6
12
|
config.graphql.parser_cache = false
|
|
13
|
+
config.eager_load_namespaces << GraphQL
|
|
7
14
|
|
|
8
15
|
initializer("graphql.cache") do |app|
|
|
9
16
|
if config.graphql.parser_cache
|