graphql 1.9.17 → 1.11.7
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/generators/graphql/core.rb +18 -2
- data/lib/generators/graphql/install_generator.rb +27 -0
- data/lib/generators/graphql/object_generator.rb +52 -8
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +14 -10
- data/lib/generators/graphql/templates/interface.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/templates/object.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/scalar.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +10 -0
- data/lib/generators/graphql/templates/union.erb +3 -1
- data/lib/graphql/analysis/ast/field_usage.rb +1 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +178 -67
- data/lib/graphql/analysis/ast/visitor.rb +3 -3
- data/lib/graphql/analysis/ast.rb +12 -11
- data/lib/graphql/argument.rb +10 -38
- data/lib/graphql/backtrace/table.rb +10 -2
- data/lib/graphql/backtrace/tracer.rb +2 -1
- data/lib/graphql/base_type.rb +4 -0
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +5 -9
- data/lib/graphql/define/assign_enum_value.rb +1 -1
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/define/assign_object_field.rb +3 -3
- data/lib/graphql/define/defined_object_proxy.rb +3 -0
- data/lib/graphql/define/instance_definable.rb +18 -108
- data/lib/graphql/directive/deprecated_directive.rb +1 -12
- data/lib/graphql/directive.rb +8 -1
- data/lib/graphql/enum_type.rb +5 -71
- data/lib/graphql/execution/directive_checks.rb +2 -2
- data/lib/graphql/execution/errors.rb +2 -3
- data/lib/graphql/execution/execute.rb +1 -1
- data/lib/graphql/execution/instrumentation.rb +1 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +51 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +79 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +25 -0
- data/lib/graphql/execution/interpreter/runtime.rb +227 -254
- data/lib/graphql/execution/interpreter.rb +34 -11
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lookahead.rb +39 -114
- data/lib/graphql/execution/multiplex.rb +14 -5
- data/lib/graphql/field.rb +14 -118
- data/lib/graphql/filter.rb +1 -1
- data/lib/graphql/function.rb +1 -30
- data/lib/graphql/input_object_type.rb +6 -24
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/interface_type.rb +7 -23
- data/lib/graphql/internal_representation/scope.rb +2 -2
- data/lib/graphql/internal_representation/visit.rb +2 -2
- data/lib/graphql/introspection/base_object.rb +2 -5
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +7 -7
- data/lib/graphql/introspection/field_type.rb +7 -3
- data/lib/graphql/introspection/input_value_type.rb +33 -9
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +4 -9
- data/lib/graphql/introspection/type_type.rb +11 -7
- data/lib/graphql/introspection.rb +96 -0
- data/lib/graphql/invalid_null_error.rb +18 -0
- data/lib/graphql/language/block_string.rb +24 -5
- data/lib/graphql/language/definition_slice.rb +21 -10
- data/lib/graphql/language/document_from_schema_definition.rb +89 -64
- data/lib/graphql/language/lexer.rb +7 -3
- data/lib/graphql/language/lexer.rl +7 -3
- data/lib/graphql/language/nodes.rb +52 -91
- data/lib/graphql/language/parser.rb +719 -717
- data/lib/graphql/language/parser.y +104 -98
- data/lib/graphql/language/printer.rb +1 -1
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/visitor.rb +2 -2
- data/lib/graphql/language.rb +2 -1
- data/lib/graphql/name_validator.rb +6 -7
- data/lib/graphql/non_null_type.rb +0 -10
- data/lib/graphql/object_type.rb +45 -56
- data/lib/graphql/pagination/active_record_relation_connection.rb +41 -0
- data/lib/graphql/pagination/array_connection.rb +77 -0
- data/lib/graphql/pagination/connection.rb +208 -0
- data/lib/graphql/pagination/connections.rb +145 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +185 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/query/arguments.rb +4 -2
- data/lib/graphql/query/context.rb +36 -9
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +23 -6
- data/lib/graphql/query/literal_input.rb +30 -10
- data/lib/graphql/query/null_context.rb +5 -1
- data/lib/graphql/query/validation_pipeline.rb +4 -1
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +16 -7
- data/lib/graphql/query.rb +64 -15
- data/lib/graphql/rake_task/validate.rb +3 -0
- data/lib/graphql/rake_task.rb +9 -9
- data/lib/graphql/relay/array_connection.rb +10 -12
- data/lib/graphql/relay/base_connection.rb +23 -13
- data/lib/graphql/relay/connection_type.rb +2 -1
- data/lib/graphql/relay/edge_type.rb +1 -0
- data/lib/graphql/relay/edges_instrumentation.rb +1 -1
- data/lib/graphql/relay/mutation.rb +1 -86
- data/lib/graphql/relay/node.rb +2 -2
- data/lib/graphql/relay/range_add.rb +14 -5
- data/lib/graphql/relay/relation_connection.rb +8 -10
- data/lib/graphql/scalar_type.rb +15 -59
- data/lib/graphql/schema/argument.rb +113 -11
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
- data/lib/graphql/schema/build_from_definition.rb +212 -190
- data/lib/graphql/schema/built_in_types.rb +5 -5
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive.rb +34 -3
- data/lib/graphql/schema/enum.rb +52 -4
- data/lib/graphql/schema/enum_value.rb +6 -1
- data/lib/graphql/schema/field/connection_extension.rb +44 -20
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +200 -129
- data/lib/graphql/schema/find_inherited_value.rb +13 -0
- data/lib/graphql/schema/finder.rb +13 -11
- data/lib/graphql/schema/input_object.rb +131 -22
- data/lib/graphql/schema/interface.rb +26 -8
- data/lib/graphql/schema/introspection_system.rb +108 -37
- data/lib/graphql/schema/late_bound_type.rb +3 -2
- data/lib/graphql/schema/list.rb +47 -0
- data/lib/graphql/schema/loader.rb +134 -96
- data/lib/graphql/schema/member/base_dsl_methods.rb +29 -12
- data/lib/graphql/schema/member/build_type.rb +19 -5
- data/lib/graphql/schema/member/cached_graphql_definition.rb +5 -0
- data/lib/graphql/schema/member/has_arguments.rb +105 -5
- data/lib/graphql/schema/member/has_ast_node.rb +20 -0
- data/lib/graphql/schema/member/has_fields.rb +20 -10
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/mutation.rb +5 -1
- data/lib/graphql/schema/non_null.rb +30 -0
- data/lib/graphql/schema/object.rb +65 -12
- data/lib/graphql/schema/possible_types.rb +9 -4
- data/lib/graphql/schema/printer.rb +0 -15
- data/lib/graphql/schema/relay_classic_mutation.rb +5 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +5 -2
- data/lib/graphql/schema/resolver.rb +26 -18
- data/lib/graphql/schema/scalar.rb +27 -3
- data/lib/graphql/schema/subscription.rb +8 -18
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/traversal.rb +1 -1
- data/lib/graphql/schema/type_expression.rb +21 -13
- data/lib/graphql/schema/type_membership.rb +2 -2
- data/lib/graphql/schema/union.rb +37 -3
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +10 -2
- data/lib/graphql/schema/warden.rb +115 -29
- data/lib/graphql/schema.rb +903 -195
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +10 -6
- data/lib/graphql/static_validation/literal_validator.rb +52 -27
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +43 -83
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +17 -5
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +33 -25
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +29 -21
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -5
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +5 -6
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
- data/lib/graphql/static_validation/type_stack.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +1 -1
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +30 -8
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +89 -19
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +84 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
- data/lib/graphql/subscriptions/event.rb +23 -5
- data/lib/graphql/subscriptions/instrumentation.rb +10 -5
- data/lib/graphql/subscriptions/serialize.rb +22 -4
- data/lib/graphql/subscriptions/subscription_root.rb +15 -5
- data/lib/graphql/subscriptions.rb +108 -35
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +14 -10
- data/lib/graphql/tracing/appoptics_tracing.rb +171 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +8 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +8 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
- data/lib/graphql/tracing/platform_tracing.rb +53 -9
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
- data/lib/graphql/tracing/scout_tracing.rb +19 -0
- data/lib/graphql/tracing/skylight_tracing.rb +8 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +14 -34
- data/lib/graphql/types/big_int.rb +1 -1
- data/lib/graphql/types/int.rb +9 -2
- data/lib/graphql/types/iso_8601_date.rb +3 -3
- data/lib/graphql/types/iso_8601_date_time.rb +25 -10
- data/lib/graphql/types/relay/base_connection.rb +11 -7
- data/lib/graphql/types/relay/base_edge.rb +2 -1
- data/lib/graphql/types/string.rb +7 -1
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/union_type.rb +13 -28
- data/lib/graphql/unresolved_type_error.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +31 -6
- data/readme.md +1 -1
- metadata +34 -9
- data/lib/graphql/literal_validation_error.rb +0 -6
@@ -71,7 +71,7 @@ module GraphQL
|
|
71
71
|
module ContextMethods
|
72
72
|
def on_operation_definition(node, parent)
|
73
73
|
object_type = @schema.root_type_for_operation(node.operation_type)
|
74
|
-
|
74
|
+
push_type(object_type)
|
75
75
|
@path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
|
76
76
|
super
|
77
77
|
@object_types.pop
|
@@ -98,9 +98,9 @@ module GraphQL
|
|
98
98
|
@field_definitions.push(field_definition)
|
99
99
|
if !field_definition.nil?
|
100
100
|
next_object_type = field_definition.type.unwrap
|
101
|
-
|
101
|
+
push_type(next_object_type)
|
102
102
|
else
|
103
|
-
|
103
|
+
push_type(nil)
|
104
104
|
end
|
105
105
|
@path.push(node.alias || node.name)
|
106
106
|
super
|
@@ -120,7 +120,7 @@ module GraphQL
|
|
120
120
|
argument_defn = if (arg = @argument_definitions.last)
|
121
121
|
arg_type = arg.type.unwrap
|
122
122
|
if arg_type.kind.input_object?
|
123
|
-
arg_type.
|
123
|
+
arg_type.arguments[node.name]
|
124
124
|
else
|
125
125
|
nil
|
126
126
|
end
|
@@ -187,15 +187,19 @@ module GraphQL
|
|
187
187
|
|
188
188
|
def on_fragment_with_type(node)
|
189
189
|
object_type = if node.type
|
190
|
-
@schema.
|
190
|
+
@schema.get_type(node.type.name)
|
191
191
|
else
|
192
192
|
@object_types.last
|
193
193
|
end
|
194
|
-
|
194
|
+
push_type(object_type)
|
195
195
|
yield(node)
|
196
196
|
@object_types.pop
|
197
197
|
@path.pop
|
198
198
|
end
|
199
|
+
|
200
|
+
def push_type(t)
|
201
|
+
@object_types.push(t)
|
202
|
+
end
|
199
203
|
end
|
200
204
|
|
201
205
|
private
|
@@ -6,59 +6,73 @@ module GraphQL
|
|
6
6
|
def initialize(context:)
|
7
7
|
@context = context
|
8
8
|
@warden = context.warden
|
9
|
+
@invalid_response = GraphQL::Query::InputValidationResult.new(valid: false, problems: [])
|
10
|
+
@valid_response = GraphQL::Query::InputValidationResult.new(valid: true, problems: [])
|
9
11
|
end
|
10
12
|
|
11
13
|
def validate(ast_value, type)
|
14
|
+
catch(:invalid) do
|
15
|
+
recursively_validate(ast_value, type)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def recursively_validate(ast_value, type)
|
12
22
|
if type.nil?
|
13
23
|
# this means we're an undefined argument, see #present_input_field_values_are_valid
|
14
24
|
maybe_raise_if_invalid(ast_value) do
|
15
|
-
|
25
|
+
@invalid_response
|
16
26
|
end
|
17
27
|
elsif ast_value.is_a?(GraphQL::Language::Nodes::NullValue)
|
18
28
|
maybe_raise_if_invalid(ast_value) do
|
19
|
-
|
29
|
+
type.kind.non_null? ? @invalid_response : @valid_response
|
20
30
|
end
|
21
31
|
elsif type.kind.non_null?
|
22
32
|
maybe_raise_if_invalid(ast_value) do
|
23
|
-
|
24
|
-
|
33
|
+
ast_value.nil? ?
|
34
|
+
@invalid_response :
|
35
|
+
recursively_validate(ast_value, type.of_type)
|
36
|
+
end
|
25
37
|
elsif type.kind.list?
|
26
38
|
item_type = type.of_type
|
27
|
-
ensure_array(ast_value).
|
39
|
+
results = ensure_array(ast_value).map { |val| recursively_validate(val, item_type) }
|
40
|
+
merge_results(results)
|
28
41
|
elsif ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
29
|
-
|
42
|
+
@valid_response
|
30
43
|
elsif type.kind.scalar? && constant_scalar?(ast_value)
|
31
44
|
maybe_raise_if_invalid(ast_value) do
|
32
|
-
type.
|
45
|
+
type.validate_input(ast_value, @context)
|
33
46
|
end
|
34
47
|
elsif type.kind.enum?
|
35
48
|
maybe_raise_if_invalid(ast_value) do
|
36
49
|
if ast_value.is_a?(GraphQL::Language::Nodes::Enum)
|
37
|
-
type.
|
50
|
+
type.validate_input(ast_value.name, @context)
|
38
51
|
else
|
39
52
|
# if our ast_value isn't an Enum it's going to be invalid so return false
|
40
|
-
|
53
|
+
@invalid_response
|
41
54
|
end
|
42
55
|
end
|
43
56
|
elsif type.kind.input_object? && ast_value.is_a?(GraphQL::Language::Nodes::InputObject)
|
44
57
|
maybe_raise_if_invalid(ast_value) do
|
45
|
-
|
58
|
+
merge_results([
|
59
|
+
required_input_fields_are_present(type, ast_value),
|
60
|
+
present_input_field_values_are_valid(type, ast_value)
|
61
|
+
])
|
46
62
|
end
|
47
63
|
else
|
48
64
|
maybe_raise_if_invalid(ast_value) do
|
49
|
-
|
65
|
+
@invalid_response
|
50
66
|
end
|
51
67
|
end
|
52
68
|
end
|
53
69
|
|
54
|
-
|
55
|
-
|
70
|
+
# When `error_bubbling` is false, we want to bail on the first failure that we find.
|
71
|
+
# Use `throw` to escape the current call stack, returning the invalid response.
|
56
72
|
def maybe_raise_if_invalid(ast_value)
|
57
73
|
ret = yield
|
58
|
-
if !@context.schema.error_bubbling && !ret
|
59
|
-
|
60
|
-
e.ast_value = ast_value
|
61
|
-
raise e
|
74
|
+
if !@context.schema.error_bubbling && !ret.valid?
|
75
|
+
throw(:invalid, ret)
|
62
76
|
else
|
63
77
|
ret
|
64
78
|
end
|
@@ -81,34 +95,45 @@ module GraphQL
|
|
81
95
|
def required_input_fields_are_present(type, ast_node)
|
82
96
|
# TODO - would be nice to use these to create an error message so the caller knows
|
83
97
|
# that required fields are missing
|
84
|
-
required_field_names =
|
85
|
-
.select { |
|
98
|
+
required_field_names = type.arguments.each_value
|
99
|
+
.select { |argument| argument.type.kind.non_null? && @warden.get_argument(type, argument.name) }
|
86
100
|
.map(&:name)
|
101
|
+
|
87
102
|
present_field_names = ast_node.arguments.map(&:name)
|
88
103
|
missing_required_field_names = required_field_names - present_field_names
|
89
104
|
if @context.schema.error_bubbling
|
90
|
-
missing_required_field_names.empty?
|
105
|
+
missing_required_field_names.empty? ? @valid_response : @invalid_response
|
91
106
|
else
|
92
|
-
missing_required_field_names.
|
93
|
-
|
107
|
+
results = missing_required_field_names.map do |name|
|
108
|
+
arg_type = @warden.get_argument(type, name).type
|
109
|
+
recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
|
94
110
|
end
|
111
|
+
merge_results(results)
|
95
112
|
end
|
96
113
|
end
|
97
114
|
|
98
115
|
def present_input_field_values_are_valid(type, ast_node)
|
99
|
-
|
100
|
-
|
101
|
-
field = field_map[value.name]
|
116
|
+
results = ast_node.arguments.map do |value|
|
117
|
+
field = @warden.get_argument(type, value.name)
|
102
118
|
# we want to call validate on an argument even if it's an invalid one
|
103
119
|
# so that our raise exception is on it instead of the entire InputObject
|
104
|
-
|
105
|
-
|
120
|
+
field_type = field && field.type
|
121
|
+
recursively_validate(value.value, field_type)
|
106
122
|
end
|
123
|
+
merge_results(results)
|
107
124
|
end
|
108
125
|
|
109
126
|
def ensure_array(value)
|
110
127
|
value.is_a?(Array) ? value : [value]
|
111
128
|
end
|
129
|
+
|
130
|
+
def merge_results(results_list)
|
131
|
+
merged_result = Query::InputValidationResult.new
|
132
|
+
results_list.each do |inner_result|
|
133
|
+
merged_result.merge_result!([], inner_result)
|
134
|
+
end
|
135
|
+
merged_result
|
136
|
+
end
|
112
137
|
end
|
113
138
|
end
|
114
139
|
end
|
@@ -2,103 +2,63 @@
|
|
2
2
|
module GraphQL
|
3
3
|
module StaticValidation
|
4
4
|
module ArgumentLiteralsAreCompatible
|
5
|
-
# TODO dedup with ArgumentsAreDefined
|
6
5
|
def on_argument(node, parent)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
if !arg_ret_type.is_a?(GraphQL::InputObjectType)
|
15
|
-
nil
|
16
|
-
else
|
17
|
-
arg_ret_type
|
18
|
-
end
|
19
|
-
end
|
20
|
-
when GraphQL::Language::Nodes::Directive
|
21
|
-
context.schema.directives[parent.name]
|
22
|
-
when GraphQL::Language::Nodes::Field
|
23
|
-
context.field_definition
|
24
|
-
else
|
25
|
-
raise "Unexpected argument parent: #{parent.class} (##{parent})"
|
6
|
+
# Check the child arguments first;
|
7
|
+
# don't add a new error if one of them reports an error
|
8
|
+
super
|
9
|
+
|
10
|
+
# Don't validate variables here
|
11
|
+
if node.value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
12
|
+
return
|
26
13
|
end
|
27
14
|
|
28
|
-
if
|
29
|
-
|
30
|
-
if arg_defn
|
31
|
-
begin
|
32
|
-
valid = context.valid_literal?(node.value, arg_defn.type)
|
33
|
-
rescue GraphQL::CoercionError => err
|
34
|
-
context.schema.error_bubbling
|
35
|
-
if !context.schema.error_bubbling && !arg_defn.type.unwrap.kind.scalar?
|
36
|
-
# if error bubbling is disabled and the arg that caused this error isn't a scalar then
|
37
|
-
# short-circuit here so we avoid bubbling this up to whatever input_object / array contains us
|
38
|
-
return super
|
39
|
-
end
|
40
|
-
error = GraphQL::StaticValidation::ArgumentLiteralsAreCompatibleError.new(err.message, nodes: parent, type: "CoercionError", extensions: err.extensions)
|
41
|
-
rescue GraphQL::LiteralValidationError => err
|
42
|
-
# check to see if the ast node that caused the error to be raised is
|
43
|
-
# the same as the node we were checking here.
|
44
|
-
arg_type = arg_defn.type
|
45
|
-
if arg_type.kind.non_null?
|
46
|
-
arg_type = arg_type.of_type
|
47
|
-
end
|
15
|
+
if @context.schema.error_bubbling || context.errors.none? { |err| err.path.take(@path.size) == @path }
|
16
|
+
parent_defn = parent_definition(parent)
|
48
17
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
18
|
+
if parent_defn && (arg_defn = parent_defn.arguments[node.name])
|
19
|
+
validation_result = context.validate_literal(node.value, arg_defn.type)
|
20
|
+
if !validation_result.valid?
|
21
|
+
kind_of_node = node_type(parent)
|
22
|
+
error_arg_name = parent_name(parent, parent_defn)
|
23
|
+
string_value = if node.value == Float::INFINITY
|
24
|
+
""
|
55
25
|
else
|
56
|
-
#
|
57
|
-
node.value == (err.ast_value)
|
26
|
+
" (#{GraphQL::Language::Printer.new.print(node.value)})"
|
58
27
|
end
|
59
|
-
if !matched
|
60
|
-
# This node isn't the node that caused the error,
|
61
|
-
# So halt this visit but continue visiting the rest of the tree
|
62
|
-
return super
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
if !valid
|
67
|
-
error ||= begin
|
68
|
-
kind_of_node = node_type(parent)
|
69
|
-
error_arg_name = parent_name(parent, parent_defn)
|
70
28
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
29
|
+
problems = validation_result.problems
|
30
|
+
first_problem = problems && problems.first
|
31
|
+
if first_problem
|
32
|
+
message = first_problem["message"]
|
33
|
+
# This is some legacy stuff from when `CoercionError` was raised thru the stack
|
34
|
+
if message
|
35
|
+
coerce_extensions = first_problem["extensions"] || {
|
36
|
+
"code" => "argumentLiteralsIncompatible"
|
37
|
+
}
|
38
|
+
end
|
77
39
|
end
|
78
|
-
add_error(error)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
40
|
|
83
|
-
|
84
|
-
|
41
|
+
error_options = {
|
42
|
+
nodes: parent,
|
43
|
+
type: kind_of_node,
|
44
|
+
argument: node.name
|
45
|
+
}
|
46
|
+
if coerce_extensions
|
47
|
+
error_options[:coerce_extensions] = coerce_extensions
|
48
|
+
end
|
85
49
|
|
50
|
+
message ||= "Argument '#{node.name}' on #{kind_of_node} '#{error_arg_name}' has an invalid value#{string_value}. Expected type '#{arg_defn.type.to_type_signature}'."
|
86
51
|
|
87
|
-
|
52
|
+
error = GraphQL::StaticValidation::ArgumentLiteralsAreCompatibleError.new(
|
53
|
+
message,
|
54
|
+
**error_options
|
55
|
+
)
|
88
56
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
elsif parent.is_a?(GraphQL::Language::Nodes::InputObject)
|
93
|
-
type_defn.name
|
94
|
-
else
|
95
|
-
parent.name
|
57
|
+
add_error(error)
|
58
|
+
end
|
59
|
+
end
|
96
60
|
end
|
97
61
|
end
|
98
|
-
|
99
|
-
def node_type(parent)
|
100
|
-
parent.class.name.split("::").last
|
101
|
-
end
|
102
62
|
end
|
103
63
|
end
|
104
64
|
end
|
@@ -5,19 +5,31 @@ module GraphQL
|
|
5
5
|
attr_reader :type_name
|
6
6
|
attr_reader :argument_name
|
7
7
|
|
8
|
-
def initialize(message, path: nil, nodes: [], type:, argument: nil, extensions: nil)
|
8
|
+
def initialize(message, path: nil, nodes: [], type:, argument: nil, extensions: nil, coerce_extensions: nil)
|
9
9
|
super(message, path: path, nodes: nodes)
|
10
10
|
@type_name = type
|
11
11
|
@argument_name = argument
|
12
12
|
@extensions = extensions
|
13
|
+
@coerce_extensions = coerce_extensions
|
13
14
|
end
|
14
15
|
|
15
16
|
# A hash representation of this Message
|
16
17
|
def to_h
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
if @coerce_extensions
|
19
|
+
extensions = @coerce_extensions
|
20
|
+
# This is for legacy compat -- but this key is supposed to be a GraphQL type name :confounded:
|
21
|
+
extensions["typeName"] = "CoercionError"
|
22
|
+
else
|
23
|
+
extensions = {
|
24
|
+
"code" => code,
|
25
|
+
"typeName" => type_name
|
26
|
+
}
|
27
|
+
|
28
|
+
if argument_name
|
29
|
+
extensions["argumentName"] = argument_name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
21
33
|
extensions.merge!(@extensions) unless @extensions.nil?
|
22
34
|
super.merge({
|
23
35
|
"extensions" => extensions
|
@@ -3,28 +3,9 @@ module GraphQL
|
|
3
3
|
module StaticValidation
|
4
4
|
module ArgumentsAreDefined
|
5
5
|
def on_argument(node, parent)
|
6
|
-
parent_defn =
|
7
|
-
when GraphQL::Language::Nodes::InputObject
|
8
|
-
arg_defn = context.argument_definition
|
9
|
-
if arg_defn.nil?
|
10
|
-
nil
|
11
|
-
else
|
12
|
-
arg_ret_type = arg_defn.type.unwrap
|
13
|
-
if !arg_ret_type.is_a?(GraphQL::InputObjectType)
|
14
|
-
nil
|
15
|
-
else
|
16
|
-
arg_ret_type
|
17
|
-
end
|
18
|
-
end
|
19
|
-
when GraphQL::Language::Nodes::Directive
|
20
|
-
context.schema.directives[parent.name]
|
21
|
-
when GraphQL::Language::Nodes::Field
|
22
|
-
context.field_definition
|
23
|
-
else
|
24
|
-
raise "Unexpected argument parent: #{parent.class} (##{parent})"
|
25
|
-
end
|
6
|
+
parent_defn = parent_definition(parent)
|
26
7
|
|
27
|
-
if parent_defn && context.warden.
|
8
|
+
if parent_defn && context.warden.get_argument(parent_defn, node.name)
|
28
9
|
super
|
29
10
|
elsif parent_defn
|
30
11
|
kind_of_node = node_type(parent)
|
@@ -44,19 +25,46 @@ module GraphQL
|
|
44
25
|
|
45
26
|
private
|
46
27
|
|
28
|
+
# TODO smell: these methods are added to all visitors, since they're included in a module.
|
47
29
|
def parent_name(parent, type_defn)
|
48
|
-
|
30
|
+
case parent
|
31
|
+
when GraphQL::Language::Nodes::Field
|
49
32
|
parent.alias || parent.name
|
50
|
-
|
51
|
-
type_defn.
|
52
|
-
|
33
|
+
when GraphQL::Language::Nodes::InputObject
|
34
|
+
type_defn.graphql_name
|
35
|
+
when GraphQL::Language::Nodes::Argument, GraphQL::Language::Nodes::Directive
|
53
36
|
parent.name
|
37
|
+
else
|
38
|
+
raise "Invariant: Unexpected parent #{parent.inspect} (#{parent.class})"
|
54
39
|
end
|
55
40
|
end
|
56
41
|
|
57
42
|
def node_type(parent)
|
58
43
|
parent.class.name.split("::").last
|
59
44
|
end
|
45
|
+
|
46
|
+
def parent_definition(parent)
|
47
|
+
case parent
|
48
|
+
when GraphQL::Language::Nodes::InputObject
|
49
|
+
arg_defn = context.argument_definition
|
50
|
+
if arg_defn.nil?
|
51
|
+
nil
|
52
|
+
else
|
53
|
+
arg_ret_type = arg_defn.type.unwrap
|
54
|
+
if arg_ret_type.kind.input_object?
|
55
|
+
arg_ret_type
|
56
|
+
else
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
when GraphQL::Language::Nodes::Directive
|
61
|
+
context.schema.directives[parent.name]
|
62
|
+
when GraphQL::Language::Nodes::Field
|
63
|
+
context.field_definition
|
64
|
+
else
|
65
|
+
raise "Unexpected argument parent: #{parent.class} (##{parent})"
|
66
|
+
end
|
67
|
+
end
|
60
68
|
end
|
61
69
|
end
|
62
70
|
end
|
@@ -56,7 +56,7 @@ module GraphQL
|
|
56
56
|
"'@#{directive_defn.graphql_name}' can't be applied to #{location_name} (allowed: #{allowed_location_names.join(", ")})",
|
57
57
|
nodes: directive_ast,
|
58
58
|
target: location_name,
|
59
|
-
name: directive_defn.
|
59
|
+
name: directive_defn.graphql_name
|
60
60
|
))
|
61
61
|
end
|
62
62
|
end
|
@@ -9,16 +9,16 @@ module GraphQL
|
|
9
9
|
if field.nil?
|
10
10
|
if parent_type.kind.union?
|
11
11
|
add_error(GraphQL::StaticValidation::FieldsHaveAppropriateSelectionsError.new(
|
12
|
-
"Selections can't be made directly on unions (see selections on #{parent_type.
|
12
|
+
"Selections can't be made directly on unions (see selections on #{parent_type.graphql_name})",
|
13
13
|
nodes: parent,
|
14
|
-
node_name: parent_type.
|
14
|
+
node_name: parent_type.graphql_name
|
15
15
|
))
|
16
16
|
else
|
17
17
|
add_error(GraphQL::StaticValidation::FieldsAreDefinedOnTypeError.new(
|
18
|
-
"Field '#{node.name}' doesn't exist on type '#{parent_type.
|
18
|
+
"Field '#{node.name}' doesn't exist on type '#{parent_type.graphql_name}'",
|
19
19
|
nodes: node,
|
20
20
|
field: node.name,
|
21
|
-
type: parent_type.
|
21
|
+
type: parent_type.graphql_name
|
22
22
|
))
|
23
23
|
end
|
24
24
|
else
|
@@ -27,12 +27,12 @@ module GraphQL
|
|
27
27
|
nil
|
28
28
|
elsif resolved_type.kind.scalar? && ast_node.selections.any?
|
29
29
|
if ast_node.selections.first.is_a?(GraphQL::Language::Nodes::InlineFragment)
|
30
|
-
"Selections can't be made on scalars (%{node_name} returns #{resolved_type.
|
30
|
+
"Selections can't be made on scalars (%{node_name} returns #{resolved_type.graphql_name} but has inline fragments [#{ast_node.selections.map(&:type).map(&:name).join(", ")}])"
|
31
31
|
else
|
32
|
-
"Selections can't be made on scalars (%{node_name} returns #{resolved_type.
|
32
|
+
"Selections can't be made on scalars (%{node_name} returns #{resolved_type.graphql_name} but has selections [#{ast_node.selections.map(&:name).join(", ")}])"
|
33
33
|
end
|
34
34
|
elsif resolved_type.kind.fields? && ast_node.selections.empty?
|
35
|
-
"Field must have selections (%{node_name} returns #{resolved_type.
|
35
|
+
"Field must have selections (%{node_name} returns #{resolved_type.graphql_name} but has no selections. Did you mean '#{ast_node.name} { ... }'?)"
|
36
36
|
else
|
37
37
|
nil
|
38
38
|
end
|
@@ -55,13 +55,13 @@ module GraphQL
|
|
55
55
|
"name": node_name.to_s
|
56
56
|
}
|
57
57
|
unless resolved_type.nil?
|
58
|
-
extensions["type"] = resolved_type.
|
58
|
+
extensions["type"] = resolved_type.to_type_signature
|
59
59
|
end
|
60
60
|
add_error(GraphQL::StaticValidation::FieldsHaveAppropriateSelectionsError.new(
|
61
61
|
msg % { node_name: node_name },
|
62
62
|
nodes: ast_node,
|
63
63
|
node_name: node_name.to_s,
|
64
|
-
type: resolved_type.nil? ? nil : resolved_type.
|
64
|
+
type: resolved_type.nil? ? nil : resolved_type.graphql_name,
|
65
65
|
))
|
66
66
|
false
|
67
67
|
else
|
@@ -93,8 +93,8 @@ module GraphQL
|
|
93
93
|
|
94
94
|
return if fragment1.nil? || fragment2.nil?
|
95
95
|
|
96
|
-
fragment_type1 = context.
|
97
|
-
fragment_type2 = context.
|
96
|
+
fragment_type1 = context.warden.get_type(fragment1.type.name)
|
97
|
+
fragment_type2 = context.warden.get_type(fragment2.type.name)
|
98
98
|
|
99
99
|
return if fragment_type1.nil? || fragment_type2.nil?
|
100
100
|
|
@@ -146,7 +146,7 @@ module GraphQL
|
|
146
146
|
fragment = context.fragments[fragment_name]
|
147
147
|
return if fragment.nil?
|
148
148
|
|
149
|
-
fragment_type = context.
|
149
|
+
fragment_type = context.warden.get_type(fragment.type.name)
|
150
150
|
return if fragment_type.nil?
|
151
151
|
|
152
152
|
fragment_fields, fragment_spreads = fields_and_fragments_from_selection(fragment, owner_type: fragment_type, parents: [*fragment_spread.parents, fragment_type])
|
@@ -202,15 +202,16 @@ module GraphQL
|
|
202
202
|
)
|
203
203
|
end
|
204
204
|
|
205
|
-
|
206
|
-
|
207
|
-
|
205
|
+
if !same_arguments?(node1, node2)
|
206
|
+
args = [serialize_field_args(node1), serialize_field_args(node2)]
|
207
|
+
conflicts = args.map { |arg| GraphQL::Language.serialize(arg) }.join(" or ")
|
208
|
+
msg = "Field '#{response_key}' has an argument conflict: #{conflicts}?"
|
208
209
|
context.errors << GraphQL::StaticValidation::FieldsWillMergeError.new(
|
209
210
|
msg,
|
210
211
|
nodes: [node1, node2],
|
211
212
|
path: [],
|
212
213
|
field_name: response_key,
|
213
|
-
conflicts:
|
214
|
+
conflicts: conflicts
|
214
215
|
)
|
215
216
|
end
|
216
217
|
end
|
@@ -316,7 +317,7 @@ module GraphQL
|
|
316
317
|
definition = context.schema.get_field(owner_type, node.name)
|
317
318
|
fields << Field.new(node, definition, owner_type, parents)
|
318
319
|
when GraphQL::Language::Nodes::InlineFragment
|
319
|
-
fragment_type = node.type ? context.
|
320
|
+
fragment_type = node.type ? context.warden.get_type(node.type.name) : owner_type
|
320
321
|
find_fields_and_fragments(node.selections, parents: [*parents, fragment_type], owner_type: owner_type, fields: fields, fragment_spreads: fragment_spreads) if fragment_type
|
321
322
|
when GraphQL::Language::Nodes::FragmentSpread
|
322
323
|
fragment_spreads << FragmentSpread.new(node.name, parents)
|
@@ -326,20 +327,19 @@ module GraphQL
|
|
326
327
|
[fields, fragment_spreads]
|
327
328
|
end
|
328
329
|
|
329
|
-
def
|
330
|
+
def same_arguments?(field1, field2)
|
330
331
|
# Check for incompatible / non-identical arguments on this node:
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
end.uniq
|
332
|
+
arguments1 = field1.arguments
|
333
|
+
arguments2 = field2.arguments
|
334
|
+
|
335
|
+
return false if arguments1.length != arguments2.length
|
336
|
+
|
337
|
+
arguments1.all? do |argument1|
|
338
|
+
argument2 = arguments2.find { |argument| argument.name == argument1.name }
|
339
|
+
return false if argument2.nil?
|
340
|
+
|
341
|
+
serialize_arg(argument1.value) == serialize_arg(argument2.value)
|
342
|
+
end
|
343
343
|
end
|
344
344
|
|
345
345
|
def serialize_arg(arg_value)
|
@@ -353,6 +353,14 @@ module GraphQL
|
|
353
353
|
end
|
354
354
|
end
|
355
355
|
|
356
|
+
def serialize_field_args(field)
|
357
|
+
serialized_args = {}
|
358
|
+
field.arguments.each do |argument|
|
359
|
+
serialized_args[argument.name] = serialize_arg(argument.value)
|
360
|
+
end
|
361
|
+
serialized_args
|
362
|
+
end
|
363
|
+
|
356
364
|
def compared_fragments_key(frag1, frag2, exclusive)
|
357
365
|
# Cache key to not compare two fragments more than once.
|
358
366
|
# The key includes both fragment names sorted (this way we
|
@@ -50,12 +50,12 @@ module GraphQL
|
|
50
50
|
if child_types.none? { |c| parent_types.include?(c) }
|
51
51
|
name = node.respond_to?(:name) ? " #{node.name}" : ""
|
52
52
|
add_error(GraphQL::StaticValidation::FragmentSpreadsArePossibleError.new(
|
53
|
-
"Fragment#{name} on #{child_type.
|
53
|
+
"Fragment#{name} on #{child_type.graphql_name} can't be spread inside #{parent_type.graphql_name}",
|
54
54
|
nodes: node,
|
55
55
|
path: path,
|
56
56
|
fragment_name: name.empty? ? "unknown" : name,
|
57
|
-
type: child_type.
|
58
|
-
parent: parent_type.
|
57
|
+
type: child_type.graphql_name,
|
58
|
+
parent: parent_type.graphql_name
|
59
59
|
))
|
60
60
|
end
|
61
61
|
end
|