graphql 2.5.23 → 2.6.3
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/query_complexity.rb +29 -13
- data/lib/graphql/analysis.rb +20 -13
- data/lib/graphql/backtrace/table.rb +10 -1
- data/lib/graphql/current.rb +7 -1
- data/lib/graphql/dataloader.rb +1 -1
- data/lib/graphql/execution/directive_checks.rb +2 -0
- data/lib/graphql/execution/field_resolve_step.rb +744 -0
- data/lib/graphql/execution/finalize.rb +230 -0
- data/lib/graphql/execution/input_values.rb +333 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +3 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +6 -0
- data/lib/graphql/execution/interpreter/runtime.rb +36 -15
- data/lib/graphql/execution/load_argument_step.rb +102 -0
- data/lib/graphql/execution/next.rb +42 -16
- data/lib/graphql/execution/prepare_object_step.rb +147 -0
- data/lib/graphql/execution/resolve_type_step.rb +27 -0
- data/lib/graphql/execution/runner.rb +445 -0
- data/lib/graphql/execution/selections_step.rb +91 -0
- data/lib/graphql/execution.rb +10 -3
- data/lib/graphql/execution_error.rb +7 -13
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/schema_type.rb +6 -2
- data/lib/graphql/language/lexer.rb +12 -8
- data/lib/graphql/language/parser.rb +1 -1
- data/lib/graphql/language.rb +8 -2
- data/lib/graphql/pagination/connections.rb +1 -3
- data/lib/graphql/query/context.rb +6 -0
- data/lib/graphql/query/partial.rb +18 -3
- data/lib/graphql/query.rb +12 -3
- data/lib/graphql/runtime_error.rb +6 -0
- data/lib/graphql/schema/argument.rb +3 -3
- data/lib/graphql/schema/build_from_definition.rb +10 -0
- data/lib/graphql/schema/directive/feature.rb +4 -0
- data/lib/graphql/schema/directive/transform.rb +20 -0
- data/lib/graphql/schema/directive.rb +23 -9
- data/lib/graphql/schema/field/connection_extension.rb +2 -15
- data/lib/graphql/schema/field/scope_extension.rb +0 -4
- data/lib/graphql/schema/field.rb +20 -20
- data/lib/graphql/schema/field_extension.rb +11 -41
- data/lib/graphql/schema/has_single_input_argument.rb +24 -13
- data/lib/graphql/schema/input_object.rb +4 -0
- data/lib/graphql/schema/interface.rb +26 -0
- data/lib/graphql/schema/introspection_system.rb +6 -21
- data/lib/graphql/schema/list.rb +4 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +0 -10
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/schema/ractor_shareable.rb +1 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +16 -2
- data/lib/graphql/schema/resolver.rb +30 -14
- data/lib/graphql/schema/subscription.rb +53 -8
- data/lib/graphql/schema/timeout.rb +2 -2
- data/lib/graphql/schema/validator/allow_blank_validator.rb +3 -3
- data/lib/graphql/schema/validator/allow_null_validator.rb +3 -3
- data/lib/graphql/schema/validator/exclusion_validator.rb +2 -2
- data/lib/graphql/schema/validator/format_validator.rb +3 -3
- data/lib/graphql/schema/validator/inclusion_validator.rb +2 -2
- data/lib/graphql/schema/validator/length_validator.rb +6 -6
- data/lib/graphql/schema/validator/numericality_validator.rb +19 -19
- data/lib/graphql/schema/validator/required_validator.rb +6 -4
- data/lib/graphql/schema/validator.rb +9 -0
- data/lib/graphql/schema/visibility/profile.rb +6 -4
- data/lib/graphql/schema/visibility/visit.rb +1 -1
- data/lib/graphql/schema/visibility.rb +30 -22
- data/lib/graphql/schema.rb +43 -20
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +31 -25
- data/lib/graphql/subscriptions/event.rb +0 -1
- data/lib/graphql/subscriptions.rb +15 -0
- data/lib/graphql/tracing/perfetto_trace.rb +5 -3
- data/lib/graphql/tracing/trace.rb +6 -0
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +1 -3
- metadata +11 -7
- data/lib/graphql/execution/next/field_resolve_step.rb +0 -743
- data/lib/graphql/execution/next/load_argument_step.rb +0 -64
- data/lib/graphql/execution/next/prepare_object_step.rb +0 -129
- data/lib/graphql/execution/next/runner.rb +0 -411
- data/lib/graphql/execution/next/selections_step.rb +0 -37
|
@@ -26,16 +26,6 @@ module GraphQL
|
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
# Just a convenience method to point out that people should use graphql_name instead
|
|
30
|
-
def name(new_name = nil)
|
|
31
|
-
return super() if new_name.nil?
|
|
32
|
-
|
|
33
|
-
fail(
|
|
34
|
-
"The new name override method is `graphql_name`, not `name`. Usage: "\
|
|
35
|
-
"graphql_name \"#{new_name}\""
|
|
36
|
-
)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
29
|
# Call this method to provide a new description; OR
|
|
40
30
|
# call it without an argument to get the description
|
|
41
31
|
# @param new_description [String]
|
|
@@ -25,7 +25,7 @@ module GraphQL
|
|
|
25
25
|
argument :client_mutation_id, String, "A unique identifier for the client performing the mutation.", required: false
|
|
26
26
|
|
|
27
27
|
# The payload should always include this field
|
|
28
|
-
field(:client_mutation_id, String, "A unique identifier for the client performing the mutation.")
|
|
28
|
+
field(:client_mutation_id, String, "A unique identifier for the client performing the mutation.", hash_key: :client_mutation_id)
|
|
29
29
|
# Relay classic default:
|
|
30
30
|
null(true)
|
|
31
31
|
|
|
@@ -35,7 +35,6 @@ module GraphQL
|
|
|
35
35
|
input = inputs[:input].to_kwargs
|
|
36
36
|
|
|
37
37
|
if input
|
|
38
|
-
# This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
|
|
39
38
|
input_kwargs = input.to_h
|
|
40
39
|
client_mutation_id = input_kwargs.delete(:client_mutation_id)
|
|
41
40
|
inputs[:input] = input_kwargs
|
|
@@ -51,6 +50,21 @@ module GraphQL
|
|
|
51
50
|
return_hash
|
|
52
51
|
end
|
|
53
52
|
end
|
|
53
|
+
|
|
54
|
+
def call
|
|
55
|
+
input = @prepared_arguments[:input]&.to_kwargs
|
|
56
|
+
|
|
57
|
+
if input
|
|
58
|
+
client_mutation_id = input.delete(:client_mutation_id)
|
|
59
|
+
@prepared_arguments[:input] = input
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
super
|
|
63
|
+
|
|
64
|
+
if (return_value = exec_result[exec_index]).is_a?(Hash)
|
|
65
|
+
return_value[:client_mutation_id] = client_mutation_id
|
|
66
|
+
end
|
|
67
|
+
end
|
|
54
68
|
end
|
|
55
69
|
end
|
|
56
70
|
end
|
|
@@ -60,29 +60,39 @@ module GraphQL
|
|
|
60
60
|
attr_writer :prepared_arguments
|
|
61
61
|
|
|
62
62
|
def call
|
|
63
|
-
if self.class < Schema::HasSingleInputArgument
|
|
64
|
-
@prepared_arguments = @prepared_arguments[:input]
|
|
65
|
-
end
|
|
66
63
|
q = context.query
|
|
67
64
|
trace_objs = [object]
|
|
68
65
|
q.current_trace.begin_execute_field(field, @prepared_arguments, trace_objs, q)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
new_return_value =
|
|
73
|
-
|
|
66
|
+
is_ready = ready?(**@prepared_arguments)
|
|
67
|
+
runner = @field_resolve_step.runner
|
|
68
|
+
if runner.resolves_lazies && runner.schema.lazy?(is_ready)
|
|
69
|
+
is_ready, new_return_value = runner.schema.sync_lazy(is_ready)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
if is_ready.is_a?(Array)
|
|
73
|
+
is_ready, new_return_value = is_ready
|
|
74
|
+
if is_ready != false
|
|
75
|
+
raise "Unexpected result from #ready? (expected `true`, `false` or `[false, {...}]`): [#{is_ready.inspect}, #{new_return_value.inspect}]"
|
|
76
|
+
else
|
|
77
|
+
new_return_value
|
|
78
|
+
end
|
|
74
79
|
end
|
|
75
80
|
|
|
76
|
-
if
|
|
81
|
+
if is_ready
|
|
82
|
+
begin
|
|
83
|
+
is_authed, new_return_value = authorized?(**@prepared_arguments)
|
|
84
|
+
rescue GraphQL::UnauthorizedError => err
|
|
85
|
+
new_return_value = q.schema.unauthorized_object(err)
|
|
86
|
+
is_authed = true # the error was handled
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if runner.resolves_lazies && runner.schema.lazy?(is_authed)
|
|
77
91
|
is_authed, new_return_value = runner.schema.sync_lazy(is_authed)
|
|
78
92
|
end
|
|
79
93
|
|
|
80
94
|
result = if is_authed
|
|
81
95
|
Schema::Validator.validate!(self.class.validators, object, context, @prepared_arguments, as: @field)
|
|
82
|
-
if q.subscription? && @field.owner == context.schema.subscription
|
|
83
|
-
# This needs to use arguments without `loads:`
|
|
84
|
-
@original_arguments = @field_resolve_step.coerce_arguments(@field, @field_resolve_step.ast_node.arguments, false)
|
|
85
|
-
end
|
|
86
96
|
call_resolve(@prepared_arguments)
|
|
87
97
|
elsif new_return_value.nil?
|
|
88
98
|
err = UnauthorizedFieldError.new(object: object, type: @field_resolve_step.parent_type, context: context, field: @field)
|
|
@@ -93,7 +103,13 @@ module GraphQL
|
|
|
93
103
|
q = context.query
|
|
94
104
|
q.current_trace.end_execute_field(field, @prepared_arguments, trace_objs, q, [result])
|
|
95
105
|
exec_result[exec_index] = result
|
|
96
|
-
rescue
|
|
106
|
+
rescue GraphQL::UnauthorizedError => auth_err
|
|
107
|
+
exec_result[exec_index] = begin
|
|
108
|
+
context.schema.unauthorized_object(auth_err)
|
|
109
|
+
rescue GraphQL::ExecutionError => exec_err
|
|
110
|
+
exec_err
|
|
111
|
+
end
|
|
112
|
+
rescue GraphQL::RuntimeError => err
|
|
97
113
|
exec_result[exec_index] = err
|
|
98
114
|
rescue StandardError => stderr
|
|
99
115
|
exec_result[exec_index] = begin
|
|
@@ -30,14 +30,47 @@ module GraphQL
|
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
# @api private
|
|
34
|
+
def call_resolve(args_hash)
|
|
35
|
+
if @field_resolve_step.nil?
|
|
36
|
+
super
|
|
37
|
+
else
|
|
38
|
+
context.namespace(:subscriptions)[:update_event] = event
|
|
39
|
+
result = nil
|
|
40
|
+
unsubscribed = true
|
|
41
|
+
unsubscribed_result = nil
|
|
42
|
+
begin
|
|
43
|
+
result = super
|
|
44
|
+
unsubscribed = false
|
|
45
|
+
rescue EarlyUnsubscribe => err
|
|
46
|
+
unsubscribed_result = err.unsubscribed_result
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if unsubscribed
|
|
51
|
+
if unsubscribed_result
|
|
52
|
+
context.namespace(:subscriptions)[:final_update] = true
|
|
53
|
+
unsubscribed_result
|
|
54
|
+
else
|
|
55
|
+
context.skip
|
|
56
|
+
end
|
|
57
|
+
else
|
|
58
|
+
result
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
33
63
|
# @api private
|
|
34
64
|
def resolve_with_support(**args)
|
|
35
65
|
@original_arguments = args # before `loads:` have been run
|
|
36
66
|
result = nil
|
|
37
67
|
unsubscribed = true
|
|
38
|
-
unsubscribed_result =
|
|
68
|
+
unsubscribed_result = nil
|
|
69
|
+
begin
|
|
39
70
|
result = super
|
|
40
71
|
unsubscribed = false
|
|
72
|
+
rescue EarlyUnsubscribe => err
|
|
73
|
+
unsubscribed_result = err.unsubscribed_result
|
|
41
74
|
end
|
|
42
75
|
|
|
43
76
|
|
|
@@ -114,7 +147,13 @@ module GraphQL
|
|
|
114
147
|
# @return [void]
|
|
115
148
|
def unsubscribe(update_value = nil)
|
|
116
149
|
context.namespace(:subscriptions)[:unsubscribed] = true
|
|
117
|
-
|
|
150
|
+
err = EarlyUnsubscribe.new
|
|
151
|
+
err.unsubscribed_result = update_value
|
|
152
|
+
raise err
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
class EarlyUnsubscribe < GraphQL::RuntimeError
|
|
156
|
+
attr_accessor :unsubscribed_result
|
|
118
157
|
end
|
|
119
158
|
|
|
120
159
|
# Call this method to provide a new subscription_scope; OR
|
|
@@ -187,12 +226,18 @@ module GraphQL
|
|
|
187
226
|
|
|
188
227
|
# @return [Subscriptions::Event] This object is used as a representation of this subscription for the backend
|
|
189
228
|
def event
|
|
190
|
-
@event ||=
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
229
|
+
@event ||= begin
|
|
230
|
+
if @original_arguments.nil? && @field_resolve_step
|
|
231
|
+
@original_arguments, _errors = @field_resolve_step.arguments_without_loads
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
Subscriptions::Event.new(
|
|
235
|
+
name: field.name,
|
|
236
|
+
arguments: @original_arguments,
|
|
237
|
+
context: context,
|
|
238
|
+
field: field,
|
|
239
|
+
)
|
|
240
|
+
end
|
|
196
241
|
end
|
|
197
242
|
end
|
|
198
243
|
end
|
|
@@ -68,7 +68,7 @@ module GraphQL
|
|
|
68
68
|
super
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
def
|
|
71
|
+
def begin_execute_field(field, _arguments, _objects, query)
|
|
72
72
|
timeout_state = query.context.namespace(@timeout).fetch(:state)
|
|
73
73
|
# If the `:state` is `false`, then `max_seconds(query)` opted out of timeout for this query.
|
|
74
74
|
if timeout_state == false
|
|
@@ -84,7 +84,7 @@ module GraphQL
|
|
|
84
84
|
|
|
85
85
|
# `handle_timeout` may have set this to be `false`
|
|
86
86
|
if timeout_state != false
|
|
87
|
-
error
|
|
87
|
+
raise error
|
|
88
88
|
else
|
|
89
89
|
super
|
|
90
90
|
end
|
|
@@ -8,7 +8,7 @@ module GraphQL
|
|
|
8
8
|
# @example Require a non-empty string for an argument
|
|
9
9
|
# argument :name, String, required: true, validate: { allow_blank: false }
|
|
10
10
|
class AllowBlankValidator < Validator
|
|
11
|
-
def initialize(allow_blank_positional, allow_blank: nil, message: "%{validated} can't be blank", **default_options)
|
|
11
|
+
def initialize(allow_blank_positional = nil, allow_blank: nil, message: "%{validated} can't be blank", **default_options)
|
|
12
12
|
@message = message
|
|
13
13
|
super(**default_options)
|
|
14
14
|
@allow_blank = allow_blank.nil? ? allow_blank_positional : allow_blank
|
|
@@ -16,10 +16,10 @@ module GraphQL
|
|
|
16
16
|
|
|
17
17
|
def validate(_object, _context, value)
|
|
18
18
|
if value.respond_to?(:blank?) && value.blank?
|
|
19
|
-
if (value.nil? && @allow_null) || @allow_blank
|
|
19
|
+
if (value.nil? && validation_parameter(@allow_null)) || validation_parameter(@allow_blank)
|
|
20
20
|
# pass
|
|
21
21
|
else
|
|
22
|
-
@message
|
|
22
|
+
validation_parameter(@message)
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
end
|
|
@@ -9,15 +9,15 @@ module GraphQL
|
|
|
9
9
|
# argument :name, String, required: false, validates: { allow_null: false }
|
|
10
10
|
class AllowNullValidator < Validator
|
|
11
11
|
MESSAGE = "%{validated} can't be null"
|
|
12
|
-
def initialize(allow_null_positional, allow_null: nil, message: MESSAGE, **default_options)
|
|
12
|
+
def initialize(allow_null_positional = nil, allow_null: nil, message: MESSAGE, **default_options)
|
|
13
13
|
@message = message
|
|
14
14
|
super(**default_options)
|
|
15
15
|
@allow_null = allow_null.nil? ? allow_null_positional : allow_null
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def validate(_object, _context, value)
|
|
19
|
-
if value.nil? &&
|
|
20
|
-
@message
|
|
19
|
+
if value.nil? && !validation_parameter(@allow_null)
|
|
20
|
+
validation_parameter(@message)
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
end
|
|
@@ -23,8 +23,8 @@ module GraphQL
|
|
|
23
23
|
def validate(_object, _context, value)
|
|
24
24
|
if permitted_empty_value?(value)
|
|
25
25
|
# pass
|
|
26
|
-
elsif @in_list.include?(value)
|
|
27
|
-
@message
|
|
26
|
+
elsif validation_parameter(@in_list).include?(value)
|
|
27
|
+
validation_parameter(@message)
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
end
|
|
@@ -37,9 +37,9 @@ module GraphQL
|
|
|
37
37
|
if permitted_empty_value?(value)
|
|
38
38
|
# Do nothing
|
|
39
39
|
elsif value.nil? ||
|
|
40
|
-
(@with_pattern && !value.match?(@with_pattern)) ||
|
|
41
|
-
(@without_pattern && value.match?(@without_pattern))
|
|
42
|
-
@message
|
|
40
|
+
(@with_pattern && !value.match?(validation_parameter(@with_pattern))) ||
|
|
41
|
+
(@without_pattern && value.match?(validation_parameter(@without_pattern)))
|
|
42
|
+
validation_parameter(@message)
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -25,8 +25,8 @@ module GraphQL
|
|
|
25
25
|
def validate(_object, _context, value)
|
|
26
26
|
if permitted_empty_value?(value)
|
|
27
27
|
# pass
|
|
28
|
-
elsif
|
|
29
|
-
@message
|
|
28
|
+
elsif !validation_parameter(@in_list).include?(value)
|
|
29
|
+
validation_parameter(@message)
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -45,12 +45,12 @@ module GraphQL
|
|
|
45
45
|
def validate(_object, _context, value)
|
|
46
46
|
return if permitted_empty_value?(value) # pass in this case
|
|
47
47
|
length = value.nil? ? 0 : value.length
|
|
48
|
-
if @maximum && length >
|
|
49
|
-
partial_format(@too_long, { count:
|
|
50
|
-
elsif @minimum && length <
|
|
51
|
-
partial_format(@too_short, { count:
|
|
52
|
-
elsif @is && length !=
|
|
53
|
-
partial_format(@wrong_length, { count:
|
|
48
|
+
if (current_max = validation_parameter(@maximum)) && length > current_max
|
|
49
|
+
partial_format(validation_parameter(@too_long), { count: current_max })
|
|
50
|
+
elsif (current_min = validation_parameter(@minimum)) && length < current_min
|
|
51
|
+
partial_format(validation_parameter(@too_short), { count: current_min })
|
|
52
|
+
elsif (current_is = validation_parameter(@is)) && length != current_is
|
|
53
|
+
partial_format(validation_parameter(@wrong_length), { count: current_is })
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
end
|
|
@@ -55,25 +55,25 @@ module GraphQL
|
|
|
55
55
|
if permitted_empty_value?(value)
|
|
56
56
|
# pass in this case
|
|
57
57
|
elsif value.nil? # @allow_null is handled in the parent class
|
|
58
|
-
@null_message
|
|
59
|
-
elsif @greater_than && value <=
|
|
60
|
-
partial_format(@message, { comparison: "greater than", target:
|
|
61
|
-
elsif @greater_than_or_equal_to && value <
|
|
62
|
-
partial_format(@message, { comparison: "greater than or equal to", target:
|
|
63
|
-
elsif @less_than && value >=
|
|
64
|
-
partial_format(@message, { comparison: "less than", target:
|
|
65
|
-
elsif @less_than_or_equal_to && value >
|
|
66
|
-
partial_format(@message, { comparison: "less than or equal to", target:
|
|
67
|
-
elsif @equal_to && value !=
|
|
68
|
-
partial_format(@message, { comparison: "equal to", target:
|
|
69
|
-
elsif @other_than && value ==
|
|
70
|
-
partial_format(@message, { comparison: "something other than", target:
|
|
71
|
-
elsif @even && !value.even?
|
|
72
|
-
(partial_format(@message, { comparison: "even", target: "" })).strip
|
|
73
|
-
elsif @odd && !value.odd?
|
|
74
|
-
(partial_format(@message, { comparison: "odd", target: "" })).strip
|
|
75
|
-
elsif @within &&
|
|
76
|
-
partial_format(@message, { comparison: "within", target:
|
|
58
|
+
validation_parameter(@null_message)
|
|
59
|
+
elsif (current_greater_than = validation_parameter(@greater_than)) && value <= current_greater_than
|
|
60
|
+
partial_format(validation_parameter(@message), { comparison: "greater than", target: current_greater_than })
|
|
61
|
+
elsif (current_greater_than_or_equal_to = validation_parameter(@greater_than_or_equal_to)) && value < current_greater_than_or_equal_to
|
|
62
|
+
partial_format(validation_parameter(@message), { comparison: "greater than or equal to", target: current_greater_than_or_equal_to })
|
|
63
|
+
elsif (current_less_than = validation_parameter(@less_than)) && value >= current_less_than
|
|
64
|
+
partial_format(validation_parameter(@message), { comparison: "less than", target: current_less_than })
|
|
65
|
+
elsif (current_less_than_or_equal_to = validation_parameter(@less_than_or_equal_to)) && value > current_less_than_or_equal_to
|
|
66
|
+
partial_format(validation_parameter(@message), { comparison: "less than or equal to", target: current_less_than_or_equal_to })
|
|
67
|
+
elsif (current_equal_to = validation_parameter(@equal_to)) && value != current_equal_to
|
|
68
|
+
partial_format(validation_parameter(@message), { comparison: "equal to", target: current_equal_to })
|
|
69
|
+
elsif (current_other_than = validation_parameter(@other_than)) && value == current_other_than
|
|
70
|
+
partial_format(validation_parameter(@message), { comparison: "something other than", target: current_other_than })
|
|
71
|
+
elsif validation_parameter(@even) && !value.even?
|
|
72
|
+
(partial_format(validation_parameter(@message), { comparison: "even", target: "" })).strip
|
|
73
|
+
elsif validation_parameter(@odd) && !value.odd?
|
|
74
|
+
(partial_format(validation_parameter(@message), { comparison: "odd", target: "" })).strip
|
|
75
|
+
elsif (current_within = validation_parameter(@within)) && !current_within.include?(value)
|
|
76
|
+
partial_format(validation_parameter(@message), { comparison: "within", target: current_within })
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
end
|
|
@@ -67,7 +67,8 @@ module GraphQL
|
|
|
67
67
|
no_visible_conditions = true
|
|
68
68
|
|
|
69
69
|
if !value.nil?
|
|
70
|
-
@one_of.each do |one_of_condition|
|
|
70
|
+
validation_parameter(@one_of).each do |one_of_condition|
|
|
71
|
+
one_of_condition = validation_parameter(one_of_condition)
|
|
71
72
|
case one_of_condition
|
|
72
73
|
when Symbol
|
|
73
74
|
if no_visible_conditions && visible_keywords.include?(one_of_condition)
|
|
@@ -108,7 +109,7 @@ module GraphQL
|
|
|
108
109
|
end
|
|
109
110
|
|
|
110
111
|
if no_visible_conditions
|
|
111
|
-
if @allow_all_hidden
|
|
112
|
+
if validation_parameter(@allow_all_hidden)
|
|
112
113
|
return nil
|
|
113
114
|
else
|
|
114
115
|
raise GraphQL::Error, <<~ERR
|
|
@@ -122,7 +123,7 @@ module GraphQL
|
|
|
122
123
|
if fully_matched_conditions == 1 && partially_matched_conditions == 0
|
|
123
124
|
nil # OK
|
|
124
125
|
else
|
|
125
|
-
@message || build_message(context)
|
|
126
|
+
validation_parameter(@message) || build_message(context)
|
|
126
127
|
end
|
|
127
128
|
end
|
|
128
129
|
|
|
@@ -130,8 +131,9 @@ module GraphQL
|
|
|
130
131
|
argument_definitions = context.types.arguments(@validated)
|
|
131
132
|
|
|
132
133
|
required_names = @one_of.map do |arg_keyword|
|
|
134
|
+
arg_keyword = validation_parameter(arg_keyword)
|
|
133
135
|
if arg_keyword.is_a?(Array)
|
|
134
|
-
names = arg_keyword.map { |arg| arg_keyword_to_graphql_name(argument_definitions, arg) }
|
|
136
|
+
names = arg_keyword.map { |arg| arg_keyword_to_graphql_name(argument_definitions, validation_parameter(arg)) }
|
|
135
137
|
names.compact! # hidden arguments are `nil`
|
|
136
138
|
"(" + names.join(" and ") + ")"
|
|
137
139
|
else
|
|
@@ -34,6 +34,15 @@ module GraphQL
|
|
|
34
34
|
string
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
# @return [Object] The current value to use for validation, based on `config_value` from configuration time. If a Proc is given, this calls it and returns it.
|
|
38
|
+
def validation_parameter(config_value)
|
|
39
|
+
if config_value.is_a?(Proc)
|
|
40
|
+
config_value.call
|
|
41
|
+
else
|
|
42
|
+
config_value
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
37
46
|
# @return [Boolean] `true` if `value` is `nil` and this validator has `allow_null: true` or if value is `.blank?` and this validator has `allow_blank: true`
|
|
38
47
|
def permitted_empty_value?(value)
|
|
39
48
|
(value.nil? && @allow_null) ||
|
|
@@ -290,11 +290,13 @@ module GraphQL
|
|
|
290
290
|
end
|
|
291
291
|
# Lots more to do here
|
|
292
292
|
end
|
|
293
|
-
@schema.
|
|
294
|
-
|
|
295
|
-
|
|
293
|
+
if @schema.query
|
|
294
|
+
@schema.introspection_system.entry_points.each do |f|
|
|
295
|
+
arguments(f).each do |arg|
|
|
296
|
+
argument(f, arg.graphql_name)
|
|
297
|
+
end
|
|
298
|
+
field(@schema.query, f.graphql_name)
|
|
296
299
|
end
|
|
297
|
-
field(@schema.query, f.graphql_name)
|
|
298
300
|
end
|
|
299
301
|
@schema.introspection_system.dynamic_fields.each do |f|
|
|
300
302
|
arguments(f).each do |arg|
|
|
@@ -102,7 +102,7 @@ module GraphQL
|
|
|
102
102
|
|
|
103
103
|
missed_late_types_streak = 0
|
|
104
104
|
while (owner, late_type = @late_bound_types.shift)
|
|
105
|
-
if (late_type.is_a?(String) && (type = Member::BuildType.constantize(
|
|
105
|
+
if (late_type.is_a?(String) && (type = Member::BuildType.constantize(late_type))) ||
|
|
106
106
|
(late_type.is_a?(LateBoundType) && (type = @visited_types.find { |t| t.graphql_name == late_type.graphql_name }))
|
|
107
107
|
missed_late_types_streak = 0 # might succeed next round
|
|
108
108
|
update_type_owner(owner, type)
|
|
@@ -8,11 +8,17 @@ module GraphQL
|
|
|
8
8
|
# Use this plugin to make some parts of your schema hidden from some viewers.
|
|
9
9
|
#
|
|
10
10
|
class Visibility
|
|
11
|
+
class TypeConfigurationError < GraphQL::Error
|
|
12
|
+
def initialize(config_message, config_str)
|
|
13
|
+
message = "GraphQL::Schema::Visibility already preloaded, but #{config_message} added to the schema. Move this `#{config_str}` configuration above `use(GraphQL::Schema::Visibility)"
|
|
14
|
+
super(message)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
11
17
|
# @param schema [Class<GraphQL::Schema>]
|
|
12
18
|
# @param profiles [Hash<Symbol => Hash>] A hash of `name => context` pairs for preloading visibility profiles
|
|
13
19
|
# @param preload [Boolean] if `true`, load the default schema profile and all named profiles immediately (defaults to `true` for `Rails.env.production?` and `Rails.env.staging?`)
|
|
14
20
|
# @param migration_errors [Boolean] if `true`, raise an error when `Visibility` and `Warden` return different results
|
|
15
|
-
def self.use(schema, dynamic: false, profiles: EmptyObjects::EMPTY_HASH, preload: (defined?(Rails.env) ? (Rails.env.production? || Rails.env.staging?) :
|
|
21
|
+
def self.use(schema, dynamic: false, profiles: EmptyObjects::EMPTY_HASH, preload: (defined?(Rails.env) ? (Rails.env.production? || Rails.env.staging? || nil) : false), migration_errors: false)
|
|
16
22
|
profiles&.each { |name, ctx|
|
|
17
23
|
ctx[:visibility_profile] = name
|
|
18
24
|
ctx.freeze
|
|
@@ -20,7 +26,7 @@ module GraphQL
|
|
|
20
26
|
schema.visibility = self.new(schema, dynamic: dynamic, preload: preload, profiles: profiles, migration_errors: migration_errors)
|
|
21
27
|
end
|
|
22
28
|
|
|
23
|
-
def initialize(schema, dynamic:, preload:, profiles:, migration_errors:)
|
|
29
|
+
def initialize(schema, dynamic:, preload:, profiles:, migration_errors:, configuration_inherited: false)
|
|
24
30
|
@schema = schema
|
|
25
31
|
schema.use_visibility_profile = true
|
|
26
32
|
schema.visibility_profile_class = if migration_errors
|
|
@@ -40,6 +46,7 @@ module GraphQL
|
|
|
40
46
|
@types = nil
|
|
41
47
|
@all_references = nil
|
|
42
48
|
@loaded_all = false
|
|
49
|
+
@configuration_inherited = configuration_inherited
|
|
43
50
|
if preload
|
|
44
51
|
self.preload
|
|
45
52
|
end
|
|
@@ -94,6 +101,7 @@ module GraphQL
|
|
|
94
101
|
# Root types may have been nil:
|
|
95
102
|
types_to_visit.compact!
|
|
96
103
|
ensure_all_loaded(types_to_visit)
|
|
104
|
+
@cached_profiles.clear
|
|
97
105
|
@profiles.each do |profile_name, example_ctx|
|
|
98
106
|
prof = profile_for(example_ctx)
|
|
99
107
|
prof.preload
|
|
@@ -102,41 +110,27 @@ module GraphQL
|
|
|
102
110
|
|
|
103
111
|
# @api private
|
|
104
112
|
def query_configured(query_type)
|
|
105
|
-
|
|
106
|
-
ensure_all_loaded([query_type])
|
|
107
|
-
end
|
|
113
|
+
require_if_preloaded("a query type was", "query(...)")
|
|
108
114
|
end
|
|
109
115
|
|
|
110
116
|
# @api private
|
|
111
117
|
def mutation_configured(mutation_type)
|
|
112
|
-
|
|
113
|
-
ensure_all_loaded([mutation_type])
|
|
114
|
-
end
|
|
118
|
+
require_if_preloaded("a mutation type was", "mutation(...)")
|
|
115
119
|
end
|
|
116
120
|
|
|
117
121
|
# @api private
|
|
118
122
|
def subscription_configured(subscription_type)
|
|
119
|
-
|
|
120
|
-
ensure_all_loaded([subscription_type])
|
|
121
|
-
end
|
|
123
|
+
require_if_preloaded("a mutation type was", "subscription(...)")
|
|
122
124
|
end
|
|
123
125
|
|
|
124
126
|
# @api private
|
|
125
127
|
def orphan_types_configured(orphan_types)
|
|
126
|
-
|
|
127
|
-
ensure_all_loaded(orphan_types)
|
|
128
|
-
end
|
|
128
|
+
require_if_preloaded("orphan types were", "orphan_types(...)")
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
# @api private
|
|
132
132
|
def introspection_system_configured(introspection_system)
|
|
133
|
-
|
|
134
|
-
introspection_types = [
|
|
135
|
-
*@schema.introspection_system.types.values,
|
|
136
|
-
*@schema.introspection_system.entry_points.map { |ep| ep.type.unwrap },
|
|
137
|
-
]
|
|
138
|
-
ensure_all_loaded(introspection_types)
|
|
139
|
-
end
|
|
133
|
+
require_if_preloaded("custom introspection was", "introspection(...)")
|
|
140
134
|
end
|
|
141
135
|
|
|
142
136
|
# Make another Visibility for `schema` based on this one
|
|
@@ -148,7 +142,8 @@ module GraphQL
|
|
|
148
142
|
dynamic: @dynamic,
|
|
149
143
|
preload: @preload,
|
|
150
144
|
profiles: @profiles,
|
|
151
|
-
migration_errors: @migration_errors
|
|
145
|
+
migration_errors: @migration_errors,
|
|
146
|
+
configuration_inherited: true,
|
|
152
147
|
)
|
|
153
148
|
end
|
|
154
149
|
|
|
@@ -196,6 +191,19 @@ module GraphQL
|
|
|
196
191
|
|
|
197
192
|
private
|
|
198
193
|
|
|
194
|
+
def require_if_preloaded(config_message, config_code)
|
|
195
|
+
case @preload
|
|
196
|
+
when false
|
|
197
|
+
# Rails.env wasn't defined, so this won't try to preload unless manually set to true
|
|
198
|
+
when true, nil
|
|
199
|
+
if @configuration_inherited
|
|
200
|
+
preload
|
|
201
|
+
else
|
|
202
|
+
raise TypeConfigurationError.new(config_message, config_code)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
199
207
|
def ensure_all_loaded(types_to_visit)
|
|
200
208
|
while (type = types_to_visit.shift)
|
|
201
209
|
if type.kind.fields? && @preloaded_types.add?(type)
|