graphql 2.0.17.2 → 2.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/ast.rb +2 -2
- data/lib/graphql/backtrace/trace.rb +96 -0
- data/lib/graphql/backtrace/tracer.rb +1 -1
- data/lib/graphql/backtrace.rb +6 -1
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -3
- data/lib/graphql/execution/interpreter/resolve.rb +19 -0
- data/lib/graphql/execution/interpreter/runtime.rb +254 -211
- data/lib/graphql/execution/interpreter.rb +9 -14
- data/lib/graphql/execution/lazy.rb +2 -4
- data/lib/graphql/execution/multiplex.rb +2 -1
- data/lib/graphql/filter.rb +7 -2
- data/lib/graphql/language/document_from_schema_definition.rb +25 -9
- data/lib/graphql/language/lexer.rb +216 -1505
- data/lib/graphql/language/nodes.rb +27 -9
- data/lib/graphql/language/parser.rb +509 -491
- data/lib/graphql/language/parser.y +43 -38
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/connection.rb +5 -5
- data/lib/graphql/query/context.rb +62 -31
- data/lib/graphql/query/null_context.rb +1 -1
- data/lib/graphql/query.rb +22 -5
- data/lib/graphql/schema/argument.rb +7 -9
- data/lib/graphql/schema/build_from_definition.rb +15 -3
- data/lib/graphql/schema/enum_value.rb +2 -5
- data/lib/graphql/schema/field.rb +44 -31
- data/lib/graphql/schema/field_extension.rb +1 -4
- data/lib/graphql/schema/find_inherited_value.rb +2 -7
- data/lib/graphql/schema/member/base_dsl_methods.rb +13 -11
- data/lib/graphql/schema/member/has_arguments.rb +1 -1
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +15 -10
- data/lib/graphql/schema/member/has_fields.rb +87 -37
- data/lib/graphql/schema/member/has_validators.rb +2 -2
- data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema/object.rb +2 -4
- data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
- data/lib/graphql/schema/resolver.rb +4 -4
- data/lib/graphql/schema/timeout.rb +24 -28
- data/lib/graphql/schema/validator.rb +1 -1
- data/lib/graphql/schema/warden.rb +11 -2
- data/lib/graphql/schema.rb +72 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
- data/lib/graphql/static_validation/validator.rb +1 -1
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +231 -0
- data/lib/graphql/tracing/appsignal_trace.rb +77 -0
- data/lib/graphql/tracing/data_dog_trace.rb +148 -0
- data/lib/graphql/tracing/legacy_trace.rb +65 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +42 -0
- data/lib/graphql/tracing/platform_trace.rb +109 -0
- data/lib/graphql/tracing/platform_tracing.rb +15 -3
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +1 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/trace.rb +75 -0
- data/lib/graphql/tracing.rb +16 -39
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/relay/base_connection.rb +1 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +24 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +16 -2
- data/lib/graphql/types/relay/node_behaviors.rb +7 -1
- data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
- data/lib/graphql/types/relay.rb +0 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +16 -9
- metadata +33 -8
- data/lib/graphql/language/lexer.rl +0 -280
- data/lib/graphql/types/relay/default_relay.rb +0 -27
@@ -162,7 +162,7 @@ rule
|
|
162
162
|
| schema_keyword
|
163
163
|
|
164
164
|
enum_value_definition:
|
165
|
-
description_opt enum_name directives_list_opt { result = make_node(:EnumValueDefinition, name: val[1], directives: val[2], description: val[0] || get_description(val[1]), definition_line: val[1]
|
165
|
+
description_opt enum_name directives_list_opt { result = make_node(:EnumValueDefinition, name: val[1], directives: val[2], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1]) }
|
166
166
|
|
167
167
|
enum_value_definitions:
|
168
168
|
enum_value_definition { result = [val[0]] }
|
@@ -180,9 +180,9 @@ rule
|
|
180
180
|
name COLON input_value { result = make_node(:Argument, name: val[0], value: val[2], position_source: val[0])}
|
181
181
|
|
182
182
|
literal_value:
|
183
|
-
FLOAT { result = val[0].to_f }
|
184
|
-
| INT { result = val[0].to_i }
|
185
|
-
| STRING { result = val[0]
|
183
|
+
FLOAT { result = val[0][3].to_f }
|
184
|
+
| INT { result = val[0][3].to_i }
|
185
|
+
| STRING { result = val[0][3] }
|
186
186
|
| TRUE { result = true }
|
187
187
|
| FALSE { result = false }
|
188
188
|
| null_value
|
@@ -284,14 +284,18 @@ rule
|
|
284
284
|
| directive_definition
|
285
285
|
|
286
286
|
schema_definition:
|
287
|
-
SCHEMA directives_list_opt
|
287
|
+
SCHEMA directives_list_opt operation_type_definition_list_opt { result = make_node(:SchemaDefinition, position_source: val[0], definition_line: val[0][1], directives: val[1], **val[2]) }
|
288
|
+
|
289
|
+
operation_type_definition_list_opt:
|
290
|
+
/* none */ { result = {} }
|
291
|
+
| LCURLY operation_type_definition_list RCURLY { result = val[1] }
|
288
292
|
|
289
293
|
operation_type_definition_list:
|
290
294
|
operation_type_definition
|
291
295
|
| operation_type_definition_list operation_type_definition { result = val[0].merge(val[1]) }
|
292
296
|
|
293
297
|
operation_type_definition:
|
294
|
-
operation_type COLON name { result = { val[0].
|
298
|
+
operation_type COLON name { result = { val[0][3].to_sym => val[2] } }
|
295
299
|
|
296
300
|
type_definition:
|
297
301
|
scalar_type_definition
|
@@ -351,12 +355,12 @@ rule
|
|
351
355
|
|
352
356
|
scalar_type_definition:
|
353
357
|
description_opt SCALAR name directives_list_opt {
|
354
|
-
result = make_node(:ScalarTypeDefinition, name: val[2], directives: val[3], description: val[0] || get_description(val[1]), definition_line: val[1]
|
358
|
+
result = make_node(:ScalarTypeDefinition, name: val[2], directives: val[3], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
|
355
359
|
}
|
356
360
|
|
357
361
|
object_type_definition:
|
358
362
|
description_opt TYPE name implements_opt directives_list_opt field_definition_list_opt {
|
359
|
-
result = make_node(:ObjectTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1]
|
363
|
+
result = make_node(:ObjectTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
|
360
364
|
}
|
361
365
|
|
362
366
|
implements_opt:
|
@@ -378,7 +382,7 @@ rule
|
|
378
382
|
|
379
383
|
input_value_definition:
|
380
384
|
description_opt name COLON type default_value_opt directives_list_opt {
|
381
|
-
result = make_node(:InputValueDefinition, name: val[1], type: val[3], default_value: val[4], directives: val[5], description: val[0] || get_description(val[1]), definition_line: val[1]
|
385
|
+
result = make_node(:InputValueDefinition, name: val[1], type: val[3], default_value: val[4], directives: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
|
382
386
|
}
|
383
387
|
|
384
388
|
input_value_definition_list:
|
@@ -391,7 +395,7 @@ rule
|
|
391
395
|
|
392
396
|
field_definition:
|
393
397
|
description_opt name arguments_definitions_opt COLON type directives_list_opt {
|
394
|
-
result = make_node(:FieldDefinition, name: val[1], arguments: val[2], type: val[4], directives: val[5], description: val[0] || get_description(val[1]), definition_line: val[1]
|
398
|
+
result = make_node(:FieldDefinition, name: val[1], arguments: val[2], type: val[4], directives: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
|
395
399
|
}
|
396
400
|
|
397
401
|
field_definition_list_opt:
|
@@ -405,7 +409,7 @@ rule
|
|
405
409
|
|
406
410
|
interface_type_definition:
|
407
411
|
description_opt INTERFACE name implements_opt directives_list_opt field_definition_list_opt {
|
408
|
-
result = make_node(:InterfaceTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1]
|
412
|
+
result = make_node(:InterfaceTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
|
409
413
|
}
|
410
414
|
|
411
415
|
union_members:
|
@@ -414,22 +418,22 @@ rule
|
|
414
418
|
|
415
419
|
union_type_definition:
|
416
420
|
description_opt UNION name directives_list_opt EQUALS union_members {
|
417
|
-
result = make_node(:UnionTypeDefinition, name: val[2], directives: val[3], types: val[5], description: val[0] || get_description(val[1]), definition_line: val[1]
|
421
|
+
result = make_node(:UnionTypeDefinition, name: val[2], directives: val[3], types: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
|
418
422
|
}
|
419
423
|
|
420
424
|
enum_type_definition:
|
421
425
|
description_opt ENUM name directives_list_opt LCURLY enum_value_definitions RCURLY {
|
422
|
-
result = make_node(:EnumTypeDefinition, name: val[2], directives: val[3], values: val[5], description: val[0] || get_description(val[1]), definition_line: val[1]
|
426
|
+
result = make_node(:EnumTypeDefinition, name: val[2], directives: val[3], values: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
|
423
427
|
}
|
424
428
|
|
425
429
|
input_object_type_definition:
|
426
430
|
description_opt INPUT name directives_list_opt LCURLY input_value_definition_list RCURLY {
|
427
|
-
result = make_node(:InputObjectTypeDefinition, name: val[2], directives: val[3], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1]
|
431
|
+
result = make_node(:InputObjectTypeDefinition, name: val[2], directives: val[3], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
|
428
432
|
}
|
429
433
|
|
430
434
|
directive_definition:
|
431
435
|
description_opt DIRECTIVE DIR_SIGN name arguments_definitions_opt directive_repeatable_opt ON directive_locations {
|
432
|
-
result = make_node(:DirectiveDefinition, name: val[3], arguments: val[4], locations: val[7], repeatable: !!val[5], description: val[0] || get_description(val[1]), definition_line: val[1]
|
436
|
+
result = make_node(:DirectiveDefinition, name: val[3], arguments: val[4], locations: val[7], repeatable: !!val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
|
433
437
|
}
|
434
438
|
|
435
439
|
directive_repeatable_opt:
|
@@ -437,8 +441,8 @@ rule
|
|
437
441
|
| REPEATABLE
|
438
442
|
|
439
443
|
directive_locations:
|
440
|
-
name { result = [make_node(:DirectiveLocation, name: val[0]
|
441
|
-
| directive_locations PIPE name { val[0] << make_node(:DirectiveLocation, name: val[2]
|
444
|
+
name { result = [make_node(:DirectiveLocation, name: val[0][3], position_source: val[0])] }
|
445
|
+
| directive_locations PIPE name { val[0] << make_node(:DirectiveLocation, name: val[2][3], position_source: val[2]) }
|
442
446
|
end
|
443
447
|
|
444
448
|
---- header ----
|
@@ -448,22 +452,22 @@ end
|
|
448
452
|
|
449
453
|
EMPTY_ARRAY = [].freeze
|
450
454
|
|
451
|
-
def initialize(query_string, filename:,
|
455
|
+
def initialize(query_string, filename:, trace: Tracing::NullTrace)
|
452
456
|
raise GraphQL::ParseError.new("No query string was present", nil, nil, query_string) if query_string.nil?
|
453
457
|
@query_string = query_string
|
454
458
|
@filename = filename
|
455
|
-
@
|
459
|
+
@trace = trace
|
456
460
|
@reused_next_token = [nil, nil]
|
457
461
|
end
|
458
462
|
|
459
463
|
def parse_document
|
460
464
|
@document ||= begin
|
461
465
|
# Break the string into tokens
|
462
|
-
@
|
463
|
-
@tokens ||= GraphQL.
|
466
|
+
@trace.lex(query_string: @query_string) do
|
467
|
+
@tokens ||= GraphQL::Language::Lexer.tokenize(@query_string)
|
464
468
|
end
|
465
469
|
# From the tokens, build an AST
|
466
|
-
@
|
470
|
+
@trace.parse(query_string: @query_string) do
|
467
471
|
if @tokens.empty?
|
468
472
|
raise GraphQL::ParseError.new("Unexpected end of document", nil, nil, @query_string)
|
469
473
|
else
|
@@ -476,17 +480,17 @@ end
|
|
476
480
|
class << self
|
477
481
|
attr_accessor :cache
|
478
482
|
|
479
|
-
def parse(query_string, filename: nil,
|
480
|
-
new(query_string, filename: filename,
|
483
|
+
def parse(query_string, filename: nil, trace: GraphQL::Tracing::NullTrace)
|
484
|
+
new(query_string, filename: filename, trace: trace).parse_document
|
481
485
|
end
|
482
486
|
|
483
|
-
def parse_file(filename,
|
487
|
+
def parse_file(filename, trace: GraphQL::Tracing::NullTrace)
|
484
488
|
if cache
|
485
489
|
cache.fetch(filename) do
|
486
|
-
parse(File.read(filename), filename: filename,
|
490
|
+
parse(File.read(filename), filename: filename, trace: trace)
|
487
491
|
end
|
488
492
|
else
|
489
|
-
parse(File.read(filename), filename: filename,
|
493
|
+
parse(File.read(filename), filename: filename, trace: trace)
|
490
494
|
end
|
491
495
|
end
|
492
496
|
end
|
@@ -498,7 +502,7 @@ def next_token
|
|
498
502
|
if lexer_token.nil?
|
499
503
|
nil
|
500
504
|
else
|
501
|
-
@reused_next_token[0] = lexer_token
|
505
|
+
@reused_next_token[0] = lexer_token[0]
|
502
506
|
@reused_next_token[1] = lexer_token
|
503
507
|
@reused_next_token
|
504
508
|
end
|
@@ -509,13 +513,13 @@ def get_description(token)
|
|
509
513
|
|
510
514
|
loop do
|
511
515
|
prev_token = token
|
512
|
-
token = token
|
516
|
+
token = token[4]
|
513
517
|
|
514
518
|
break if token.nil?
|
515
|
-
break if token
|
516
|
-
break if prev_token
|
519
|
+
break if token[0] != :COMMENT
|
520
|
+
break if prev_token[1] != token[1] + 1
|
517
521
|
|
518
|
-
comments.unshift(token.
|
522
|
+
comments.unshift(token[3].sub(/^#\s*/, ""))
|
519
523
|
end
|
520
524
|
|
521
525
|
return nil if comments.empty?
|
@@ -531,11 +535,12 @@ def on_error(parser_token_id, lexer_token, vstack)
|
|
531
535
|
if parser_token_name.nil?
|
532
536
|
raise GraphQL::ParseError.new("Parse Error on unknown token: {token_id: #{parser_token_id}, lexer_token: #{lexer_token}} from #{@query_string}", nil, nil, @query_string, filename: @filename)
|
533
537
|
else
|
534
|
-
line
|
535
|
-
|
536
|
-
|
538
|
+
line = lexer_token[1]
|
539
|
+
col = lexer_token[2]
|
540
|
+
if lexer_token[0] == :BAD_UNICODE_ESCAPE
|
541
|
+
raise GraphQL::ParseError.new("Parse error on bad Unicode escape sequence: #{lexer_token[3].inspect} (#{parser_token_name}) at [#{line}, #{col}]", line, col, @query_string, filename: @filename)
|
537
542
|
else
|
538
|
-
raise GraphQL::ParseError.new("Parse error on #{lexer_token.
|
543
|
+
raise GraphQL::ParseError.new("Parse error on #{lexer_token[3].inspect} (#{parser_token_name}) at [#{line}, #{col}]", line, col, @query_string, filename: @filename)
|
539
544
|
end
|
540
545
|
end
|
541
546
|
end
|
@@ -543,8 +548,8 @@ end
|
|
543
548
|
|
544
549
|
def make_node(node_name, assigns)
|
545
550
|
assigns.each do |key, value|
|
546
|
-
if key != :position_source && value.is_a?(
|
547
|
-
assigns[key] = value
|
551
|
+
if key != :position_source && value.is_a?(Array) && value[0].is_a?(Symbol)
|
552
|
+
assigns[key] = value[3]
|
548
553
|
end
|
549
554
|
end
|
550
555
|
|
@@ -7,14 +7,6 @@ module GraphQL
|
|
7
7
|
class ActiveRecordRelationConnection < Pagination::RelationConnection
|
8
8
|
private
|
9
9
|
|
10
|
-
def relation_larger_than(relation, initial_offset, size)
|
11
|
-
if already_loaded?(relation)
|
12
|
-
(relation.size + initial_offset) > size
|
13
|
-
else
|
14
|
-
set_offset(sliced_nodes, initial_offset + size).exists?
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
10
|
def relation_count(relation)
|
19
11
|
int_or_hash = if already_loaded?(relation)
|
20
12
|
relation.size
|
@@ -58,7 +58,7 @@ module GraphQL
|
|
58
58
|
# @param arguments [Hash] The arguments to the field that returned the collection wrapped by this connection
|
59
59
|
# @param max_page_size [Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given and no `default_page_size` is set.
|
60
60
|
# @param default_page_size [Integer, nil] A configured value to determine the result size when neither first or last are given.
|
61
|
-
def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size:
|
61
|
+
def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, last: nil, before: nil, edge_class: nil, arguments: nil)
|
62
62
|
@items = items
|
63
63
|
@parent = parent
|
64
64
|
@context = context
|
@@ -71,14 +71,14 @@ module GraphQL
|
|
71
71
|
@edge_class = edge_class || self.class::Edge
|
72
72
|
# This is only true if the object was _initialized_ with an override
|
73
73
|
# or if one is assigned later.
|
74
|
-
@has_max_page_size_override = max_page_size !=
|
75
|
-
@max_page_size = if max_page_size ==
|
74
|
+
@has_max_page_size_override = max_page_size != NOT_CONFIGURED
|
75
|
+
@max_page_size = if max_page_size == NOT_CONFIGURED
|
76
76
|
nil
|
77
77
|
else
|
78
78
|
max_page_size
|
79
79
|
end
|
80
|
-
@has_default_page_size_override = default_page_size !=
|
81
|
-
@default_page_size = if default_page_size ==
|
80
|
+
@has_default_page_size_override = default_page_size != NOT_CONFIGURED
|
81
|
+
@default_page_size = if default_page_size == NOT_CONFIGURED
|
82
82
|
nil
|
83
83
|
else
|
84
84
|
default_page_size
|
@@ -91,22 +91,31 @@ module GraphQL
|
|
91
91
|
end
|
92
92
|
|
93
93
|
class ScopedContext
|
94
|
+
NO_PATH = GraphQL::EmptyObjects::EMPTY_ARRAY
|
95
|
+
NO_CONTEXT = GraphQL::EmptyObjects::EMPTY_HASH
|
96
|
+
|
94
97
|
def initialize(query_context)
|
95
98
|
@query_context = query_context
|
96
|
-
@scoped_contexts =
|
97
|
-
@
|
99
|
+
@scoped_contexts = nil
|
100
|
+
@all_keys = nil
|
98
101
|
end
|
99
102
|
|
100
103
|
def merged_context
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
+
if @scoped_contexts.nil?
|
105
|
+
NO_CONTEXT
|
106
|
+
else
|
107
|
+
merged_ctx = {}
|
108
|
+
each_present_path_ctx do |path_ctx|
|
109
|
+
merged_ctx = path_ctx.merge(merged_ctx)
|
110
|
+
end
|
111
|
+
merged_ctx
|
104
112
|
end
|
105
|
-
merged_ctx
|
106
113
|
end
|
107
114
|
|
108
115
|
def merge!(hash)
|
109
|
-
|
116
|
+
@all_keys ||= Set.new
|
117
|
+
@all_keys.merge(hash.keys)
|
118
|
+
ctx = @scoped_contexts ||= {}
|
110
119
|
current_path.each do |path_part|
|
111
120
|
ctx = ctx[path_part] ||= { parent: ctx }
|
112
121
|
end
|
@@ -114,15 +123,12 @@ module GraphQL
|
|
114
123
|
this_scoped_ctx.merge!(hash)
|
115
124
|
end
|
116
125
|
|
117
|
-
def current_path
|
118
|
-
thread_info = Thread.current[:__graphql_runtime_info]
|
119
|
-
(thread_info && thread_info[:current_path]) || @no_path
|
120
|
-
end
|
121
|
-
|
122
126
|
def key?(key)
|
123
|
-
|
124
|
-
|
125
|
-
|
127
|
+
if @all_keys && @all_keys.include?(key)
|
128
|
+
each_present_path_ctx do |path_ctx|
|
129
|
+
if path_ctx.key?(key)
|
130
|
+
return true
|
131
|
+
end
|
126
132
|
end
|
127
133
|
end
|
128
134
|
false
|
@@ -137,6 +143,10 @@ module GraphQL
|
|
137
143
|
nil
|
138
144
|
end
|
139
145
|
|
146
|
+
def current_path
|
147
|
+
@query_context.current_path || NO_PATH
|
148
|
+
end
|
149
|
+
|
140
150
|
def dig(key, *other_keys)
|
141
151
|
each_present_path_ctx do |path_ctx|
|
142
152
|
if path_ctx.key?(key)
|
@@ -157,19 +167,23 @@ module GraphQL
|
|
157
167
|
# but look up the tree for previously-assigned scoped values
|
158
168
|
def each_present_path_ctx
|
159
169
|
ctx = @scoped_contexts
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
170
|
+
if ctx.nil?
|
171
|
+
# no-op
|
172
|
+
else
|
173
|
+
current_path.each do |path_part|
|
174
|
+
if ctx.key?(path_part)
|
175
|
+
ctx = ctx[path_part]
|
176
|
+
else
|
177
|
+
break
|
178
|
+
end
|
165
179
|
end
|
166
|
-
end
|
167
180
|
|
168
|
-
|
169
|
-
|
170
|
-
|
181
|
+
while ctx
|
182
|
+
if (scoped_ctx = ctx[:scoped_context])
|
183
|
+
yield(scoped_ctx)
|
184
|
+
end
|
185
|
+
ctx = ctx[:parent]
|
171
186
|
end
|
172
|
-
ctx = ctx[:parent]
|
173
187
|
end
|
174
188
|
end
|
175
189
|
end
|
@@ -209,14 +223,30 @@ module GraphQL
|
|
209
223
|
elsif @provided_values.key?(key)
|
210
224
|
@provided_values[key]
|
211
225
|
elsif RUNTIME_METADATA_KEYS.include?(key)
|
212
|
-
|
213
|
-
|
226
|
+
if key == :current_path
|
227
|
+
current_path
|
228
|
+
else
|
229
|
+
(current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
230
|
+
(current_runtime_state.public_send(key))
|
231
|
+
end
|
214
232
|
else
|
215
233
|
# not found
|
216
234
|
nil
|
217
235
|
end
|
218
236
|
end
|
219
237
|
|
238
|
+
def current_path
|
239
|
+
current_runtime_state = Thread.current[:__graphql_runtime_info]
|
240
|
+
path = current_runtime_state &&
|
241
|
+
(result = current_runtime_state.current_result) &&
|
242
|
+
(result.path)
|
243
|
+
if path && (rn = current_runtime_state.current_result_name)
|
244
|
+
path = path.dup
|
245
|
+
path.push(rn)
|
246
|
+
end
|
247
|
+
path
|
248
|
+
end
|
249
|
+
|
220
250
|
def delete(key)
|
221
251
|
if @scoped_context.key?(key)
|
222
252
|
@scoped_context.delete(key)
|
@@ -229,8 +259,8 @@ module GraphQL
|
|
229
259
|
|
230
260
|
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
231
261
|
if RUNTIME_METADATA_KEYS.include?(key)
|
232
|
-
(
|
233
|
-
|
262
|
+
(runtime = Thread.current[:__graphql_runtime_info]) &&
|
263
|
+
(runtime.public_send(key))
|
234
264
|
elsif @scoped_context.key?(key)
|
235
265
|
scoped_context[key]
|
236
266
|
elsif @provided_values.key?(key)
|
@@ -246,8 +276,9 @@ module GraphQL
|
|
246
276
|
|
247
277
|
def dig(key, *other_keys)
|
248
278
|
if RUNTIME_METADATA_KEYS.include?(key)
|
249
|
-
(
|
250
|
-
|
279
|
+
(current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
280
|
+
(obj = current_runtime_state.public_send(key)) &&
|
281
|
+
obj.dig(*other_keys)
|
251
282
|
elsif @scoped_context.key?(key)
|
252
283
|
@scoped_context.dig(key, *other_keys)
|
253
284
|
else
|
data/lib/graphql/query.rb
CHANGED
@@ -95,12 +95,24 @@ module GraphQL
|
|
95
95
|
@fragments = nil
|
96
96
|
@operations = nil
|
97
97
|
@validate = validate
|
98
|
-
|
98
|
+
context_tracers = (context ? context.fetch(:tracers, []) : [])
|
99
|
+
@tracers = schema.tracers + context_tracers
|
100
|
+
|
99
101
|
# Support `ctx[:backtrace] = true` for wrapping backtraces
|
100
102
|
if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
|
101
|
-
|
103
|
+
if schema.trace_class <= GraphQL::Tracing::LegacyTrace
|
104
|
+
context_tracers += [GraphQL::Backtrace::Tracer]
|
105
|
+
@tracers << GraphQL::Backtrace::Tracer
|
106
|
+
elsif !(current_trace.class <= GraphQL::Backtrace::Trace)
|
107
|
+
raise "Invariant: `backtrace: true` should have provided a trace class with Backtrace mixed in, but it didnt. (Found: #{current_trace.class.ancestors}). This is a bug in GraphQL-Ruby, please report it on GitHub."
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
if context_tracers.any? && !(schema.trace_class <= GraphQL::Tracing::LegacyTrace)
|
112
|
+
raise ArgumentError, "context[:tracers] are not supported without `trace_class(GraphQL::Tracing::LegacyTrace)` in the schema configuration, please add it."
|
102
113
|
end
|
103
114
|
|
115
|
+
|
104
116
|
@analysis_errors = []
|
105
117
|
if variables.is_a?(String)
|
106
118
|
raise ArgumentError, "Query variables should be a Hash, not a String. Try JSON.parse to prepare variables."
|
@@ -157,6 +169,11 @@ module GraphQL
|
|
157
169
|
|
158
170
|
attr_accessor :multiplex
|
159
171
|
|
172
|
+
# @return [GraphQL::Tracing::Trace]
|
173
|
+
def current_trace
|
174
|
+
@current_trace ||= multiplex ? multiplex.current_trace : schema.new_trace(multiplex: multiplex, query: self)
|
175
|
+
end
|
176
|
+
|
160
177
|
def subscription_update?
|
161
178
|
@subscription_topic && subscription?
|
162
179
|
end
|
@@ -305,8 +322,8 @@ module GraphQL
|
|
305
322
|
# @param value [Object] Any runtime value
|
306
323
|
# @return [GraphQL::ObjectType, nil] The runtime type of `value` from {Schema#resolve_type}
|
307
324
|
# @see {#possible_types} to apply filtering from `only` / `except`
|
308
|
-
def resolve_type(abstract_type, value =
|
309
|
-
if value.is_a?(Symbol) && value ==
|
325
|
+
def resolve_type(abstract_type, value = NOT_CONFIGURED)
|
326
|
+
if value.is_a?(Symbol) && value == NOT_CONFIGURED
|
310
327
|
# Old method signature
|
311
328
|
value = abstract_type
|
312
329
|
abstract_type = nil
|
@@ -362,7 +379,7 @@ module GraphQL
|
|
362
379
|
parse_error = nil
|
363
380
|
@document ||= begin
|
364
381
|
if query_string
|
365
|
-
GraphQL.parse(query_string,
|
382
|
+
GraphQL.parse(query_string, trace: self.current_trace)
|
366
383
|
end
|
367
384
|
rescue GraphQL::ParseError => err
|
368
385
|
parse_error = err
|
@@ -7,9 +7,7 @@ module GraphQL
|
|
7
7
|
include GraphQL::Schema::Member::HasDirectives
|
8
8
|
include GraphQL::Schema::Member::HasDeprecationReason
|
9
9
|
include GraphQL::Schema::Member::HasValidators
|
10
|
-
include GraphQL::
|
11
|
-
|
12
|
-
NO_DEFAULT = :__no_default__
|
10
|
+
include GraphQL::EmptyObjects
|
13
11
|
|
14
12
|
# @return [String] the GraphQL name for this argument, camelized unless `camelize: false` is provided
|
15
13
|
attr_reader :name
|
@@ -20,8 +18,8 @@ module GraphQL
|
|
20
18
|
|
21
19
|
# @param new_prepare [Method, Proc]
|
22
20
|
# @return [Symbol] A method or proc to call to transform this value before sending it to field resolution method
|
23
|
-
def prepare(new_prepare =
|
24
|
-
if new_prepare !=
|
21
|
+
def prepare(new_prepare = NOT_CONFIGURED)
|
22
|
+
if new_prepare != NOT_CONFIGURED
|
25
23
|
@prepare = new_prepare
|
26
24
|
end
|
27
25
|
@prepare
|
@@ -52,7 +50,7 @@ module GraphQL
|
|
52
50
|
# @param deprecation_reason [String]
|
53
51
|
# @param validates [Hash, nil] Options for building validators, if any should be applied
|
54
52
|
# @param replace_null_with_default [Boolean] if `true`, incoming values of `null` will be replaced with the configured `default_value`
|
55
|
-
def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value:
|
53
|
+
def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: 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)
|
56
54
|
arg_name ||= name
|
57
55
|
@name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
|
58
56
|
@type_expr = type_expr || type
|
@@ -104,8 +102,8 @@ module GraphQL
|
|
104
102
|
|
105
103
|
# @param default_value [Object] The value to use when the client doesn't provide one
|
106
104
|
# @return [Object] the value used when the client doesn't provide a value for this argument
|
107
|
-
def default_value(new_default_value =
|
108
|
-
if new_default_value !=
|
105
|
+
def default_value(new_default_value = NOT_CONFIGURED)
|
106
|
+
if new_default_value != NOT_CONFIGURED
|
109
107
|
@default_value = new_default_value
|
110
108
|
end
|
111
109
|
@default_value
|
@@ -113,7 +111,7 @@ module GraphQL
|
|
113
111
|
|
114
112
|
# @return [Boolean] True if this argument has a default value
|
115
113
|
def default_value?
|
116
|
-
@default_value !=
|
114
|
+
@default_value != NOT_CONFIGURED
|
117
115
|
end
|
118
116
|
|
119
117
|
def replace_null_with_default?
|
@@ -21,6 +21,7 @@ module GraphQL
|
|
21
21
|
|
22
22
|
# @api private
|
23
23
|
module Builder
|
24
|
+
include GraphQL::EmptyObjects
|
24
25
|
extend self
|
25
26
|
|
26
27
|
def build(schema_superclass, document, default_resolve:, using: {}, relay:)
|
@@ -99,6 +100,16 @@ module GraphQL
|
|
99
100
|
raise InvalidDocumentError.new("Specified subscription type \"#{schema_definition.subscription}\" not found in document.") unless types[schema_definition.subscription]
|
100
101
|
subscription_root_type = types[schema_definition.subscription]
|
101
102
|
end
|
103
|
+
|
104
|
+
if schema_definition.query.nil? &&
|
105
|
+
schema_definition.mutation.nil? &&
|
106
|
+
schema_definition.subscription.nil?
|
107
|
+
# This schema may have been given with directives only,
|
108
|
+
# check for defaults:
|
109
|
+
query_root_type = types['Query']
|
110
|
+
mutation_root_type = types['Mutation']
|
111
|
+
subscription_root_type = types['Subscription']
|
112
|
+
end
|
102
113
|
else
|
103
114
|
query_root_type = types['Query']
|
104
115
|
mutation_root_type = types['Mutation']
|
@@ -107,6 +118,8 @@ module GraphQL
|
|
107
118
|
|
108
119
|
raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
|
109
120
|
|
121
|
+
builder = self
|
122
|
+
|
110
123
|
schema_class = Class.new(schema_superclass) do
|
111
124
|
begin
|
112
125
|
# Add these first so that there's some chance of resolving late-bound types
|
@@ -134,6 +147,7 @@ module GraphQL
|
|
134
147
|
|
135
148
|
if schema_definition
|
136
149
|
ast_node(schema_definition)
|
150
|
+
builder.build_directives(self, schema_definition, type_resolver)
|
137
151
|
end
|
138
152
|
|
139
153
|
using.each do |plugin, options|
|
@@ -361,8 +375,6 @@ module GraphQL
|
|
361
375
|
end
|
362
376
|
end
|
363
377
|
|
364
|
-
NO_DEFAULT_VALUE = {}.freeze
|
365
|
-
|
366
378
|
def build_arguments(type_class, arguments, type_resolver)
|
367
379
|
builder = self
|
368
380
|
|
@@ -370,7 +382,7 @@ module GraphQL
|
|
370
382
|
default_value_kwargs = if !argument_defn.default_value.nil?
|
371
383
|
{ default_value: builder.build_default_value(argument_defn.default_value) }
|
372
384
|
else
|
373
|
-
|
385
|
+
EMPTY_HASH
|
374
386
|
end
|
375
387
|
|
376
388
|
type_class.argument(
|
@@ -25,19 +25,16 @@ module GraphQL
|
|
25
25
|
include GraphQL::Schema::Member::HasDirectives
|
26
26
|
include GraphQL::Schema::Member::HasDeprecationReason
|
27
27
|
|
28
|
-
UNDEFINED_VALUE = Object.new.freeze
|
29
|
-
private_constant :UNDEFINED_VALUE
|
30
|
-
|
31
28
|
attr_reader :graphql_name
|
32
29
|
|
33
30
|
# @return [Class] The enum type that owns this value
|
34
31
|
attr_reader :owner
|
35
32
|
|
36
|
-
def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value:
|
33
|
+
def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value: NOT_CONFIGURED, deprecation_reason: nil, &block)
|
37
34
|
@graphql_name = graphql_name.to_s
|
38
35
|
GraphQL::NameValidator.validate!(@graphql_name)
|
39
36
|
@description = desc || description
|
40
|
-
@value = value ===
|
37
|
+
@value = value === NOT_CONFIGURED ? @graphql_name : value
|
41
38
|
if deprecation_reason
|
42
39
|
self.deprecation_reason = deprecation_reason
|
43
40
|
end
|