graphql 1.13.12 → 1.13.19
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/execution/interpreter/runtime.rb +4 -4
- data/lib/graphql/introspection/directive_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +2 -2
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/query/input_validation_result.rb +9 -0
- data/lib/graphql/query/validation_pipeline.rb +2 -3
- data/lib/graphql/query/variable_validation_error.rb +2 -2
- data/lib/graphql/query/variables.rb +30 -3
- data/lib/graphql/query.rb +0 -1
- data/lib/graphql/schema/directive.rb +1 -1
- data/lib/graphql/schema/enum.rb +1 -2
- data/lib/graphql/schema/field.rb +37 -20
- data/lib/graphql/schema/input_object.rb +1 -2
- data/lib/graphql/schema/list.rb +18 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +2 -2
- data/lib/graphql/schema/member/has_fields.rb +1 -1
- data/lib/graphql/schema/member/has_interfaces.rb +11 -1
- data/lib/graphql/schema/member/validates_input.rb +2 -2
- data/lib/graphql/schema/non_null.rb +2 -2
- data/lib/graphql/schema/scalar.rb +1 -1
- data/lib/graphql/schema/warden.rb +11 -2
- data/lib/graphql/tracing/data_dog_tracing.rb +19 -2
- data/lib/graphql/tracing/platform_tracing.rb +9 -4
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c21327429549138738debab2d522197133548eb4b275a5f67086154e08469149
|
4
|
+
data.tar.gz: ec61107f4f45aaf1de25c6674d7fcf3b8e19b1245fdbf2a1bd1b0f7f1dd9b0aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b56c3aaa86b6d758b53d49a7906de483375c54f40db9126b96d791f41c7bba6407d9b59205a4d47215cef1391cd5ebbc03d5eb76825747cbfc1d0f6baf1f0ef
|
7
|
+
data.tar.gz: 7f7cb3b2e4fa8c26b355ea4adf01803ab32e2d97036475469071e2cf67d06431ab0486f0daf8ab28433deb95bb8642ea0a2b52739abe6d0ad06bb22b4fdcb2cc
|
@@ -400,6 +400,7 @@ module GraphQL
|
|
400
400
|
raise "Invariant: no field for #{owner_type}.#{field_name}"
|
401
401
|
end
|
402
402
|
end
|
403
|
+
|
403
404
|
return_type = field_defn.type
|
404
405
|
|
405
406
|
next_path = path.dup
|
@@ -425,18 +426,17 @@ module GraphQL
|
|
425
426
|
total_args_count = field_defn.arguments(context).size
|
426
427
|
if total_args_count == 0
|
427
428
|
resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
|
428
|
-
evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
|
429
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
|
429
430
|
else
|
430
431
|
# TODO remove all arguments(...) usages?
|
431
432
|
@query.arguments_cache.dataload_for(ast_node, field_defn, object) do |resolved_arguments|
|
432
|
-
evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
|
433
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
|
433
434
|
end
|
434
435
|
end
|
435
436
|
end
|
436
437
|
|
437
|
-
def evaluate_selection_with_args(arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selection_result, parent_object) # rubocop:disable Metrics/ParameterLists
|
438
|
+
def evaluate_selection_with_args(arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selection_result, parent_object, return_type) # rubocop:disable Metrics/ParameterLists
|
438
439
|
context.scoped_context = scoped_context
|
439
|
-
return_type = field_defn.type
|
440
440
|
after_lazy(arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
|
441
441
|
if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
|
442
442
|
continue_value(next_path, resolved_arguments, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
|
@@ -11,8 +11,8 @@ module GraphQL
|
|
11
11
|
"to the executor."
|
12
12
|
field :name, String, null: false, method: :graphql_name
|
13
13
|
field :description, String
|
14
|
-
field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false
|
15
|
-
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
|
14
|
+
field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false, scope: false
|
15
|
+
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
|
16
16
|
argument :include_deprecated, Boolean, required: false, default_value: false
|
17
17
|
end
|
18
18
|
field :on_operation, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_operation?
|
@@ -7,7 +7,7 @@ module GraphQL
|
|
7
7
|
"a name, potentially a list of arguments, and a return type."
|
8
8
|
field :name, String, null: false
|
9
9
|
field :description, String
|
10
|
-
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
|
10
|
+
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
|
11
11
|
argument :include_deprecated, Boolean, required: false, default_value: false
|
12
12
|
end
|
13
13
|
field :type, GraphQL::Schema::LateBoundType.new("__Type"), null: false
|
@@ -8,11 +8,11 @@ module GraphQL
|
|
8
8
|
"available types and directives on the server, as well as the entry points for "\
|
9
9
|
"query, mutation, and subscription operations."
|
10
10
|
|
11
|
-
field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false
|
11
|
+
field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false, scope: false
|
12
12
|
field :query_type, GraphQL::Schema::LateBoundType.new("__Type"), "The type that query operations will be rooted at.", null: false
|
13
13
|
field :mutation_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at."
|
14
14
|
field :subscription_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at."
|
15
|
-
field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false
|
15
|
+
field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false, scope: false
|
16
16
|
field :description, String, resolver_method: :schema_description
|
17
17
|
|
18
18
|
def schema_description
|
@@ -14,15 +14,15 @@ module GraphQL
|
|
14
14
|
field :kind, GraphQL::Schema::LateBoundType.new("__TypeKind"), null: false
|
15
15
|
field :name, String, method: :graphql_name
|
16
16
|
field :description, String
|
17
|
-
field :fields, [GraphQL::Schema::LateBoundType.new("__Field")] do
|
17
|
+
field :fields, [GraphQL::Schema::LateBoundType.new("__Field")], scope: false do
|
18
18
|
argument :include_deprecated, Boolean, required: false, default_value: false
|
19
19
|
end
|
20
|
-
field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")]
|
21
|
-
field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")]
|
22
|
-
field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")] do
|
20
|
+
field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
|
21
|
+
field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
|
22
|
+
field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")], scope: false do
|
23
23
|
argument :include_deprecated, Boolean, required: false, default_value: false
|
24
24
|
end
|
25
|
-
field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")] do
|
25
|
+
field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], scope: false do
|
26
26
|
argument :include_deprecated, Boolean, required: false, default_value: false
|
27
27
|
end
|
28
28
|
field :of_type, GraphQL::Schema::LateBoundType.new("__Type")
|
@@ -4,6 +4,12 @@ module GraphQL
|
|
4
4
|
class InputValidationResult
|
5
5
|
attr_accessor :problems
|
6
6
|
|
7
|
+
def self.from_problem(explanation, path = nil, extensions: nil, message: nil)
|
8
|
+
result = self.new
|
9
|
+
result.add_problem(explanation, path, extensions: extensions, message: message)
|
10
|
+
result
|
11
|
+
end
|
12
|
+
|
7
13
|
def initialize(valid: true, problems: nil)
|
8
14
|
@valid = valid
|
9
15
|
@problems = problems
|
@@ -38,6 +44,9 @@ module GraphQL
|
|
38
44
|
# It could have been explicitly set on inner_result (if it had no problems)
|
39
45
|
@valid = false
|
40
46
|
end
|
47
|
+
|
48
|
+
VALID = self.new
|
49
|
+
VALID.freeze
|
41
50
|
end
|
42
51
|
end
|
43
52
|
end
|
@@ -16,10 +16,9 @@ module GraphQL
|
|
16
16
|
class ValidationPipeline
|
17
17
|
attr_reader :max_depth, :max_complexity
|
18
18
|
|
19
|
-
def initialize(query:,
|
19
|
+
def initialize(query:, parse_error:, operation_name_error:, max_depth:, max_complexity:)
|
20
20
|
@validation_errors = []
|
21
21
|
@internal_representation = nil
|
22
|
-
@validate = validate
|
23
22
|
@parse_error = parse_error
|
24
23
|
@operation_name_error = operation_name_error
|
25
24
|
@query = query
|
@@ -72,7 +71,7 @@ module GraphQL
|
|
72
71
|
elsif @operation_name_error
|
73
72
|
@validation_errors << @operation_name_error
|
74
73
|
else
|
75
|
-
validation_result = @schema.static_validator.validate(@query, validate: @validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
|
74
|
+
validation_result = @schema.static_validator.validate(@query, validate: @query.validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
|
76
75
|
@validation_errors.concat(validation_result[:errors])
|
77
76
|
@internal_representation = validation_result[:irep]
|
78
77
|
|
@@ -4,11 +4,11 @@ module GraphQL
|
|
4
4
|
class VariableValidationError < GraphQL::ExecutionError
|
5
5
|
attr_accessor :value, :validation_result
|
6
6
|
|
7
|
-
def initialize(variable_ast, type, value, validation_result)
|
7
|
+
def initialize(variable_ast, type, value, validation_result, msg: nil)
|
8
8
|
@value = value
|
9
9
|
@validation_result = validation_result
|
10
10
|
|
11
|
-
msg
|
11
|
+
msg ||= "Variable $#{variable_ast.name} of type #{type.to_type_signature} was provided invalid value"
|
12
12
|
|
13
13
|
if problem_fields.any?
|
14
14
|
msg += " for #{problem_fields.join(", ")}"
|
@@ -17,6 +17,10 @@ module GraphQL
|
|
17
17
|
@provided_variables = GraphQL::Argument.deep_stringify(provided_variables)
|
18
18
|
@errors = []
|
19
19
|
@storage = ast_variables.each_with_object({}) do |ast_variable, memo|
|
20
|
+
if schema.validate_max_errors && schema.validate_max_errors <= @errors.count
|
21
|
+
add_max_errors_reached_message
|
22
|
+
break
|
23
|
+
end
|
20
24
|
# Find the right value for this variable:
|
21
25
|
# - First, use the value provided at runtime
|
22
26
|
# - Then, fall back to the default value from the query string
|
@@ -29,8 +33,9 @@ module GraphQL
|
|
29
33
|
default_value = ast_variable.default_value
|
30
34
|
provided_value = @provided_variables[variable_name]
|
31
35
|
value_was_provided = @provided_variables.key?(variable_name)
|
36
|
+
max_errors = schema.validate_max_errors - @errors.count if schema.validate_max_errors
|
32
37
|
begin
|
33
|
-
validation_result = variable_type.validate_input(provided_value, ctx)
|
38
|
+
validation_result = variable_type.validate_input(provided_value, ctx, max_errors: max_errors)
|
34
39
|
if validation_result.valid?
|
35
40
|
if value_was_provided
|
36
41
|
# Add the variable if a value was provided
|
@@ -61,8 +66,7 @@ module GraphQL
|
|
61
66
|
# like InputValidationResults generated by validate_non_null_input but unfortunately we don't
|
62
67
|
# have this information available in the coerce_input call chain. Note this path is the path
|
63
68
|
# that appears under errors.extensions.problems.path and NOT the result path under errors.path.
|
64
|
-
validation_result = GraphQL::Query::InputValidationResult.
|
65
|
-
validation_result.add_problem(ex.message)
|
69
|
+
validation_result = GraphQL::Query::InputValidationResult.from_problem(ex.message)
|
66
70
|
end
|
67
71
|
|
68
72
|
if !validation_result.valid?
|
@@ -73,6 +77,29 @@ module GraphQL
|
|
73
77
|
end
|
74
78
|
|
75
79
|
def_delegators :@storage, :length, :key?, :[], :fetch, :to_h
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def deep_stringify(val)
|
84
|
+
case val
|
85
|
+
when Array
|
86
|
+
val.map { |v| deep_stringify(v) }
|
87
|
+
when Hash
|
88
|
+
new_val = {}
|
89
|
+
val.each do |k, v|
|
90
|
+
new_val[k.to_s] = deep_stringify(v)
|
91
|
+
end
|
92
|
+
new_val
|
93
|
+
else
|
94
|
+
val
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def add_max_errors_reached_message
|
99
|
+
message = "Too many errors processing variables, max validation error limit reached. Execution aborted"
|
100
|
+
validation_result = GraphQL::Query::InputValidationResult.from_problem(message)
|
101
|
+
errors << GraphQL::Query::VariableValidationError.new(nil, nil, nil, validation_result, msg: message)
|
102
|
+
end
|
76
103
|
end
|
77
104
|
end
|
78
105
|
end
|
data/lib/graphql/query.rb
CHANGED
data/lib/graphql/schema/enum.rb
CHANGED
@@ -139,9 +139,8 @@ module GraphQL
|
|
139
139
|
GraphQL::TypeKinds::ENUM
|
140
140
|
end
|
141
141
|
|
142
|
-
def validate_non_null_input(value_name, ctx)
|
142
|
+
def validate_non_null_input(value_name, ctx, max_errors: nil)
|
143
143
|
result = GraphQL::Query::InputValidationResult.new
|
144
|
-
|
145
144
|
allowed_values = ctx.warden.enum_values(self)
|
146
145
|
matching_value = allowed_values.find { |v| v.graphql_name == value_name }
|
147
146
|
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -176,6 +176,8 @@ module GraphQL
|
|
176
176
|
|
177
177
|
# @return Boolean
|
178
178
|
attr_reader :relay_node_field
|
179
|
+
# @return Boolean
|
180
|
+
attr_reader :relay_nodes_field
|
179
181
|
|
180
182
|
# @return [Boolean] Should we warn if this field's name conflicts with a built-in method?
|
181
183
|
def method_conflict_warning?
|
@@ -227,6 +229,7 @@ module GraphQL
|
|
227
229
|
end
|
228
230
|
@original_name = name
|
229
231
|
name_s = -name.to_s
|
232
|
+
|
230
233
|
@underscored_name = -Member::BuildType.underscore(name_s)
|
231
234
|
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
|
232
235
|
@description = description
|
@@ -256,6 +259,10 @@ module GraphQL
|
|
256
259
|
# TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
|
257
260
|
method_name = method || hash_key || name_s
|
258
261
|
@dig_keys = dig
|
262
|
+
if hash_key
|
263
|
+
@hash_key = hash_key
|
264
|
+
end
|
265
|
+
|
259
266
|
resolver_method ||= name_s.to_sym
|
260
267
|
|
261
268
|
@method_str = -method_name.to_s
|
@@ -471,7 +478,13 @@ module GraphQL
|
|
471
478
|
case defined_complexity
|
472
479
|
when Proc
|
473
480
|
arguments = query.arguments_for(nodes.first, self)
|
474
|
-
|
481
|
+
if arguments.is_a?(GraphQL::ExecutionError)
|
482
|
+
return child_complexity
|
483
|
+
elsif arguments.respond_to?(:keyword_arguments)
|
484
|
+
arguments = arguments.keyword_arguments
|
485
|
+
end
|
486
|
+
|
487
|
+
defined_complexity.call(query.context, arguments, child_complexity)
|
475
488
|
when Numeric
|
476
489
|
defined_complexity + child_complexity
|
477
490
|
else
|
@@ -638,27 +651,29 @@ module GraphQL
|
|
638
651
|
arg_values = args
|
639
652
|
using_arg_values = false
|
640
653
|
end
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
if
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
application_arg_value.
|
654
|
+
if args.size > 0
|
655
|
+
args = context.warden.arguments(self)
|
656
|
+
args.each do |arg|
|
657
|
+
arg_key = arg.keyword
|
658
|
+
if arg_values.key?(arg_key)
|
659
|
+
arg_value = arg_values[arg_key]
|
660
|
+
if using_arg_values
|
661
|
+
if arg_value.default_used?
|
662
|
+
# pass -- no auth required for default used
|
663
|
+
next
|
664
|
+
else
|
665
|
+
application_arg_value = arg_value.value
|
666
|
+
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
|
667
|
+
application_arg_value.keyword_arguments
|
668
|
+
end
|
654
669
|
end
|
670
|
+
else
|
671
|
+
application_arg_value = arg_value
|
655
672
|
end
|
656
|
-
else
|
657
|
-
application_arg_value = arg_value
|
658
|
-
end
|
659
673
|
|
660
|
-
|
661
|
-
|
674
|
+
if !arg.authorized?(object, application_arg_value, context)
|
675
|
+
return false
|
676
|
+
end
|
662
677
|
end
|
663
678
|
end
|
664
679
|
end
|
@@ -814,7 +829,7 @@ module GraphQL
|
|
814
829
|
# Find a way to resolve this field, checking:
|
815
830
|
#
|
816
831
|
# - A method on the type instance;
|
817
|
-
# - Hash keys, if the wrapped object is a hash
|
832
|
+
# - Hash keys, if the wrapped object is a hash or responds to `#[]`
|
818
833
|
# - A method on the wrapped object;
|
819
834
|
# - Or, raise not implemented.
|
820
835
|
#
|
@@ -836,6 +851,8 @@ module GraphQL
|
|
836
851
|
else
|
837
852
|
inner_object[@method_str]
|
838
853
|
end
|
854
|
+
elsif defined?(@hash_key) && obj.object.respond_to?(:[])
|
855
|
+
obj.object[@hash_key]
|
839
856
|
elsif obj.object.respond_to?(@method_sym)
|
840
857
|
method_to_call = @method_sym
|
841
858
|
method_receiver = obj.object
|
@@ -173,9 +173,8 @@ module GraphQL
|
|
173
173
|
# @api private
|
174
174
|
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object responding to `to_h` or `to_unsafe_h`."
|
175
175
|
|
176
|
-
def validate_non_null_input(input, ctx)
|
176
|
+
def validate_non_null_input(input, ctx, max_errors: nil)
|
177
177
|
result = GraphQL::Query::InputValidationResult.new
|
178
|
-
|
179
178
|
warden = ctx.warden
|
180
179
|
|
181
180
|
if input.is_a?(Array)
|
data/lib/graphql/schema/list.rb
CHANGED
@@ -51,15 +51,24 @@ module GraphQL
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
def validate_non_null_input(value, ctx)
|
54
|
+
def validate_non_null_input(value, ctx, max_errors: nil)
|
55
55
|
result = GraphQL::Query::InputValidationResult.new
|
56
56
|
ensure_array(value).each_with_index do |item, index|
|
57
57
|
item_result = of_type.validate_input(item, ctx)
|
58
|
-
|
58
|
+
unless item_result.valid?
|
59
|
+
if max_errors
|
60
|
+
if max_errors == 0
|
61
|
+
add_max_errros_reached_message(result)
|
62
|
+
break
|
63
|
+
end
|
64
|
+
|
65
|
+
max_errors -= 1
|
66
|
+
end
|
67
|
+
|
59
68
|
result.merge_result!(index, item_result)
|
60
69
|
end
|
61
70
|
end
|
62
|
-
result
|
71
|
+
result.valid? ? nil : result
|
63
72
|
end
|
64
73
|
|
65
74
|
private
|
@@ -72,6 +81,12 @@ module GraphQL
|
|
72
81
|
[value]
|
73
82
|
end
|
74
83
|
end
|
84
|
+
|
85
|
+
def add_max_errros_reached_message(result)
|
86
|
+
message = "Too many errors processing list variable, max validation error limit reached. Execution aborted"
|
87
|
+
item_result = GraphQL::Query::InputValidationResult.from_problem(message)
|
88
|
+
result.merge_result!(nil, item_result)
|
89
|
+
end
|
75
90
|
end
|
76
91
|
end
|
77
92
|
end
|
@@ -108,7 +108,7 @@ module GraphQL
|
|
108
108
|
@default_graphql_name ||= begin
|
109
109
|
raise GraphQL::RequiredImplementationMissingError, 'Anonymous class should declare a `graphql_name`' if name.nil?
|
110
110
|
|
111
|
-
name.split("::").last.sub(/Type\Z/, "")
|
111
|
+
-name.split("::").last.sub(/Type\Z/, "")
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
@@ -167,7 +167,7 @@ module GraphQL
|
|
167
167
|
# @return [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
|
168
168
|
def coerce_arguments(parent_object, values, context, &block)
|
169
169
|
# Cache this hash to avoid re-merging it
|
170
|
-
arg_defns =
|
170
|
+
arg_defns = context.warden.arguments(self)
|
171
171
|
total_args_count = arg_defns.size
|
172
172
|
|
173
173
|
finished_args = nil
|
@@ -181,7 +181,7 @@ module GraphQL
|
|
181
181
|
argument_values = {}
|
182
182
|
resolved_args_count = 0
|
183
183
|
raised_error = false
|
184
|
-
arg_defns.each do |
|
184
|
+
arg_defns.each do |arg_defn|
|
185
185
|
context.dataloader.append_job do
|
186
186
|
begin
|
187
187
|
arg_defn.coerce_into_values(parent_object, values, context, argument_values)
|
@@ -134,7 +134,7 @@ module GraphQL
|
|
134
134
|
if type.respond_to?(:kind) && type.kind.interface?
|
135
135
|
implements_this_interface = false
|
136
136
|
implementation_is_visible = false
|
137
|
-
interface_type_memberships.each do |tm|
|
137
|
+
warden.interface_type_memberships(self, context).each do |tm|
|
138
138
|
if tm.abstract_type == type
|
139
139
|
implements_this_interface ||= true
|
140
140
|
if warden.visible_type_membership?(tm, context)
|
@@ -57,7 +57,17 @@ module GraphQL
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def interface_type_memberships
|
60
|
-
|
60
|
+
own_tms = own_interface_type_memberships
|
61
|
+
if (self.is_a?(Class) && superclass.respond_to?(:interface_type_memberships))
|
62
|
+
inherited_tms = superclass.interface_type_memberships
|
63
|
+
if inherited_tms.size > 0
|
64
|
+
own_tms + inherited_tms
|
65
|
+
else
|
66
|
+
own_tms
|
67
|
+
end
|
68
|
+
else
|
69
|
+
own_tms
|
70
|
+
end
|
61
71
|
end
|
62
72
|
|
63
73
|
# param context [Query::Context] If omitted, skip filtering.
|
@@ -8,11 +8,11 @@ module GraphQL
|
|
8
8
|
validate_input(val, ctx).valid?
|
9
9
|
end
|
10
10
|
|
11
|
-
def validate_input(val, ctx)
|
11
|
+
def validate_input(val, ctx, max_errors: nil)
|
12
12
|
if val.nil?
|
13
13
|
GraphQL::Query::InputValidationResult.new
|
14
14
|
else
|
15
|
-
validate_non_null_input(val, ctx)
|
15
|
+
validate_non_null_input(val, ctx, max_errors: max_errors) || Query::InputValidationResult::VALID
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -37,13 +37,13 @@ module GraphQL
|
|
37
37
|
"#<#{self.class.name} @of_type=#{@of_type.inspect}>"
|
38
38
|
end
|
39
39
|
|
40
|
-
def validate_input(value, ctx)
|
40
|
+
def validate_input(value, ctx, max_errors: nil)
|
41
41
|
if value.nil?
|
42
42
|
result = GraphQL::Query::InputValidationResult.new
|
43
43
|
result.add_problem("Expected value to not be null")
|
44
44
|
result
|
45
45
|
else
|
46
|
-
of_type.validate_input(value, ctx)
|
46
|
+
of_type.validate_input(value, ctx, max_errors: max_errors)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -55,7 +55,7 @@ module GraphQL
|
|
55
55
|
@default_scalar ||= false
|
56
56
|
end
|
57
57
|
|
58
|
-
def validate_non_null_input(value, ctx)
|
58
|
+
def validate_non_null_input(value, ctx, max_errors: nil)
|
59
59
|
result = Query::InputValidationResult.new
|
60
60
|
coerced_result = begin
|
61
61
|
ctx.query.with_error_handling do
|
@@ -78,6 +78,8 @@ module GraphQL
|
|
78
78
|
def visible_type?(type, ctx); type.visible?(ctx); end
|
79
79
|
def visible_enum_value?(ev, ctx); ev.visible?(ctx); end
|
80
80
|
def visible_type_membership?(tm, ctx); tm.visible?(ctx); end
|
81
|
+
def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
|
82
|
+
def arguments(owner, ctx); owner.arguments(ctx); end
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
@@ -172,8 +174,8 @@ module GraphQL
|
|
172
174
|
|
173
175
|
# @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
|
174
176
|
# @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
|
175
|
-
def arguments(argument_owner)
|
176
|
-
@visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a) } }
|
177
|
+
def arguments(argument_owner, ctx = nil)
|
178
|
+
@visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a, @context) } }
|
177
179
|
@visible_arguments[argument_owner]
|
178
180
|
end
|
179
181
|
|
@@ -231,6 +233,13 @@ module GraphQL
|
|
231
233
|
visible?(type_membership)
|
232
234
|
end
|
233
235
|
|
236
|
+
def interface_type_memberships(obj_type, _ctx = nil)
|
237
|
+
@type_memberships ||= read_through do |obj_t|
|
238
|
+
obj_t.interface_type_memberships
|
239
|
+
end
|
240
|
+
@type_memberships[obj_type]
|
241
|
+
end
|
242
|
+
|
234
243
|
private
|
235
244
|
|
236
245
|
def visible_and_reachable_type?(type_defn)
|
@@ -17,15 +17,21 @@ module GraphQL
|
|
17
17
|
def platform_trace(platform_key, key, data)
|
18
18
|
tracer.trace(platform_key, service: service_name) do |span|
|
19
19
|
span.span_type = 'custom'
|
20
|
+
if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
|
21
|
+
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
|
22
|
+
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, key)
|
23
|
+
end
|
20
24
|
|
21
25
|
if key == 'execute_multiplex'
|
22
26
|
operations = data[:multiplex].queries.map(&:selected_operation_name).join(', ')
|
23
|
-
|
27
|
+
|
28
|
+
resource = if operations.empty?
|
24
29
|
first_query = data[:multiplex].queries.first
|
25
30
|
fallback_transaction_name(first_query && first_query.context)
|
26
31
|
else
|
27
32
|
operations
|
28
33
|
end
|
34
|
+
span.resource = resource if resource
|
29
35
|
|
30
36
|
# For top span of query, set the analytics sample rate tag, if available.
|
31
37
|
if analytics_enabled?
|
@@ -39,6 +45,8 @@ module GraphQL
|
|
39
45
|
span.set_tag(:query_string, data[:query].query_string)
|
40
46
|
end
|
41
47
|
|
48
|
+
prepare_span(key, data, span)
|
49
|
+
|
42
50
|
yield
|
43
51
|
end
|
44
52
|
end
|
@@ -47,8 +55,17 @@ module GraphQL
|
|
47
55
|
options.fetch(:service, 'ruby-graphql')
|
48
56
|
end
|
49
57
|
|
58
|
+
# Implement this method in a subclass to apply custom tags to datadog spans
|
59
|
+
# @param key [String] The event being traced
|
60
|
+
# @param data [Hash] The runtime data for this event (@see GraphQL::Tracing for keys for each event)
|
61
|
+
# @param span [Datadog::Tracing::SpanOperation] The datadog span for this event
|
62
|
+
def prepare_span(key, data, span)
|
63
|
+
end
|
64
|
+
|
50
65
|
def tracer
|
51
|
-
|
66
|
+
default_tracer = defined?(Datadog::Tracing) ? Datadog::Tracing : Datadog.tracer
|
67
|
+
|
68
|
+
options.fetch(:tracer, default_tracer)
|
52
69
|
end
|
53
70
|
|
54
71
|
def analytics_available?
|
@@ -10,6 +10,10 @@ module GraphQL
|
|
10
10
|
class PlatformTracing
|
11
11
|
class << self
|
12
12
|
attr_accessor :platform_keys
|
13
|
+
|
14
|
+
def inherited(child_class)
|
15
|
+
child_class.platform_keys = self.platform_keys
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
def initialize(options = {})
|
@@ -32,6 +36,7 @@ module GraphQL
|
|
32
36
|
trace_field = true # implemented with instrumenter
|
33
37
|
else
|
34
38
|
field = data[:field]
|
39
|
+
# HERE
|
35
40
|
return_type = field.type.unwrap
|
36
41
|
trace_field = if return_type.kind.scalar? || return_type.kind.enum?
|
37
42
|
(field.trace.nil? && @trace_scalars) || field.trace
|
@@ -41,7 +46,7 @@ module GraphQL
|
|
41
46
|
|
42
47
|
platform_key = if trace_field
|
43
48
|
context = data.fetch(:query).context
|
44
|
-
cached_platform_key(context, field) { platform_field_key(data[:owner], field) }
|
49
|
+
cached_platform_key(context, field, :field) { platform_field_key(data[:owner], field) }
|
45
50
|
else
|
46
51
|
nil
|
47
52
|
end
|
@@ -57,14 +62,14 @@ module GraphQL
|
|
57
62
|
when "authorized", "authorized_lazy"
|
58
63
|
type = data.fetch(:type)
|
59
64
|
context = data.fetch(:context)
|
60
|
-
platform_key = cached_platform_key(context, type) { platform_authorized_key(type) }
|
65
|
+
platform_key = cached_platform_key(context, type, :authorized) { platform_authorized_key(type) }
|
61
66
|
platform_trace(platform_key, key, data) do
|
62
67
|
yield
|
63
68
|
end
|
64
69
|
when "resolve_type", "resolve_type_lazy"
|
65
70
|
type = data.fetch(:type)
|
66
71
|
context = data.fetch(:context)
|
67
|
-
platform_key = cached_platform_key(context, type) { platform_resolve_type_key(type) }
|
72
|
+
platform_key = cached_platform_key(context, type, :resolve_type) { platform_resolve_type_key(type) }
|
68
73
|
platform_trace(platform_key, key, data) do
|
69
74
|
yield
|
70
75
|
end
|
@@ -135,7 +140,7 @@ module GraphQL
|
|
135
140
|
# If the key isn't present, the given block is called and the result is cached for `key`.
|
136
141
|
#
|
137
142
|
# @return [String]
|
138
|
-
def cached_platform_key(ctx, key)
|
143
|
+
def cached_platform_key(ctx, key, trace_phase)
|
139
144
|
cache = ctx.namespace(self.class)[:platform_key_cache] ||= {}
|
140
145
|
cache.fetch(key) { cache[key] = yield }
|
141
146
|
end
|
data/lib/graphql/types/string.rb
CHANGED
data/lib/graphql/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.13.
|
4
|
+
version: 1.13.19
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -722,7 +722,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
722
722
|
- !ruby/object:Gem::Version
|
723
723
|
version: '0'
|
724
724
|
requirements: []
|
725
|
-
rubygems_version: 3.
|
725
|
+
rubygems_version: 3.3.3
|
726
726
|
signing_key:
|
727
727
|
specification_version: 4
|
728
728
|
summary: A GraphQL language and runtime for Ruby
|