graphql 2.2.17 → 2.5.16
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/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install_generator.rb +46 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_resolver.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +3 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyzer.rb +90 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +263 -0
- data/lib/graphql/analysis/{ast/query_depth.rb → query_depth.rb} +23 -25
- data/lib/graphql/analysis/visitor.rb +280 -0
- data/lib/graphql/analysis.rb +95 -1
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/current.rb +57 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/subscriptions.rb +96 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +158 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
- data/lib/graphql/dataloader/active_record_source.rb +47 -0
- data/lib/graphql/dataloader/async_dataloader.rb +46 -19
- data/lib/graphql/dataloader/null_dataloader.rb +51 -10
- data/lib/graphql/dataloader/source.rb +20 -9
- data/lib/graphql/dataloader.rb +153 -45
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +23 -25
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +63 -5
- data/lib/graphql/execution/interpreter/runtime.rb +321 -222
- data/lib/graphql/execution/interpreter.rb +23 -30
- data/lib/graphql/execution/lookahead.rb +18 -11
- data/lib/graphql/execution/multiplex.rb +6 -5
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +6 -11
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +20 -17
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/document_from_schema_definition.rb +64 -35
- data/lib/graphql/language/lexer.rb +72 -42
- data/lib/graphql/language/nodes.rb +93 -52
- data/lib/graphql/language/parser.rb +168 -61
- data/lib/graphql/language/printer.rb +31 -15
- data/lib/graphql/language/sanitized_printer.rb +1 -1
- data/lib/graphql/language.rb +61 -1
- data/lib/graphql/pagination/connection.rb +1 -1
- data/lib/graphql/query/context/scoped_context.rb +1 -1
- data/lib/graphql/query/context.rb +46 -47
- data/lib/graphql/query/null_context.rb +3 -5
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query.rb +123 -69
- data/lib/graphql/railtie.rb +7 -0
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +26 -13
- data/lib/graphql/schema/always_visible.rb +7 -2
- data/lib/graphql/schema/argument.rb +57 -8
- data/lib/graphql/schema/build_from_definition.rb +116 -49
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive.rb +54 -2
- data/lib/graphql/schema/enum.rb +107 -24
- data/lib/graphql/schema/enum_value.rb +10 -2
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +134 -45
- data/lib/graphql/schema/field_extension.rb +1 -1
- data/lib/graphql/schema/has_single_input_argument.rb +6 -2
- data/lib/graphql/schema/input_object.rb +122 -64
- data/lib/graphql/schema/interface.rb +23 -5
- data/lib/graphql/schema/introspection_system.rb +6 -17
- data/lib/graphql/schema/late_bound_type.rb +4 -0
- data/lib/graphql/schema/list.rb +3 -3
- data/lib/graphql/schema/loader.rb +3 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
- data/lib/graphql/schema/member/has_arguments.rb +44 -58
- data/lib/graphql/schema/member/has_dataloader.rb +62 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +26 -6
- data/lib/graphql/schema/member/has_interfaces.rb +6 -6
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +25 -8
- data/lib/graphql/schema/printer.rb +1 -0
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
- data/lib/graphql/schema/resolver.rb +29 -23
- data/lib/graphql/schema/scalar.rb +1 -6
- data/lib/graphql/schema/subscription.rb +52 -6
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/required_validator.rb +92 -11
- data/lib/graphql/schema/validator.rb +3 -1
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +445 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +311 -0
- data/lib/graphql/schema/warden.rb +190 -20
- data/lib/graphql/schema.rb +695 -167
- data/lib/graphql/static_validation/all_rules.rb +2 -2
- data/lib/graphql/static_validation/base_visitor.rb +6 -5
- data/lib/graphql/static_validation/literal_validator.rb +4 -4
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +18 -2
- data/lib/graphql/static_validation/validator.rb +6 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +5 -3
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +13 -2
- data/lib/graphql/subscriptions/serialize.rb +1 -1
- data/lib/graphql/subscriptions.rb +7 -5
- data/lib/graphql/testing/helpers.rb +48 -16
- data/lib/graphql/testing/mock_action_cable.rb +111 -0
- data/lib/graphql/testing.rb +1 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +5 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
- data/lib/graphql/tracing/appsignal_trace.rb +32 -59
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +46 -162
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +141 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +47 -54
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +183 -37
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +818 -0
- data/lib/graphql/tracing/platform_tracing.rb +1 -1
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
- data/lib/graphql/tracing/prometheus_trace.rb +73 -73
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -58
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +64 -98
- data/lib/graphql/tracing/statsd_trace.rb +33 -45
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +111 -1
- data/lib/graphql/tracing.rb +31 -30
- data/lib/graphql/type_kinds.rb +2 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +12 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +11 -1
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/types.rb +18 -11
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +64 -54
- metadata +197 -22
- data/lib/graphql/analysis/ast/analyzer.rb +0 -91
- data/lib/graphql/analysis/ast/field_usage.rb +0 -82
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -182
- data/lib/graphql/analysis/ast/visitor.rb +0 -276
- data/lib/graphql/analysis/ast.rb +0 -94
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/trace.rb +0 -93
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
|
@@ -34,9 +34,9 @@ module GraphQL
|
|
|
34
34
|
GraphQL::StaticValidation::VariableUsagesAreAllowed,
|
|
35
35
|
GraphQL::StaticValidation::MutationRootExists,
|
|
36
36
|
GraphQL::StaticValidation::QueryRootExists,
|
|
37
|
-
GraphQL::StaticValidation::
|
|
37
|
+
GraphQL::StaticValidation::SubscriptionRootExistsAndSingleSubscriptionSelection,
|
|
38
38
|
GraphQL::StaticValidation::InputObjectNamesAreUnique,
|
|
39
39
|
GraphQL::StaticValidation::OneOfInputObjectsAreValid,
|
|
40
|
-
]
|
|
40
|
+
].freeze
|
|
41
41
|
end
|
|
42
42
|
end
|
|
@@ -10,6 +10,7 @@ module GraphQL
|
|
|
10
10
|
@argument_definitions = []
|
|
11
11
|
@directive_definitions = []
|
|
12
12
|
@context = context
|
|
13
|
+
@types = context.query.types
|
|
13
14
|
@schema = context.schema
|
|
14
15
|
super(document)
|
|
15
16
|
end
|
|
@@ -77,7 +78,7 @@ module GraphQL
|
|
|
77
78
|
|
|
78
79
|
def on_field(node, parent)
|
|
79
80
|
parent_type = @object_types.last
|
|
80
|
-
field_definition = @
|
|
81
|
+
field_definition = @types.field(parent_type, node.name)
|
|
81
82
|
@field_definitions.push(field_definition)
|
|
82
83
|
if !field_definition.nil?
|
|
83
84
|
next_object_type = field_definition.type.unwrap
|
|
@@ -103,14 +104,14 @@ module GraphQL
|
|
|
103
104
|
argument_defn = if (arg = @argument_definitions.last)
|
|
104
105
|
arg_type = arg.type.unwrap
|
|
105
106
|
if arg_type.kind.input_object?
|
|
106
|
-
@
|
|
107
|
+
@types.argument(arg_type, node.name)
|
|
107
108
|
else
|
|
108
109
|
nil
|
|
109
110
|
end
|
|
110
111
|
elsif (directive_defn = @directive_definitions.last)
|
|
111
|
-
@
|
|
112
|
+
@types.argument(directive_defn, node.name)
|
|
112
113
|
elsif (field_defn = @field_definitions.last)
|
|
113
|
-
@
|
|
114
|
+
@types.argument(field_defn, node.name)
|
|
114
115
|
else
|
|
115
116
|
nil
|
|
116
117
|
end
|
|
@@ -170,7 +171,7 @@ module GraphQL
|
|
|
170
171
|
|
|
171
172
|
def on_fragment_with_type(node)
|
|
172
173
|
object_type = if node.type
|
|
173
|
-
@
|
|
174
|
+
@types.type(node.type.name)
|
|
174
175
|
else
|
|
175
176
|
@object_types.last
|
|
176
177
|
end
|
|
@@ -5,7 +5,7 @@ module GraphQL
|
|
|
5
5
|
class LiteralValidator
|
|
6
6
|
def initialize(context:)
|
|
7
7
|
@context = context
|
|
8
|
-
@
|
|
8
|
+
@types = context.types
|
|
9
9
|
@invalid_response = GraphQL::Query::InputValidationResult.new(valid: false, problems: [])
|
|
10
10
|
@valid_response = GraphQL::Query::InputValidationResult.new(valid: true, problems: [])
|
|
11
11
|
end
|
|
@@ -109,7 +109,7 @@ module GraphQL
|
|
|
109
109
|
def required_input_fields_are_present(type, ast_node)
|
|
110
110
|
# TODO - would be nice to use these to create an error message so the caller knows
|
|
111
111
|
# that required fields are missing
|
|
112
|
-
required_field_names = @
|
|
112
|
+
required_field_names = @types.arguments(type)
|
|
113
113
|
.select { |argument| argument.type.kind.non_null? && !argument.default_value? }
|
|
114
114
|
.map!(&:name)
|
|
115
115
|
|
|
@@ -119,7 +119,7 @@ module GraphQL
|
|
|
119
119
|
missing_required_field_names.empty? ? @valid_response : @invalid_response
|
|
120
120
|
else
|
|
121
121
|
results = missing_required_field_names.map do |name|
|
|
122
|
-
arg_type = @
|
|
122
|
+
arg_type = @types.argument(type, name).type
|
|
123
123
|
recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
|
|
124
124
|
end
|
|
125
125
|
if type.one_of? && ast_node.arguments.size != 1
|
|
@@ -131,7 +131,7 @@ module GraphQL
|
|
|
131
131
|
|
|
132
132
|
def present_input_field_values_are_valid(type, ast_node)
|
|
133
133
|
results = ast_node.arguments.map do |value|
|
|
134
|
-
field = @
|
|
134
|
+
field = @types.argument(type, value.name)
|
|
135
135
|
# we want to call validate on an argument even if it's an invalid one
|
|
136
136
|
# so that our raise exception is on it instead of the entire InputObject
|
|
137
137
|
field_type = field && field.type
|
|
@@ -15,7 +15,7 @@ module GraphQL
|
|
|
15
15
|
if @context.schema.error_bubbling || context.errors.none? { |err| err.path.take(@path.size) == @path }
|
|
16
16
|
parent_defn = parent_definition(parent)
|
|
17
17
|
|
|
18
|
-
if parent_defn && (arg_defn =
|
|
18
|
+
if parent_defn && (arg_defn = @types.argument(parent_defn, node.name))
|
|
19
19
|
validation_result = context.validate_literal(node.value, arg_defn.type)
|
|
20
20
|
if !validation_result.valid?
|
|
21
21
|
kind_of_node = node_type(parent)
|
|
@@ -16,7 +16,7 @@ module GraphQL
|
|
|
16
16
|
|
|
17
17
|
def validate_arguments(node)
|
|
18
18
|
argument_defns = node.arguments
|
|
19
|
-
if argument_defns.
|
|
19
|
+
if !argument_defns.empty?
|
|
20
20
|
args_by_name = Hash.new { |h, k| h[k] = [] }
|
|
21
21
|
argument_defns.each { |a| args_by_name[a.name] << a }
|
|
22
22
|
args_by_name.each do |name, defns|
|
|
@@ -5,13 +5,14 @@ module GraphQL
|
|
|
5
5
|
def on_argument(node, parent)
|
|
6
6
|
parent_defn = parent_definition(parent)
|
|
7
7
|
|
|
8
|
-
if parent_defn &&
|
|
8
|
+
if parent_defn && @types.argument(parent_defn, node.name)
|
|
9
9
|
super
|
|
10
10
|
elsif parent_defn
|
|
11
11
|
kind_of_node = node_type(parent)
|
|
12
12
|
error_arg_name = parent_name(parent, parent_defn)
|
|
13
|
+
arg_names = context.types.arguments(parent_defn).map(&:graphql_name)
|
|
13
14
|
add_error(GraphQL::StaticValidation::ArgumentsAreDefinedError.new(
|
|
14
|
-
"#{kind_of_node} '#{error_arg_name}' doesn't accept argument '#{node.name}'",
|
|
15
|
+
"#{kind_of_node} '#{error_arg_name}' doesn't accept argument '#{node.name}'#{context.did_you_mean_suggestion(node.name, arg_names)}",
|
|
15
16
|
nodes: node,
|
|
16
17
|
name: error_arg_name,
|
|
17
18
|
type: kind_of_node,
|
|
@@ -4,15 +4,15 @@ module GraphQL
|
|
|
4
4
|
module DirectivesAreDefined
|
|
5
5
|
def initialize(*)
|
|
6
6
|
super
|
|
7
|
-
@directive_names = context.warden.directives.map(&:graphql_name)
|
|
8
7
|
end
|
|
9
8
|
|
|
10
9
|
def on_directive(node, parent)
|
|
11
|
-
if !@
|
|
10
|
+
if !@types.directive_exists?(node.name)
|
|
12
11
|
@directives_are_defined_errors_by_name ||= {}
|
|
13
12
|
error = @directives_are_defined_errors_by_name[node.name] ||= begin
|
|
13
|
+
@directive_names ||= @types.directives.map(&:graphql_name)
|
|
14
14
|
err = GraphQL::StaticValidation::DirectivesAreDefinedError.new(
|
|
15
|
-
"Directive @#{node.name} is not defined",
|
|
15
|
+
"Directive @#{node.name} is not defined#{context.did_you_mean_suggestion(node.name, @directive_names)}",
|
|
16
16
|
nodes: [],
|
|
17
17
|
directive: node.name
|
|
18
18
|
)
|
|
@@ -19,6 +19,7 @@ module GraphQL
|
|
|
19
19
|
GraphQL::Schema::Directive::FRAGMENT_DEFINITION => "fragment definitions",
|
|
20
20
|
GraphQL::Schema::Directive::FRAGMENT_SPREAD => "fragment spreads",
|
|
21
21
|
GraphQL::Schema::Directive::INLINE_FRAGMENT => "inline fragments",
|
|
22
|
+
GraphQL::Schema::Directive::VARIABLE_DEFINITION => "variable definitions",
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
SIMPLE_LOCATIONS = {
|
|
@@ -26,6 +27,7 @@ module GraphQL
|
|
|
26
27
|
Nodes::InlineFragment => GraphQL::Schema::Directive::INLINE_FRAGMENT,
|
|
27
28
|
Nodes::FragmentSpread => GraphQL::Schema::Directive::FRAGMENT_SPREAD,
|
|
28
29
|
Nodes::FragmentDefinition => GraphQL::Schema::Directive::FRAGMENT_DEFINITION,
|
|
30
|
+
Nodes::VariableDefinition => GraphQL::Schema::Directive::VARIABLE_DEFINITION,
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
SIMPLE_LOCATION_NODES = SIMPLE_LOCATIONS.keys
|
|
@@ -4,7 +4,7 @@ module GraphQL
|
|
|
4
4
|
module FieldsAreDefinedOnType
|
|
5
5
|
def on_field(node, parent)
|
|
6
6
|
parent_type = @object_types[-2]
|
|
7
|
-
field = context.
|
|
7
|
+
field = context.query.types.field(parent_type, node.name)
|
|
8
8
|
|
|
9
9
|
if field.nil?
|
|
10
10
|
if parent_type.kind.union?
|
|
@@ -14,8 +14,11 @@ module GraphQL
|
|
|
14
14
|
node_name: parent_type.graphql_name
|
|
15
15
|
))
|
|
16
16
|
else
|
|
17
|
+
possible_fields = possible_fields(context, parent_type)
|
|
18
|
+
suggestion = context.did_you_mean_suggestion(node.name, possible_fields)
|
|
19
|
+
message = "Field '#{node.name}' doesn't exist on type '#{parent_type.graphql_name}'#{suggestion}"
|
|
17
20
|
add_error(GraphQL::StaticValidation::FieldsAreDefinedOnTypeError.new(
|
|
18
|
-
|
|
21
|
+
message,
|
|
19
22
|
nodes: node,
|
|
20
23
|
field: node.name,
|
|
21
24
|
type: parent_type.graphql_name
|
|
@@ -25,6 +28,13 @@ module GraphQL
|
|
|
25
28
|
super
|
|
26
29
|
end
|
|
27
30
|
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def possible_fields(context, parent_type)
|
|
35
|
+
return EmptyObjects::EMPTY_ARRAY if parent_type.kind.leaf?
|
|
36
|
+
context.types.fields(parent_type).map(&:graphql_name)
|
|
37
|
+
end
|
|
28
38
|
end
|
|
29
39
|
end
|
|
30
40
|
end
|
|
@@ -25,22 +25,56 @@ module GraphQL
|
|
|
25
25
|
def validate_field_selections(ast_node, resolved_type)
|
|
26
26
|
msg = if resolved_type.nil?
|
|
27
27
|
nil
|
|
28
|
-
elsif resolved_type.kind.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
elsif resolved_type.kind.leaf?
|
|
29
|
+
if !ast_node.selections.empty?
|
|
30
|
+
selection_strs = ast_node.selections.map do |n|
|
|
31
|
+
case n
|
|
32
|
+
when GraphQL::Language::Nodes::InlineFragment
|
|
33
|
+
"\"... on #{n.type.name} { ... }\""
|
|
34
|
+
when GraphQL::Language::Nodes::Field
|
|
35
|
+
"\"#{n.name}\""
|
|
36
|
+
when GraphQL::Language::Nodes::FragmentSpread
|
|
37
|
+
"\"#{n.name}\""
|
|
38
|
+
else
|
|
39
|
+
raise "Invariant: unexpected selection node: #{n}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
"Selections can't be made on #{resolved_type.kind.name.sub("_", " ").downcase}s (%{node_name} returns #{resolved_type.graphql_name} but has selections [#{selection_strs.join(", ")}])"
|
|
43
|
+
else
|
|
44
|
+
nil
|
|
45
|
+
end
|
|
46
|
+
elsif ast_node.selections.empty?
|
|
47
|
+
return_validation_error = true
|
|
48
|
+
legacy_invalid_empty_selection_result = nil
|
|
49
|
+
if !resolved_type.kind.fields?
|
|
50
|
+
case @schema.allow_legacy_invalid_empty_selections_on_union
|
|
51
|
+
when true
|
|
52
|
+
legacy_invalid_empty_selection_result = @schema.legacy_invalid_empty_selections_on_union_with_type(@context.query, resolved_type)
|
|
53
|
+
case legacy_invalid_empty_selection_result
|
|
54
|
+
when :return_validation_error
|
|
55
|
+
# keep `return_validation_error = true`
|
|
56
|
+
when String
|
|
57
|
+
return_validation_error = false
|
|
58
|
+
# the string is returned below
|
|
59
|
+
when nil
|
|
60
|
+
# No error:
|
|
61
|
+
return_validation_error = false
|
|
62
|
+
legacy_invalid_empty_selection_result = nil
|
|
63
|
+
else
|
|
64
|
+
raise GraphQL::InvariantError, "Unexpected return value from legacy_invalid_empty_selections_on_union_with_type, must be `:return_validation_error`, String, or nil (got: #{legacy_invalid_empty_selection_result.inspect})"
|
|
65
|
+
end
|
|
66
|
+
when false
|
|
67
|
+
# pass -- error below
|
|
37
68
|
else
|
|
38
|
-
|
|
69
|
+
return_validation_error = false
|
|
70
|
+
@context.query.logger.warn("Unions require selections but #{ast_node.alias || ast_node.name} (#{resolved_type.graphql_name}) doesn't have any. This will fail with a validation error on a future GraphQL-Ruby version. More info: https://graphql-ruby.org/api-doc/#{GraphQL::VERSION}/GraphQL/Schema.html#allow_legacy_invalid_empty_selections_on_union-class_method")
|
|
39
71
|
end
|
|
40
72
|
end
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
73
|
+
if return_validation_error
|
|
74
|
+
"Field must have selections (%{node_name} returns #{resolved_type.graphql_name} but has no selections. Did you mean '#{ast_node.name} { ... }'?)"
|
|
75
|
+
else
|
|
76
|
+
legacy_invalid_empty_selection_result
|
|
77
|
+
end
|
|
44
78
|
else
|
|
45
79
|
nil
|
|
46
80
|
end
|
|
@@ -33,26 +33,19 @@ module GraphQL
|
|
|
33
33
|
|
|
34
34
|
private
|
|
35
35
|
|
|
36
|
-
def
|
|
37
|
-
@
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def arg_conflicts
|
|
43
|
-
@arg_conflicts ||= Hash.new do |errors, field|
|
|
44
|
-
errors[field] = GraphQL::StaticValidation::FieldsWillMergeError.new(kind: :argument, field_name: field)
|
|
36
|
+
def conflicts
|
|
37
|
+
@conflicts ||= Hash.new do |h, error_type|
|
|
38
|
+
h[error_type] = Hash.new do |h2, field_name|
|
|
39
|
+
h2[field_name] = GraphQL::StaticValidation::FieldsWillMergeError.new(kind: error_type, field_name: field_name)
|
|
40
|
+
end
|
|
45
41
|
end
|
|
46
42
|
end
|
|
47
43
|
|
|
48
44
|
def setting_errors
|
|
49
|
-
@
|
|
50
|
-
@arg_conflicts = nil
|
|
51
|
-
|
|
45
|
+
@conflicts = nil
|
|
52
46
|
yield
|
|
53
47
|
# don't initialize these if they weren't initialized in the block:
|
|
54
|
-
@
|
|
55
|
-
@arg_conflicts && @arg_conflicts.each_value { |error| add_error(error) }
|
|
48
|
+
@conflicts&.each_value { |error_type| error_type.each_value { |error| add_error(error) } }
|
|
56
49
|
end
|
|
57
50
|
|
|
58
51
|
def conflicts_within_selection_set(node, parent_type)
|
|
@@ -117,8 +110,8 @@ module GraphQL
|
|
|
117
110
|
|
|
118
111
|
return if fragment1.nil? || fragment2.nil?
|
|
119
112
|
|
|
120
|
-
fragment_type1 = context.
|
|
121
|
-
fragment_type2 = context.
|
|
113
|
+
fragment_type1 = context.query.types.type(fragment1.type.name)
|
|
114
|
+
fragment_type2 = context.query.types.type(fragment2.type.name)
|
|
122
115
|
|
|
123
116
|
return if fragment_type1.nil? || fragment_type2.nil?
|
|
124
117
|
|
|
@@ -170,7 +163,7 @@ module GraphQL
|
|
|
170
163
|
fragment = context.fragments[fragment_name]
|
|
171
164
|
return if fragment.nil?
|
|
172
165
|
|
|
173
|
-
fragment_type =
|
|
166
|
+
fragment_type = @types.type(fragment.type.name)
|
|
174
167
|
return if fragment_type.nil?
|
|
175
168
|
|
|
176
169
|
fragment_fields, fragment_spreads = fields_and_fragments_from_selection(fragment, owner_type: fragment_type, parents: [*fragment_spread.parents, fragment_type])
|
|
@@ -212,6 +205,7 @@ module GraphQL
|
|
|
212
205
|
|
|
213
206
|
def find_conflict(response_key, field1, field2, mutually_exclusive: false)
|
|
214
207
|
return if @conflict_count >= context.max_errors
|
|
208
|
+
return if field1.definition.nil? || field2.definition.nil?
|
|
215
209
|
|
|
216
210
|
node1 = field1.node
|
|
217
211
|
node2 = field2.node
|
|
@@ -221,7 +215,7 @@ module GraphQL
|
|
|
221
215
|
|
|
222
216
|
if !are_mutually_exclusive
|
|
223
217
|
if node1.name != node2.name
|
|
224
|
-
conflict =
|
|
218
|
+
conflict = conflicts[:field][response_key]
|
|
225
219
|
|
|
226
220
|
conflict.add_conflict(node1, node1.name)
|
|
227
221
|
conflict.add_conflict(node2, node2.name)
|
|
@@ -230,7 +224,7 @@ module GraphQL
|
|
|
230
224
|
end
|
|
231
225
|
|
|
232
226
|
if !same_arguments?(node1, node2)
|
|
233
|
-
conflict =
|
|
227
|
+
conflict = conflicts[:argument][response_key]
|
|
234
228
|
|
|
235
229
|
conflict.add_conflict(node1, GraphQL::Language.serialize(serialize_field_args(node1)))
|
|
236
230
|
conflict.add_conflict(node2, GraphQL::Language.serialize(serialize_field_args(node2)))
|
|
@@ -239,6 +233,49 @@ module GraphQL
|
|
|
239
233
|
end
|
|
240
234
|
end
|
|
241
235
|
|
|
236
|
+
if !conflicts[:field].key?(response_key) &&
|
|
237
|
+
(t1 = field1.definition&.type) &&
|
|
238
|
+
(t2 = field2.definition&.type) &&
|
|
239
|
+
return_types_conflict?(t1, t2)
|
|
240
|
+
|
|
241
|
+
return_error = nil
|
|
242
|
+
message_override = nil
|
|
243
|
+
case @schema.allow_legacy_invalid_return_type_conflicts
|
|
244
|
+
when false
|
|
245
|
+
return_error = true
|
|
246
|
+
when true
|
|
247
|
+
legacy_handling = @schema.legacy_invalid_return_type_conflicts(@context.query, t1, t2, node1, node2)
|
|
248
|
+
case legacy_handling
|
|
249
|
+
when nil
|
|
250
|
+
return_error = false
|
|
251
|
+
when :return_validation_error
|
|
252
|
+
return_error = true
|
|
253
|
+
when String
|
|
254
|
+
return_error = true
|
|
255
|
+
message_override = legacy_handling
|
|
256
|
+
else
|
|
257
|
+
raise GraphQL::Error, "#{@schema}.legacy_invalid_scalar_conflicts returned unexpected value: #{legacy_handling.inspect}. Expected `nil`, String, or `:return_validation_error`."
|
|
258
|
+
end
|
|
259
|
+
else
|
|
260
|
+
return_error = false
|
|
261
|
+
@context.query.logger.warn <<~WARN
|
|
262
|
+
GraphQL-Ruby encountered mismatched types in this query: `#{t1.to_type_signature}` (at #{node1.line}:#{node1.col}) vs. `#{t2.to_type_signature}` (at #{node2.line}:#{node2.col}).
|
|
263
|
+
This will return an error in future GraphQL-Ruby versions, as per the GraphQL specification
|
|
264
|
+
Learn about migrating here: https://graphql-ruby.org/api-doc/#{GraphQL::VERSION}/GraphQL/Schema.html#allow_legacy_invalid_return_type_conflicts-class_method
|
|
265
|
+
WARN
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
if return_error
|
|
269
|
+
conflict = conflicts[:return_type][response_key]
|
|
270
|
+
if message_override
|
|
271
|
+
conflict.message = message_override
|
|
272
|
+
end
|
|
273
|
+
conflict.add_conflict(node1, "`#{t1.to_type_signature}`")
|
|
274
|
+
conflict.add_conflict(node2, "`#{t2.to_type_signature}`")
|
|
275
|
+
@conflict_count += 1
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
242
279
|
find_conflicts_between_sub_selection_sets(
|
|
243
280
|
field1,
|
|
244
281
|
field2,
|
|
@@ -246,6 +283,32 @@ module GraphQL
|
|
|
246
283
|
)
|
|
247
284
|
end
|
|
248
285
|
|
|
286
|
+
def return_types_conflict?(type1, type2)
|
|
287
|
+
if type1.list?
|
|
288
|
+
if type2.list?
|
|
289
|
+
return_types_conflict?(type1.of_type, type2.of_type)
|
|
290
|
+
else
|
|
291
|
+
true
|
|
292
|
+
end
|
|
293
|
+
elsif type2.list?
|
|
294
|
+
true
|
|
295
|
+
elsif type1.non_null?
|
|
296
|
+
if type2.non_null?
|
|
297
|
+
return_types_conflict?(type1.of_type, type2.of_type)
|
|
298
|
+
else
|
|
299
|
+
true
|
|
300
|
+
end
|
|
301
|
+
elsif type2.non_null?
|
|
302
|
+
true
|
|
303
|
+
elsif type1.kind.leaf? && type2.kind.leaf?
|
|
304
|
+
type1 != type2
|
|
305
|
+
else
|
|
306
|
+
# One or more of these are composite types,
|
|
307
|
+
# their selections will be validated later on.
|
|
308
|
+
false
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
249
312
|
def find_conflicts_between_sub_selection_sets(field1, field2, mutually_exclusive:)
|
|
250
313
|
return if field1.definition.nil? ||
|
|
251
314
|
field2.definition.nil? ||
|
|
@@ -340,11 +403,11 @@ module GraphQL
|
|
|
340
403
|
selections.each do |node|
|
|
341
404
|
case node
|
|
342
405
|
when GraphQL::Language::Nodes::Field
|
|
343
|
-
definition =
|
|
406
|
+
definition = @types.field(owner_type, node.name)
|
|
344
407
|
fields << Field.new(node, definition, owner_type, parents)
|
|
345
408
|
when GraphQL::Language::Nodes::InlineFragment
|
|
346
|
-
fragment_type = node.type ?
|
|
347
|
-
find_fields_and_fragments(node.selections, parents: [*parents, fragment_type], owner_type:
|
|
409
|
+
fragment_type = node.type ? @types.type(node.type.name) : owner_type
|
|
410
|
+
find_fields_and_fragments(node.selections, parents: [*parents, fragment_type], owner_type: fragment_type, fields: fields, fragment_spreads: fragment_spreads) if fragment_type
|
|
348
411
|
when GraphQL::Language::Nodes::FragmentSpread
|
|
349
412
|
fragment_spreads << FragmentSpread.new(node.name, parents)
|
|
350
413
|
end
|
|
@@ -396,7 +459,7 @@ module GraphQL
|
|
|
396
459
|
end
|
|
397
460
|
|
|
398
461
|
# Given two list of parents, find out if they are mutually exclusive
|
|
399
|
-
# In this context, `parents`
|
|
462
|
+
# In this context, `parents` represents the "self scope" of the field,
|
|
400
463
|
# what types may be found at this point in the query.
|
|
401
464
|
def mutually_exclusive?(parents1, parents2)
|
|
402
465
|
if parents1.empty? || parents2.empty?
|
|
@@ -411,8 +474,8 @@ module GraphQL
|
|
|
411
474
|
false
|
|
412
475
|
else
|
|
413
476
|
# Check if these two scopes have _any_ types in common.
|
|
414
|
-
possible_right_types = context.
|
|
415
|
-
possible_left_types = context.
|
|
477
|
+
possible_right_types = context.types.possible_types(type1)
|
|
478
|
+
possible_left_types = context.types.possible_types(type2)
|
|
416
479
|
(possible_right_types & possible_left_types).empty?
|
|
417
480
|
end
|
|
418
481
|
end
|
|
@@ -14,9 +14,11 @@ module GraphQL
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def message
|
|
17
|
-
"Field '#{field_name}' has #{kind == :argument ? 'an' : 'a'} #{kind} conflict: #{conflicts}?"
|
|
17
|
+
@message || "Field '#{field_name}' has #{kind == :argument ? 'an' : 'a'} #{kind} conflict: #{conflicts}?"
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
attr_writer :message
|
|
21
|
+
|
|
20
22
|
def path
|
|
21
23
|
[]
|
|
22
24
|
end
|
|
@@ -26,7 +28,13 @@ module GraphQL
|
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
def add_conflict(node, conflict_str)
|
|
29
|
-
|
|
31
|
+
# Can't use `.include?` here because AST nodes implement `#==`
|
|
32
|
+
# based on string value, not including location. But sometimes,
|
|
33
|
+
# identical nodes conflict because of their differing return types.
|
|
34
|
+
if nodes.any? { |n| n == node && n.line == node.line && n.col == node.col }
|
|
35
|
+
# already have an error for this node
|
|
36
|
+
return
|
|
37
|
+
end
|
|
30
38
|
|
|
31
39
|
@nodes << node
|
|
32
40
|
@conflicts << conflict_str
|
|
@@ -28,7 +28,7 @@ module GraphQL
|
|
|
28
28
|
frag_node = context.fragments[frag_spread.node.name]
|
|
29
29
|
if frag_node
|
|
30
30
|
fragment_child_name = frag_node.type.name
|
|
31
|
-
fragment_child =
|
|
31
|
+
fragment_child = @types.type(fragment_child_name)
|
|
32
32
|
# Might be non-existent type name
|
|
33
33
|
if fragment_child
|
|
34
34
|
validate_fragment_in_scope(frag_spread.parent_type, fragment_child, frag_spread.node, context, frag_spread.path)
|
|
@@ -44,8 +44,8 @@ module GraphQL
|
|
|
44
44
|
# It's not a valid fragment type, this error was handled someplace else
|
|
45
45
|
return
|
|
46
46
|
end
|
|
47
|
-
parent_types =
|
|
48
|
-
child_types =
|
|
47
|
+
parent_types = @types.possible_types(parent_type.unwrap)
|
|
48
|
+
child_types = @types.possible_types(child_type.unwrap)
|
|
49
49
|
|
|
50
50
|
if child_types.none? { |c| parent_types.include?(c) }
|
|
51
51
|
name = node.respond_to?(:name) ? " #{node.name}" : ""
|
|
@@ -21,10 +21,20 @@ module GraphQL
|
|
|
21
21
|
true
|
|
22
22
|
else
|
|
23
23
|
type_name = fragment_node.type.name
|
|
24
|
-
type =
|
|
24
|
+
type = @types.type(type_name)
|
|
25
25
|
if type.nil?
|
|
26
|
+
@all_possible_fragment_type_names ||= begin
|
|
27
|
+
names = []
|
|
28
|
+
context.types.all_types.each do |type|
|
|
29
|
+
if type.kind.fields?
|
|
30
|
+
names << type.graphql_name
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
names
|
|
34
|
+
end
|
|
35
|
+
|
|
26
36
|
add_error(GraphQL::StaticValidation::FragmentTypesExistError.new(
|
|
27
|
-
"No such type #{type_name}, so it can't be a fragment condition",
|
|
37
|
+
"No such type #{type_name}, so it can't be a fragment condition#{context.did_you_mean_suggestion(type_name, @all_possible_fragment_type_names)}",
|
|
28
38
|
nodes: fragment_node,
|
|
29
39
|
type: type_name
|
|
30
40
|
))
|
|
@@ -19,7 +19,7 @@ module GraphQL
|
|
|
19
19
|
true
|
|
20
20
|
else
|
|
21
21
|
type_name = node_type.to_query_string
|
|
22
|
-
type_def =
|
|
22
|
+
type_def = @types.type(type_name)
|
|
23
23
|
if type_def.nil? || !type_def.kind.composite?
|
|
24
24
|
add_error(GraphQL::StaticValidation::FragmentsAreOnCompositeTypesError.new(
|
|
25
25
|
"Invalid fragment on type #{type_name} (must be Union, Interface or Object)",
|
|
@@ -3,7 +3,7 @@ module GraphQL
|
|
|
3
3
|
module StaticValidation
|
|
4
4
|
module MutationRootExists
|
|
5
5
|
def on_operation_definition(node, _parent)
|
|
6
|
-
if node.operation_type == 'mutation' && context.
|
|
6
|
+
if node.operation_type == 'mutation' && context.query.types.mutation_root.nil?
|
|
7
7
|
add_error(GraphQL::StaticValidation::MutationRootExistsError.new(
|
|
8
8
|
'Schema is not configured for mutations',
|
|
9
9
|
nodes: node
|
|
@@ -32,7 +32,7 @@ module GraphQL
|
|
|
32
32
|
|
|
33
33
|
def on_document(node, parent)
|
|
34
34
|
super
|
|
35
|
-
if
|
|
35
|
+
if !@schema_definition_nodes.empty?
|
|
36
36
|
add_error(GraphQL::StaticValidation::NoDefinitionsArePresentError.new(%|Query cannot contain schema definitions|, nodes: @schema_definition_nodes))
|
|
37
37
|
end
|
|
38
38
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
module StaticValidation
|
|
4
|
+
class NotSingleSubscriptionError < StaticValidation::Error
|
|
5
|
+
def initialize(message, path: nil, nodes: [])
|
|
6
|
+
super(message, path: path, nodes: nodes)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# A hash representation of this Message
|
|
10
|
+
def to_h
|
|
11
|
+
extensions = {
|
|
12
|
+
"code" => code,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
super.merge({
|
|
16
|
+
"extensions" => extensions
|
|
17
|
+
})
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def code
|
|
21
|
+
"notSingleSubscription"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -3,7 +3,7 @@ module GraphQL
|
|
|
3
3
|
module StaticValidation
|
|
4
4
|
module QueryRootExists
|
|
5
5
|
def on_operation_definition(node, _parent)
|
|
6
|
-
if (node.operation_type == 'query' || node.operation_type.nil?) && context.
|
|
6
|
+
if (node.operation_type == 'query' || node.operation_type.nil?) && context.query.types.query_root.nil?
|
|
7
7
|
add_error(GraphQL::StaticValidation::QueryRootExistsError.new(
|
|
8
8
|
'Schema is not configured for queries',
|
|
9
9
|
nodes: node
|
|
@@ -16,15 +16,15 @@ module GraphQL
|
|
|
16
16
|
private
|
|
17
17
|
|
|
18
18
|
def assert_required_args(ast_node, defn)
|
|
19
|
-
args =
|
|
19
|
+
args = @context.query.types.arguments(defn)
|
|
20
20
|
return if args.empty?
|
|
21
21
|
present_argument_names = ast_node.arguments.map(&:name)
|
|
22
|
-
required_argument_names = context.
|
|
23
|
-
.select { |a| a.type.kind.non_null? && !a.default_value? && context.
|
|
22
|
+
required_argument_names = context.query.types.arguments(defn)
|
|
23
|
+
.select { |a| a.type.kind.non_null? && !a.default_value? && context.query.types.argument(defn, a.name) }
|
|
24
24
|
.map!(&:name)
|
|
25
25
|
|
|
26
26
|
missing_names = required_argument_names - present_argument_names
|
|
27
|
-
if missing_names.
|
|
27
|
+
if !missing_names.empty?
|
|
28
28
|
add_error(GraphQL::StaticValidation::RequiredArgumentsArePresentError.new(
|
|
29
29
|
"#{ast_node.class.name.split("::").last} '#{ast_node.name}' is missing required arguments: #{missing_names.join(", ")}",
|
|
30
30
|
nodes: ast_node,
|