graphql 2.2.5 → 2.3.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/ast/field_usage.rb +32 -7
- data/lib/graphql/analysis/ast/visitor.rb +8 -0
- data/lib/graphql/analysis/ast.rb +10 -1
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/execution/interpreter/runtime.rb +9 -0
- data/lib/graphql/execution/interpreter.rb +90 -150
- data/lib/graphql/introspection/entry_points.rb +9 -3
- data/lib/graphql/introspection/schema_type.rb +3 -1
- data/lib/graphql/language/document_from_schema_definition.rb +2 -3
- data/lib/graphql/language/lexer.rb +29 -28
- data/lib/graphql/language/nodes.rb +1 -1
- data/lib/graphql/language/parser.rb +12 -8
- data/lib/graphql/language/printer.rb +4 -0
- data/lib/graphql/language.rb +37 -0
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/query/context.rb +30 -33
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +2 -2
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +3 -1
- data/lib/graphql/schema/field.rb +33 -30
- data/lib/graphql/schema/interface.rb +5 -1
- data/lib/graphql/schema/loader.rb +2 -1
- data/lib/graphql/schema/member/has_arguments.rb +2 -2
- data/lib/graphql/schema/resolver.rb +9 -5
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema.rb +108 -28
- data/lib/graphql/static_validation/literal_validator.rb +1 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
- data/lib/graphql/static_validation/validator.rb +3 -0
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +0 -3
- data/lib/graphql/testing/helpers.rb +8 -4
- data/lib/graphql/tracing/data_dog_trace.rb +21 -34
- data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
- data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing.rb +3 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +3 -2
- metadata +38 -23
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
|
@@ -121,7 +121,17 @@ module GraphQL
|
|
|
121
121
|
value
|
|
122
122
|
end
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
directives = parse_directives
|
|
125
|
+
|
|
126
|
+
defs << Nodes::VariableDefinition.new(
|
|
127
|
+
pos: loc,
|
|
128
|
+
name: var_name,
|
|
129
|
+
type: var_type,
|
|
130
|
+
default_value: default_value,
|
|
131
|
+
directives: directives,
|
|
132
|
+
filename: @filename,
|
|
133
|
+
source_string: @graphql_str
|
|
134
|
+
)
|
|
125
135
|
end
|
|
126
136
|
expect_token(:RPAREN)
|
|
127
137
|
defs
|
|
@@ -729,13 +739,7 @@ module GraphQL
|
|
|
729
739
|
# token_value works for when the scanner matched something
|
|
730
740
|
# which is usually fine and it's good for it to be fast at that.
|
|
731
741
|
def debug_token_value
|
|
732
|
-
|
|
733
|
-
Lexer::Punctuation.const_get(token_name)
|
|
734
|
-
elsif token_name == :ELLIPSIS
|
|
735
|
-
"..."
|
|
736
|
-
else
|
|
737
|
-
@lexer.token_value
|
|
738
|
-
end
|
|
742
|
+
@lexer.debug_token_value(token_name)
|
|
739
743
|
end
|
|
740
744
|
end
|
|
741
745
|
end
|
|
@@ -208,6 +208,10 @@ module GraphQL
|
|
|
208
208
|
print_string(" = ")
|
|
209
209
|
print_node(variable_definition.default_value)
|
|
210
210
|
end
|
|
211
|
+
variable_definition.directives.each do |dir|
|
|
212
|
+
print_string(" ")
|
|
213
|
+
print_directive(dir)
|
|
214
|
+
end
|
|
211
215
|
end
|
|
212
216
|
|
|
213
217
|
def print_variable_identifier(variable_identifier)
|
data/lib/graphql/language.rb
CHANGED
|
@@ -12,6 +12,7 @@ require "graphql/language/static_visitor"
|
|
|
12
12
|
require "graphql/language/token"
|
|
13
13
|
require "graphql/language/visitor"
|
|
14
14
|
require "graphql/language/definition_slice"
|
|
15
|
+
require "strscan"
|
|
15
16
|
|
|
16
17
|
module GraphQL
|
|
17
18
|
module Language
|
|
@@ -33,5 +34,41 @@ module GraphQL
|
|
|
33
34
|
JSON.generate(value, quirks_mode: true)
|
|
34
35
|
end
|
|
35
36
|
end
|
|
37
|
+
|
|
38
|
+
# Returns a new string if any single-quoted newlines were escaped.
|
|
39
|
+
# Otherwise, returns `query_str` unchanged.
|
|
40
|
+
# @return [String]
|
|
41
|
+
def self.escape_single_quoted_newlines(query_str)
|
|
42
|
+
scanner = StringScanner.new(query_str)
|
|
43
|
+
inside_single_quoted_string = false
|
|
44
|
+
new_query_str = nil
|
|
45
|
+
while !scanner.eos?
|
|
46
|
+
if (match = scanner.scan(/(?:\\"|[^"\n\r]|""")+/m)) && new_query_str
|
|
47
|
+
new_query_str << match
|
|
48
|
+
elsif scanner.scan('"')
|
|
49
|
+
new_query_str && (new_query_str << '"')
|
|
50
|
+
inside_single_quoted_string = !inside_single_quoted_string
|
|
51
|
+
elsif scanner.scan("\n")
|
|
52
|
+
if inside_single_quoted_string
|
|
53
|
+
new_query_str ||= query_str[0, scanner.pos - 1]
|
|
54
|
+
new_query_str << '\\n'
|
|
55
|
+
else
|
|
56
|
+
new_query_str && (new_query_str << "\n")
|
|
57
|
+
end
|
|
58
|
+
elsif scanner.scan("\r")
|
|
59
|
+
if inside_single_quoted_string
|
|
60
|
+
new_query_str ||= query_str[0, scanner.pos - 1]
|
|
61
|
+
new_query_str << '\\r'
|
|
62
|
+
else
|
|
63
|
+
new_query_str && (new_query_str << "\r")
|
|
64
|
+
end
|
|
65
|
+
elsif scanner.eos?
|
|
66
|
+
break
|
|
67
|
+
else
|
|
68
|
+
raise ArgumentError, "Unmatchable string scanner segment: #{scanner.rest.inspect}"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
new_query_str || query_str
|
|
72
|
+
end
|
|
36
73
|
end
|
|
37
74
|
end
|
|
@@ -35,10 +35,10 @@ module GraphQL
|
|
|
35
35
|
def load_nodes
|
|
36
36
|
@nodes ||= begin
|
|
37
37
|
sliced_nodes = if before && after
|
|
38
|
-
end_idx = index_from_cursor(before)-
|
|
38
|
+
end_idx = index_from_cursor(before) - 2
|
|
39
39
|
end_idx < 0 ? [] : items[index_from_cursor(after)..end_idx] || []
|
|
40
40
|
elsif before
|
|
41
|
-
end_idx = index_from_cursor(before)-2
|
|
41
|
+
end_idx = index_from_cursor(before) - 2
|
|
42
42
|
end_idx < 0 ? [] : items[0..end_idx] || []
|
|
43
43
|
elsif after
|
|
44
44
|
items[index_from_cursor(after)..-1] || []
|
|
@@ -56,12 +56,12 @@ module GraphQL
|
|
|
56
56
|
false
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
@has_next_page = if
|
|
60
|
-
# There are more items after these items
|
|
61
|
-
sliced_nodes.count > first
|
|
62
|
-
elsif before
|
|
59
|
+
@has_next_page = if before
|
|
63
60
|
# The original array is longer than the `before` index
|
|
64
61
|
index_from_cursor(before) < items.length + 1
|
|
62
|
+
elsif first
|
|
63
|
+
# There are more items after these items
|
|
64
|
+
sliced_nodes.count > first
|
|
65
65
|
else
|
|
66
66
|
false
|
|
67
67
|
end
|
|
@@ -6,36 +6,6 @@ module GraphQL
|
|
|
6
6
|
# Expose some query-specific info to field resolve functions.
|
|
7
7
|
# It delegates `[]` to the hash that's passed to `GraphQL::Query#initialize`.
|
|
8
8
|
class Context
|
|
9
|
-
module SharedMethods
|
|
10
|
-
# Return this value to tell the runtime
|
|
11
|
-
# to exclude this field from the response altogether
|
|
12
|
-
def skip
|
|
13
|
-
GraphQL::Execution::SKIP
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Add error at query-level.
|
|
17
|
-
# @param error [GraphQL::ExecutionError] an execution error
|
|
18
|
-
# @return [void]
|
|
19
|
-
def add_error(error)
|
|
20
|
-
if !error.is_a?(ExecutionError)
|
|
21
|
-
raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
|
|
22
|
-
end
|
|
23
|
-
errors << error
|
|
24
|
-
nil
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# @example Print the GraphQL backtrace during field resolution
|
|
28
|
-
# puts ctx.backtrace
|
|
29
|
-
#
|
|
30
|
-
# @return [GraphQL::Backtrace] The backtrace for this point in query execution
|
|
31
|
-
def backtrace
|
|
32
|
-
GraphQL::Backtrace.new(self)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def execution_errors
|
|
36
|
-
@execution_errors ||= ExecutionErrors.new(self)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
9
|
|
|
40
10
|
class ExecutionErrors
|
|
41
11
|
def initialize(ctx)
|
|
@@ -59,7 +29,6 @@ module GraphQL
|
|
|
59
29
|
alias :push :add
|
|
60
30
|
end
|
|
61
31
|
|
|
62
|
-
include SharedMethods
|
|
63
32
|
extend Forwardable
|
|
64
33
|
|
|
65
34
|
# @return [Array<GraphQL::ExecutionError>] errors returned during execution
|
|
@@ -77,11 +46,10 @@ module GraphQL
|
|
|
77
46
|
# Make a new context which delegates key lookup to `values`
|
|
78
47
|
# @param query [GraphQL::Query] the query who owns this context
|
|
79
48
|
# @param values [Hash] A hash of arbitrary values which will be accessible at query-time
|
|
80
|
-
def initialize(query:, schema: query.schema, values
|
|
49
|
+
def initialize(query:, schema: query.schema, values:)
|
|
81
50
|
@query = query
|
|
82
51
|
@schema = schema
|
|
83
52
|
@provided_values = values || {}
|
|
84
|
-
@object = object
|
|
85
53
|
# Namespaced storage, where user-provided values are in `nil` namespace:
|
|
86
54
|
@storage = Hash.new { |h, k| h[k] = {} }
|
|
87
55
|
@storage[nil] = @provided_values
|
|
@@ -140,6 +108,35 @@ module GraphQL
|
|
|
140
108
|
end
|
|
141
109
|
end
|
|
142
110
|
|
|
111
|
+
# Return this value to tell the runtime
|
|
112
|
+
# to exclude this field from the response altogether
|
|
113
|
+
def skip
|
|
114
|
+
GraphQL::Execution::SKIP
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Add error at query-level.
|
|
118
|
+
# @param error [GraphQL::ExecutionError] an execution error
|
|
119
|
+
# @return [void]
|
|
120
|
+
def add_error(error)
|
|
121
|
+
if !error.is_a?(ExecutionError)
|
|
122
|
+
raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
|
|
123
|
+
end
|
|
124
|
+
errors << error
|
|
125
|
+
nil
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# @example Print the GraphQL backtrace during field resolution
|
|
129
|
+
# puts ctx.backtrace
|
|
130
|
+
#
|
|
131
|
+
# @return [GraphQL::Backtrace] The backtrace for this point in query execution
|
|
132
|
+
def backtrace
|
|
133
|
+
GraphQL::Backtrace.new(self)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def execution_errors
|
|
137
|
+
@execution_errors ||= ExecutionErrors.new(self)
|
|
138
|
+
end
|
|
139
|
+
|
|
143
140
|
def current_path
|
|
144
141
|
current_runtime_state = Thread.current[:__graphql_runtime_info]
|
|
145
142
|
query_runtime_state = current_runtime_state && current_runtime_state[@query]
|
|
@@ -14,7 +14,7 @@ module GraphQL
|
|
|
14
14
|
#
|
|
15
15
|
# @api private
|
|
16
16
|
class ValidationPipeline
|
|
17
|
-
attr_reader :max_depth, :max_complexity
|
|
17
|
+
attr_reader :max_depth, :max_complexity, :validate_timeout_remaining
|
|
18
18
|
|
|
19
19
|
def initialize(query:, parse_error:, operation_name_error:, max_depth:, max_complexity:)
|
|
20
20
|
@validation_errors = []
|
|
@@ -71,7 +71,7 @@ module GraphQL
|
|
|
71
71
|
validator = @query.static_validator || @schema.static_validator
|
|
72
72
|
validation_result = validator.validate(@query, validate: @query.validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
|
|
73
73
|
@validation_errors.concat(validation_result[:errors])
|
|
74
|
-
|
|
74
|
+
@validate_timeout_remaining = validation_result[:remaining_timeout]
|
|
75
75
|
if @validation_errors.empty?
|
|
76
76
|
@validation_errors.concat(@query.variables.errors)
|
|
77
77
|
end
|
|
@@ -26,7 +26,7 @@ module GraphQL
|
|
|
26
26
|
# - Then, fall back to the default value from the query string
|
|
27
27
|
# If it's still nil, raise an error if it's required.
|
|
28
28
|
variable_type = schema.type_from_ast(ast_variable.type, context: ctx)
|
|
29
|
-
if variable_type.nil?
|
|
29
|
+
if variable_type.nil? || !variable_type.unwrap.kind.input?
|
|
30
30
|
# Pass -- it will get handled by a validator
|
|
31
31
|
else
|
|
32
32
|
variable_name = ast_variable.name
|
|
@@ -80,12 +80,12 @@ module GraphQL
|
|
|
80
80
|
else
|
|
81
81
|
val
|
|
82
82
|
end
|
|
83
|
-
end
|
|
83
|
+
end
|
|
84
84
|
|
|
85
85
|
def add_max_errors_reached_message
|
|
86
86
|
message = "Too many errors processing variables, max validation error limit reached. Execution aborted"
|
|
87
87
|
validation_result = GraphQL::Query::InputValidationResult.from_problem(message)
|
|
88
|
-
errors << GraphQL::Query::VariableValidationError.new(nil, nil, nil, validation_result, msg: message)
|
|
88
|
+
errors << GraphQL::Query::VariableValidationError.new(nil, nil, nil, validation_result, msg: message)
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
91
|
end
|
data/lib/graphql/query.rb
CHANGED
|
@@ -99,7 +99,7 @@ module GraphQL
|
|
|
99
99
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
|
100
100
|
variables ||= {}
|
|
101
101
|
@schema = schema
|
|
102
|
-
@context = schema.context_class.new(query: self,
|
|
102
|
+
@context = schema.context_class.new(query: self, values: context)
|
|
103
103
|
@warden = warden
|
|
104
104
|
@subscription_topic = subscription_topic
|
|
105
105
|
@root_value = root_value
|
|
@@ -317,7 +317,7 @@ module GraphQL
|
|
|
317
317
|
end
|
|
318
318
|
|
|
319
319
|
def_delegators :validation_pipeline, :validation_errors,
|
|
320
|
-
:analyzers, :ast_analyzers, :max_depth, :max_complexity
|
|
320
|
+
:analyzers, :ast_analyzers, :max_depth, :max_complexity, :validate_timeout_remaining
|
|
321
321
|
|
|
322
322
|
attr_accessor :analysis_errors
|
|
323
323
|
def valid?
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'graphql/schema/base_64_bp'
|
|
4
|
-
|
|
2
|
+
require "base64"
|
|
5
3
|
module GraphQL
|
|
6
4
|
class Schema
|
|
7
5
|
# @api private
|
|
8
6
|
module Base64Encoder
|
|
9
7
|
def self.encode(unencoded_text, nonce: false)
|
|
10
|
-
|
|
8
|
+
Base64.urlsafe_encode64(unencoded_text, padding: false)
|
|
11
9
|
end
|
|
12
10
|
|
|
13
11
|
def self.decode(encoded_text, nonce: false)
|
|
14
12
|
# urlsafe_decode64 is for forward compatibility
|
|
15
|
-
|
|
13
|
+
Base64.urlsafe_decode64(encoded_text)
|
|
16
14
|
rescue ArgumentError
|
|
17
15
|
raise GraphQL::ExecutionError, "Invalid input: #{encoded_text.inspect}"
|
|
18
16
|
end
|
|
@@ -120,10 +120,12 @@ module GraphQL
|
|
|
120
120
|
|
|
121
121
|
builder = self
|
|
122
122
|
|
|
123
|
+
found_types = types.values
|
|
123
124
|
schema_class = Class.new(schema_superclass) do
|
|
124
125
|
begin
|
|
125
126
|
# Add these first so that there's some chance of resolving late-bound types
|
|
126
|
-
|
|
127
|
+
add_type_and_traverse(found_types, root: false)
|
|
128
|
+
orphan_types(found_types.select { |t| t.respond_to?(:kind) && t.kind.object? })
|
|
127
129
|
query query_root_type
|
|
128
130
|
mutation mutation_root_type
|
|
129
131
|
subscription subscription_root_type
|
data/lib/graphql/schema/field.rb
CHANGED
|
@@ -471,6 +471,8 @@ module GraphQL
|
|
|
471
471
|
if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
|
|
472
472
|
max_possible_page_size = arguments[:last]
|
|
473
473
|
end
|
|
474
|
+
elsif arguments.is_a?(GraphQL::UnauthorizedError)
|
|
475
|
+
raise arguments
|
|
474
476
|
end
|
|
475
477
|
|
|
476
478
|
if max_possible_page_size.nil?
|
|
@@ -483,41 +485,24 @@ module GraphQL
|
|
|
483
485
|
metadata_complexity = 0
|
|
484
486
|
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
|
485
487
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
488
|
+
lookahead.selections.each do |next_lookahead|
|
|
489
|
+
# this includes `pageInfo`, `nodes` and `edges` and any custom fields
|
|
490
|
+
# TODO this doesn't support procs yet -- unlikely to need it.
|
|
491
|
+
metadata_complexity += next_lookahead.field.complexity
|
|
492
|
+
if next_lookahead.name != :nodes && next_lookahead.name != :edges
|
|
493
|
+
# subfields, eg, for pageInfo -- assumes no subselections
|
|
494
|
+
metadata_complexity += next_lookahead.selections.size
|
|
495
|
+
end
|
|
493
496
|
end
|
|
494
497
|
|
|
495
|
-
nodes_edges_complexity = 0
|
|
496
|
-
nodes_edges_complexity += 1 if lookahead.selects?(:edges)
|
|
497
|
-
nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
|
|
498
|
-
|
|
499
498
|
# Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
|
|
500
|
-
items_complexity = child_complexity - metadata_complexity
|
|
501
|
-
|
|
502
|
-
|
|
499
|
+
items_complexity = child_complexity - metadata_complexity
|
|
500
|
+
subfields_complexity = (max_possible_page_size * items_complexity) + metadata_complexity
|
|
501
|
+
# Apply this field's own complexity
|
|
502
|
+
apply_own_complexity_to(subfields_complexity, query, nodes)
|
|
503
503
|
end
|
|
504
504
|
else
|
|
505
|
-
|
|
506
|
-
case defined_complexity
|
|
507
|
-
when Proc
|
|
508
|
-
arguments = query.arguments_for(nodes.first, self)
|
|
509
|
-
if arguments.is_a?(GraphQL::ExecutionError)
|
|
510
|
-
return child_complexity
|
|
511
|
-
elsif arguments.respond_to?(:keyword_arguments)
|
|
512
|
-
arguments = arguments.keyword_arguments
|
|
513
|
-
end
|
|
514
|
-
|
|
515
|
-
defined_complexity.call(query.context, arguments, child_complexity)
|
|
516
|
-
when Numeric
|
|
517
|
-
defined_complexity + child_complexity
|
|
518
|
-
else
|
|
519
|
-
raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
|
|
520
|
-
end
|
|
505
|
+
apply_own_complexity_to(child_complexity, query, nodes)
|
|
521
506
|
end
|
|
522
507
|
end
|
|
523
508
|
|
|
@@ -882,6 +867,24 @@ ERR
|
|
|
882
867
|
yield(obj, args)
|
|
883
868
|
end
|
|
884
869
|
end
|
|
870
|
+
|
|
871
|
+
def apply_own_complexity_to(child_complexity, query, nodes)
|
|
872
|
+
case (own_complexity = complexity)
|
|
873
|
+
when Numeric
|
|
874
|
+
own_complexity + child_complexity
|
|
875
|
+
when Proc
|
|
876
|
+
arguments = query.arguments_for(nodes.first, self)
|
|
877
|
+
if arguments.is_a?(GraphQL::ExecutionError)
|
|
878
|
+
return child_complexity
|
|
879
|
+
elsif arguments.respond_to?(:keyword_arguments)
|
|
880
|
+
arguments = arguments.keyword_arguments
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
own_complexity.call(query.context, arguments, child_complexity)
|
|
884
|
+
else
|
|
885
|
+
raise ArgumentError, "Invalid complexity for #{self.path}: #{own_complexity.inspect}"
|
|
886
|
+
end
|
|
887
|
+
end
|
|
885
888
|
end
|
|
886
889
|
end
|
|
887
890
|
end
|
|
@@ -69,7 +69,11 @@ module GraphQL
|
|
|
69
69
|
end
|
|
70
70
|
elsif child_class < GraphQL::Schema::Object
|
|
71
71
|
# This is being included into an object type, make sure it's using `implements(...)`
|
|
72
|
-
backtrace_line =
|
|
72
|
+
backtrace_line = caller_locations(0, 10).find do |location|
|
|
73
|
+
location.base_label == "implements" &&
|
|
74
|
+
location.path.end_with?("schema/member/has_interfaces.rb")
|
|
75
|
+
end
|
|
76
|
+
|
|
73
77
|
if !backtrace_line
|
|
74
78
|
raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
|
|
75
79
|
end
|
|
@@ -32,7 +32,8 @@ module GraphQL
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
Class.new(GraphQL::Schema) do
|
|
35
|
-
|
|
35
|
+
add_type_and_traverse(types.values, root: false)
|
|
36
|
+
orphan_types(types.values.select { |t| t.kind.object? })
|
|
36
37
|
directives(directives)
|
|
37
38
|
description(schema["description"])
|
|
38
39
|
|
|
@@ -50,7 +50,7 @@ module GraphQL
|
|
|
50
50
|
if loads && arg_defn.type.list?
|
|
51
51
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
52
52
|
def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
|
|
53
|
-
argument = get_argument("#{arg_defn.graphql_name}")
|
|
53
|
+
argument = get_argument("#{arg_defn.graphql_name}", context || self.context)
|
|
54
54
|
(context || self.context).query.after_lazy(values) do |values2|
|
|
55
55
|
GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
|
|
56
56
|
end
|
|
@@ -59,7 +59,7 @@ module GraphQL
|
|
|
59
59
|
elsif loads
|
|
60
60
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
61
61
|
def #{method_owner}load_#{arg_defn.keyword}(value, context = nil)
|
|
62
|
-
argument = get_argument("#{arg_defn.graphql_name}")
|
|
62
|
+
argument = get_argument("#{arg_defn.graphql_name}", context || self.context)
|
|
63
63
|
load_application_object(argument, value, context || self.context)
|
|
64
64
|
end
|
|
65
65
|
RUBY
|
|
@@ -166,11 +166,15 @@ module GraphQL
|
|
|
166
166
|
args.each_value do |argument|
|
|
167
167
|
arg_keyword = argument.keyword
|
|
168
168
|
if inputs.key?(arg_keyword) && !(arg_value = inputs[arg_keyword]).nil? && (arg_value != argument.default_value)
|
|
169
|
-
|
|
170
|
-
if
|
|
171
|
-
return
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
auth_result = argument.authorized?(self, arg_value, context)
|
|
170
|
+
if auth_result.is_a?(Array)
|
|
171
|
+
# only return this second value if the application returned a second value
|
|
172
|
+
arg_auth, err = auth_result
|
|
173
|
+
if !arg_auth
|
|
174
|
+
return arg_auth, err
|
|
175
|
+
end
|
|
176
|
+
elsif auth_result == false
|
|
177
|
+
return auth_result
|
|
174
178
|
end
|
|
175
179
|
else
|
|
176
180
|
true
|