graphql 2.4.3 → 2.5.2
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 +34 -4
- data/lib/graphql/execution/interpreter/runtime.rb +94 -51
- 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 +3 -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 +27 -13
- 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 +77 -40
- 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_deprecation_reason.rb +15 -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 +12 -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 +95 -243
- 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 +283 -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 +62 -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
@@ -23,7 +23,7 @@ module GraphQL
|
|
23
23
|
# @return [Array<GraphQL::Query::Result>] One result per query
|
24
24
|
def run_all(schema, query_options, context: {}, max_complexity: schema.max_complexity)
|
25
25
|
queries = query_options.map do |opts|
|
26
|
-
case opts
|
26
|
+
query = case opts
|
27
27
|
when Hash
|
28
28
|
schema.query_class.new(schema, nil, **opts)
|
29
29
|
when GraphQL::Query
|
@@ -31,11 +31,15 @@ module GraphQL
|
|
31
31
|
else
|
32
32
|
raise "Expected Hash or GraphQL::Query, not #{opts.class} (#{opts.inspect})"
|
33
33
|
end
|
34
|
+
query
|
34
35
|
end
|
35
36
|
|
37
|
+
return GraphQL::EmptyObjects::EMPTY_ARRAY if queries.empty?
|
38
|
+
|
36
39
|
multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
|
40
|
+
trace = multiplex.current_trace
|
37
41
|
Fiber[:__graphql_current_multiplex] = multiplex
|
38
|
-
|
42
|
+
trace.execute_multiplex(multiplex: multiplex) do
|
39
43
|
schema = multiplex.schema
|
40
44
|
queries = multiplex.queries
|
41
45
|
lazies_at_depth = Hash.new { |h, k| h[k] = [] }
|
@@ -44,7 +48,10 @@ module GraphQL
|
|
44
48
|
multiplex_analyzers += [GraphQL::Analysis::MaxQueryComplexity]
|
45
49
|
end
|
46
50
|
|
51
|
+
trace.begin_analyze_multiplex(multiplex, multiplex_analyzers)
|
47
52
|
schema.analysis_engine.analyze_multiplex(multiplex, multiplex_analyzers)
|
53
|
+
trace.end_analyze_multiplex(multiplex, multiplex_analyzers)
|
54
|
+
|
48
55
|
begin
|
49
56
|
# Since this is basically the batching context,
|
50
57
|
# share it for a whole multiplex
|
@@ -53,11 +60,13 @@ module GraphQL
|
|
53
60
|
results = []
|
54
61
|
queries.each_with_index do |query, idx|
|
55
62
|
if query.subscription? && !query.subscription_update?
|
56
|
-
query.context.namespace(:subscriptions)
|
63
|
+
subs_namespace = query.context.namespace(:subscriptions)
|
64
|
+
subs_namespace[:events] = []
|
65
|
+
subs_namespace[:subscriptions] = {}
|
57
66
|
end
|
58
67
|
multiplex.dataloader.append_job {
|
59
68
|
operation = query.selected_operation
|
60
|
-
result = if operation.nil? || !query.valid? || query.context.errors.
|
69
|
+
result = if operation.nil? || !query.valid? || !query.context.errors.empty?
|
61
70
|
NO_OPERATION
|
62
71
|
else
|
63
72
|
begin
|
@@ -100,12 +109,12 @@ module GraphQL
|
|
100
109
|
# Then, find all errors and assign the result to the query object
|
101
110
|
results.each_with_index do |data_result, idx|
|
102
111
|
query = queries[idx]
|
103
|
-
if (events = query.context.namespace(:subscriptions)[:events]) && events.
|
112
|
+
if (events = query.context.namespace(:subscriptions)[:events]) && !events.empty?
|
104
113
|
schema.subscriptions.write_subscription(query, events)
|
105
114
|
end
|
106
115
|
# Assign the result so that it can be accessed in instrumentation
|
107
116
|
query.result_values = if data_result.equal?(NO_OPERATION)
|
108
|
-
if !query.valid? || query.context.errors.
|
117
|
+
if !query.valid? || !query.context.errors.empty?
|
109
118
|
# A bit weird, but `Query#static_errors` _includes_ `query.context.errors`
|
110
119
|
{ "errors" => query.static_errors.map(&:to_h) }
|
111
120
|
else
|
@@ -114,7 +123,7 @@ module GraphQL
|
|
114
123
|
else
|
115
124
|
result = {}
|
116
125
|
|
117
|
-
if query.context.errors.
|
126
|
+
if !query.context.errors.empty?
|
118
127
|
error_result = query.context.errors.map(&:to_h)
|
119
128
|
result["errors"] = error_result
|
120
129
|
end
|
@@ -32,14 +32,10 @@ module GraphQL
|
|
32
32
|
@queries = queries
|
33
33
|
@queries.each { |q| q.multiplex = self }
|
34
34
|
@context = context
|
35
|
-
@current_trace = @context[:trace] || schema.new_trace(multiplex: self)
|
36
35
|
@dataloader = @context[:dataloader] ||= @schema.dataloader_class.new
|
37
36
|
@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
37
|
@max_complexity = max_complexity
|
38
|
+
@current_trace = context[:trace] ||= schema.new_trace(multiplex: self)
|
43
39
|
end
|
44
40
|
end
|
45
41
|
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
|
@@ -2,33 +2,23 @@
|
|
2
2
|
module GraphQL
|
3
3
|
# Raised automatically when a field's resolve function returns `nil`
|
4
4
|
# for a non-null field.
|
5
|
-
class InvalidNullError < GraphQL::
|
5
|
+
class InvalidNullError < GraphQL::Error
|
6
6
|
# @return [GraphQL::BaseType] The owner of {#field}
|
7
7
|
attr_reader :parent_type
|
8
8
|
|
9
9
|
# @return [GraphQL::Field] The field which failed to return a value
|
10
10
|
attr_reader :field
|
11
11
|
|
12
|
-
# @return [
|
13
|
-
attr_reader :
|
12
|
+
# @return [GraphQL::Language::Nodes::Field] the field where the error occurred
|
13
|
+
attr_reader :ast_node
|
14
14
|
|
15
|
-
def initialize(parent_type, field,
|
15
|
+
def initialize(parent_type, field, ast_node)
|
16
16
|
@parent_type = parent_type
|
17
17
|
@field = field
|
18
|
-
@
|
18
|
+
@ast_node = ast_node
|
19
19
|
super("Cannot return null for non-nullable field #{@parent_type.graphql_name}.#{@field.graphql_name}")
|
20
20
|
end
|
21
21
|
|
22
|
-
# @return [Hash] An entry for the response's "errors" key
|
23
|
-
def to_h
|
24
|
-
{ "message" => message }
|
25
|
-
end
|
26
|
-
|
27
|
-
# @deprecated always false
|
28
|
-
def parent_error?
|
29
|
-
false
|
30
|
-
end
|
31
|
-
|
32
22
|
class << self
|
33
23
|
attr_accessor :parent_class
|
34
24
|
|
@@ -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
|