graphql 1.13.17 → 2.0.20
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/install_generator.rb +1 -1
- data/lib/generators/graphql/relay.rb +3 -17
- data/lib/generators/graphql/templates/schema.erb +3 -0
- data/lib/graphql/analysis/ast/field_usage.rb +3 -1
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
- data/lib/graphql/analysis/ast/query_depth.rb +0 -1
- data/lib/graphql/analysis/ast/visitor.rb +43 -36
- data/lib/graphql/analysis/ast.rb +2 -12
- data/lib/graphql/analysis.rb +0 -7
- data/lib/graphql/backtrace/table.rb +2 -20
- data/lib/graphql/backtrace/tracer.rb +2 -3
- data/lib/graphql/backtrace.rb +2 -8
- data/lib/graphql/dataloader/null_dataloader.rb +3 -1
- data/lib/graphql/dataloader/source.rb +9 -0
- data/lib/graphql/dataloader.rb +4 -1
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/execution/errors.rb +12 -82
- data/lib/graphql/execution/interpreter/resolve.rb +26 -0
- data/lib/graphql/execution/interpreter/runtime.rb +159 -120
- data/lib/graphql/execution/interpreter.rb +187 -78
- data/lib/graphql/execution/lazy.rb +7 -21
- data/lib/graphql/execution/lookahead.rb +44 -40
- data/lib/graphql/execution/multiplex.rb +3 -174
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/introspection/directive_type.rb +2 -2
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +2 -15
- 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 +13 -6
- data/lib/graphql/introspection.rb +4 -3
- data/lib/graphql/language/document_from_schema_definition.rb +18 -35
- data/lib/graphql/language/lexer.rb +216 -1488
- data/lib/graphql/language/nodes.rb +65 -39
- data/lib/graphql/language/parser.rb +376 -364
- data/lib/graphql/language/parser.y +49 -44
- data/lib/graphql/language/printer.rb +37 -21
- data/lib/graphql/language/visitor.rb +191 -83
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/array_connection.rb +4 -2
- data/lib/graphql/pagination/connection.rb +31 -4
- data/lib/graphql/pagination/connections.rb +3 -28
- data/lib/graphql/pagination/relation_connection.rb +2 -0
- data/lib/graphql/query/context.rb +155 -196
- data/lib/graphql/query/input_validation_result.rb +1 -1
- data/lib/graphql/query/null_context.rb +0 -3
- data/lib/graphql/query/validation_pipeline.rb +10 -34
- data/lib/graphql/query/variables.rb +7 -20
- data/lib/graphql/query.rb +32 -42
- data/lib/graphql/railtie.rb +0 -104
- data/lib/graphql/rake_task/validate.rb +1 -1
- data/lib/graphql/rake_task.rb +29 -1
- data/lib/graphql/relay/range_add.rb +9 -20
- data/lib/graphql/relay.rb +0 -15
- data/lib/graphql/schema/addition.rb +7 -9
- data/lib/graphql/schema/argument.rb +36 -43
- data/lib/graphql/schema/build_from_definition.rb +32 -18
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +12 -23
- data/lib/graphql/schema/enum.rb +28 -39
- data/lib/graphql/schema/enum_value.rb +5 -25
- data/lib/graphql/schema/field/connection_extension.rb +4 -0
- data/lib/graphql/schema/field.rb +237 -339
- data/lib/graphql/schema/input_object.rb +56 -67
- data/lib/graphql/schema/interface.rb +0 -35
- data/lib/graphql/schema/introspection_system.rb +3 -8
- data/lib/graphql/schema/late_bound_type.rb +8 -2
- data/lib/graphql/schema/list.rb +0 -6
- data/lib/graphql/schema/loader.rb +1 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +17 -19
- data/lib/graphql/schema/member/build_type.rb +5 -7
- data/lib/graphql/schema/member/has_arguments.rb +146 -55
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -59
- data/lib/graphql/schema/member/has_fields.rb +17 -4
- data/lib/graphql/schema/member/has_interfaces.rb +49 -10
- data/lib/graphql/schema/member/has_validators.rb +31 -5
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
- data/lib/graphql/schema/member/validates_input.rb +1 -1
- data/lib/graphql/schema/member.rb +0 -6
- data/lib/graphql/schema/mutation.rb +0 -9
- data/lib/graphql/schema/non_null.rb +1 -7
- data/lib/graphql/schema/object.rb +15 -52
- data/lib/graphql/schema/relay_classic_mutation.rb +53 -42
- data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
- data/lib/graphql/schema/resolver.rb +41 -42
- data/lib/graphql/schema/scalar.rb +7 -22
- data/lib/graphql/schema/subscription.rb +0 -7
- data/lib/graphql/schema/timeout.rb +24 -28
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +10 -17
- data/lib/graphql/schema/warden.rb +34 -8
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +241 -973
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +4 -21
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/error.rb +2 -2
- data/lib/graphql/static_validation/literal_validator.rb +19 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +12 -12
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +12 -6
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
- data/lib/graphql/static_validation/validator.rb +3 -25
- data/lib/graphql/static_validation.rb +0 -2
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
- data/lib/graphql/subscriptions/event.rb +3 -8
- data/lib/graphql/subscriptions/instrumentation.rb +0 -51
- data/lib/graphql/subscriptions.rb +32 -20
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +231 -0
- data/lib/graphql/tracing/appsignal_trace.rb +71 -0
- data/lib/graphql/tracing/data_dog_trace.rb +148 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +41 -0
- data/lib/graphql/tracing/platform_trace.rb +107 -0
- data/lib/graphql/tracing/platform_tracing.rb +26 -40
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing.rb +136 -40
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/iso_8601_date.rb +4 -1
- data/lib/graphql/types/iso_8601_date_time.rb +4 -0
- data/lib/graphql/types/relay/base_connection.rb +16 -6
- data/lib/graphql/types/relay/connection_behaviors.rb +29 -27
- data/lib/graphql/types/relay/edge_behaviors.rb +16 -5
- data/lib/graphql/types/relay/node_behaviors.rb +12 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
- data/lib/graphql/types/relay.rb +0 -3
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +13 -74
- metadata +30 -133
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/field_usage.rb +0 -45
- data/lib/graphql/analysis/max_query_complexity.rb +0 -26
- data/lib/graphql/analysis/max_query_depth.rb +0 -26
- data/lib/graphql/analysis/query_complexity.rb +0 -88
- data/lib/graphql/analysis/query_depth.rb +0 -43
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -232
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -436
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -255
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -55
- data/lib/graphql/directive/deprecated_directive.rb +0 -2
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -107
- data/lib/graphql/enum_type.rb +0 -133
- data/lib/graphql/execution/execute.rb +0 -333
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/instrumentation.rb +0 -92
- data/lib/graphql/execution/lazy/resolve.rb +0 -91
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -226
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -128
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -138
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -72
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/language/lexer.rl +0 -260
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -130
- data/lib/graphql/query/arguments.rb +0 -189
- data/lib/graphql/query/arguments_cache.rb +0 -24
- data/lib/graphql/query/executor.rb +0 -52
- data/lib/graphql/query/literal_input.rb +0 -136
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -40
- data/lib/graphql/relay/array_connection.rb +0 -83
- data/lib/graphql/relay/base_connection.rb +0 -189
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -54
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -19
- data/lib/graphql/relay/edges_instrumentation.rb +0 -39
- data/lib/graphql/relay/global_id_resolve.rb +0 -17
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -106
- data/lib/graphql/relay/node.rb +0 -39
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -188
- data/lib/graphql/relay/type_extensions.rb +0 -32
- data/lib/graphql/scalar_type.rb +0 -91
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -17
- data/lib/graphql/schema/member/accepts_definition.rb +0 -164
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -44
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -88
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -313
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/subscription_root.rb +0 -76
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/default_relay.rb +0 -31
- data/lib/graphql/types/relay/node_field.rb +0 -24
- data/lib/graphql/types/relay/nodes_field.rb +0 -43
- data/lib/graphql/union_type.rb +0 -115
- data/lib/graphql/upgrader/member.rb +0 -937
- data/lib/graphql/upgrader/schema.rb +0 -38
@@ -14,11 +14,6 @@ module GraphQL
|
|
14
14
|
super(document)
|
15
15
|
end
|
16
16
|
|
17
|
-
# This will be overwritten by {InternalRepresentation::Rewrite} if it's included
|
18
|
-
def rewrite_document
|
19
|
-
nil
|
20
|
-
end
|
21
|
-
|
22
17
|
attr_reader :context
|
23
18
|
|
24
19
|
# @return [Array<GraphQL::ObjectType>] Types whose scope we've entered
|
@@ -32,22 +27,13 @@ module GraphQL
|
|
32
27
|
# Build a class to visit the AST and perform validation,
|
33
28
|
# or use a pre-built class if rules is `ALL_RULES` or empty.
|
34
29
|
# @param rules [Array<Module, Class>]
|
35
|
-
# @param rewrite [Boolean] if `false`, don't include rewrite
|
36
30
|
# @return [Class] A class for validating `rules` during visitation
|
37
|
-
def self.including_rules(rules
|
31
|
+
def self.including_rules(rules)
|
38
32
|
if rules.empty?
|
39
|
-
|
40
|
-
|
41
|
-
else
|
42
|
-
# It's not doing _anything?!?_
|
43
|
-
BaseVisitor
|
44
|
-
end
|
33
|
+
# It's not doing _anything?!?_
|
34
|
+
BaseVisitor
|
45
35
|
elsif rules == ALL_RULES
|
46
|
-
|
47
|
-
DefaultVisitor
|
48
|
-
else
|
49
|
-
InterpreterVisitor
|
50
|
-
end
|
36
|
+
InterpreterVisitor
|
51
37
|
else
|
52
38
|
visitor_class = Class.new(self) do
|
53
39
|
include(GraphQL::StaticValidation::DefinitionDependencies)
|
@@ -60,9 +46,6 @@ module GraphQL
|
|
60
46
|
end
|
61
47
|
end
|
62
48
|
|
63
|
-
if rewrite
|
64
|
-
visitor_class.include(GraphQL::InternalRepresentation::Rewrite)
|
65
|
-
end
|
66
49
|
visitor_class.include(ContextMethods)
|
67
50
|
visitor_class
|
68
51
|
end
|
@@ -127,8 +127,14 @@ module GraphQL
|
|
127
127
|
# same name as if they were the same name. If _any_ of the fragments
|
128
128
|
# with that name has a dependency, we record it.
|
129
129
|
independent_fragment_nodes = @defdep_fragment_definitions.values.flatten - @defdep_immediate_dependencies.keys
|
130
|
-
|
130
|
+
visited_fragment_names = Set.new
|
131
131
|
while fragment_node = independent_fragment_nodes.pop
|
132
|
+
if visited_fragment_names.add?(fragment_node.name)
|
133
|
+
# this is a new fragment name
|
134
|
+
else
|
135
|
+
# this is a duplicate fragment name
|
136
|
+
next
|
137
|
+
end
|
132
138
|
loops += 1
|
133
139
|
if loops > max_loops
|
134
140
|
raise("Resolution loops exceeded the number of definitions; infinite loop detected. (Max: #{max_loops}, Current: #{loops})")
|
@@ -18,6 +18,19 @@ module GraphQL
|
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
|
+
def replace_nulls_in(ast_value)
|
22
|
+
case ast_value
|
23
|
+
when Array
|
24
|
+
ast_value.map { |v| replace_nulls_in(v) }
|
25
|
+
when GraphQL::Language::Nodes::InputObject
|
26
|
+
ast_value.to_h
|
27
|
+
when GraphQL::Language::Nodes::NullValue
|
28
|
+
nil
|
29
|
+
else
|
30
|
+
ast_value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
21
34
|
def recursively_validate(ast_value, type)
|
22
35
|
if type.nil?
|
23
36
|
# this means we're an undefined argument, see #present_input_field_values_are_valid
|
@@ -42,7 +55,8 @@ module GraphQL
|
|
42
55
|
@valid_response
|
43
56
|
elsif type.kind.scalar? && constant_scalar?(ast_value)
|
44
57
|
maybe_raise_if_invalid(ast_value) do
|
45
|
-
|
58
|
+
ruby_value = replace_nulls_in(ast_value)
|
59
|
+
type.validate_input(ruby_value, @context)
|
46
60
|
end
|
47
61
|
elsif type.kind.enum?
|
48
62
|
maybe_raise_if_invalid(ast_value) do
|
@@ -108,6 +122,10 @@ module GraphQL
|
|
108
122
|
arg_type = @warden.get_argument(type, name).type
|
109
123
|
recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
|
110
124
|
end
|
125
|
+
|
126
|
+
if type.one_of? && ast_node.arguments.size != 1
|
127
|
+
results << Query::InputValidationResult.from_problem("`#{type.graphql_name}` is a OneOf type, so only one argument may be given (instead of #{ast_node.arguments.size})")
|
128
|
+
end
|
111
129
|
merge_results(results)
|
112
130
|
end
|
113
131
|
end
|
@@ -9,11 +9,17 @@ module GraphQL
|
|
9
9
|
|
10
10
|
def on_directive(node, parent)
|
11
11
|
if !@directive_names.include?(node.name)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
@directives_are_defined_errors_by_name ||= {}
|
13
|
+
error = @directives_are_defined_errors_by_name[node.name] ||= begin
|
14
|
+
err = GraphQL::StaticValidation::DirectivesAreDefinedError.new(
|
15
|
+
"Directive @#{node.name} is not defined",
|
16
|
+
nodes: [],
|
17
|
+
directive: node.name
|
18
|
+
)
|
19
|
+
add_error(err)
|
20
|
+
err
|
21
|
+
end
|
22
|
+
error.nodes << node
|
17
23
|
else
|
18
24
|
super
|
19
25
|
end
|
@@ -12,20 +12,20 @@ module GraphQL
|
|
12
12
|
private
|
13
13
|
|
14
14
|
LOCATION_MESSAGE_NAMES = {
|
15
|
-
GraphQL::Directive::QUERY => "queries",
|
16
|
-
GraphQL::Directive::MUTATION => "mutations",
|
17
|
-
GraphQL::Directive::SUBSCRIPTION => "subscriptions",
|
18
|
-
GraphQL::Directive::FIELD => "fields",
|
19
|
-
GraphQL::Directive::FRAGMENT_DEFINITION => "fragment definitions",
|
20
|
-
GraphQL::Directive::FRAGMENT_SPREAD => "fragment spreads",
|
21
|
-
GraphQL::Directive::INLINE_FRAGMENT => "inline fragments",
|
15
|
+
GraphQL::Schema::Directive::QUERY => "queries",
|
16
|
+
GraphQL::Schema::Directive::MUTATION => "mutations",
|
17
|
+
GraphQL::Schema::Directive::SUBSCRIPTION => "subscriptions",
|
18
|
+
GraphQL::Schema::Directive::FIELD => "fields",
|
19
|
+
GraphQL::Schema::Directive::FRAGMENT_DEFINITION => "fragment definitions",
|
20
|
+
GraphQL::Schema::Directive::FRAGMENT_SPREAD => "fragment spreads",
|
21
|
+
GraphQL::Schema::Directive::INLINE_FRAGMENT => "inline fragments",
|
22
22
|
}
|
23
23
|
|
24
24
|
SIMPLE_LOCATIONS = {
|
25
|
-
Nodes::Field => GraphQL::Directive::FIELD,
|
26
|
-
Nodes::InlineFragment => GraphQL::Directive::INLINE_FRAGMENT,
|
27
|
-
Nodes::FragmentSpread => GraphQL::Directive::FRAGMENT_SPREAD,
|
28
|
-
Nodes::FragmentDefinition => GraphQL::Directive::FRAGMENT_DEFINITION,
|
25
|
+
Nodes::Field => GraphQL::Schema::Directive::FIELD,
|
26
|
+
Nodes::InlineFragment => GraphQL::Schema::Directive::INLINE_FRAGMENT,
|
27
|
+
Nodes::FragmentSpread => GraphQL::Schema::Directive::FRAGMENT_SPREAD,
|
28
|
+
Nodes::FragmentDefinition => GraphQL::Schema::Directive::FRAGMENT_DEFINITION,
|
29
29
|
}
|
30
30
|
|
31
31
|
SIMPLE_LOCATION_NODES = SIMPLE_LOCATIONS.keys
|
@@ -34,7 +34,7 @@ module GraphQL
|
|
34
34
|
directive_defn = directives[ast_directive.name]
|
35
35
|
case ast_parent
|
36
36
|
when Nodes::OperationDefinition
|
37
|
-
required_location = GraphQL::Directive.const_get(ast_parent.operation_type.upcase)
|
37
|
+
required_location = GraphQL::Schema::Directive.const_get(ast_parent.operation_type.upcase)
|
38
38
|
assert_includes_location(directive_defn, ast_directive, required_location)
|
39
39
|
when *SIMPLE_LOCATION_NODES
|
40
40
|
required_location = SIMPLE_LOCATIONS[ast_parent.class]
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
module OneOfInputObjectsAreValid
|
5
|
+
def on_input_object(node, parent)
|
6
|
+
return super unless parent.is_a?(GraphQL::Language::Nodes::Argument)
|
7
|
+
|
8
|
+
parent_type = get_parent_type(context, parent)
|
9
|
+
return super unless parent_type && parent_type.kind.input_object? && parent_type.one_of?
|
10
|
+
|
11
|
+
validate_one_of_input_object(node, context, parent_type)
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def validate_one_of_input_object(ast_node, context, parent_type)
|
18
|
+
present_fields = ast_node.arguments.map(&:name)
|
19
|
+
input_object_type = parent_type.to_type_signature
|
20
|
+
|
21
|
+
if present_fields.count != 1
|
22
|
+
add_error(
|
23
|
+
OneOfInputObjectsAreValidError.new(
|
24
|
+
"OneOf Input Object '#{input_object_type}' must specify exactly one key.",
|
25
|
+
path: context.path,
|
26
|
+
nodes: ast_node,
|
27
|
+
input_object_type: input_object_type
|
28
|
+
)
|
29
|
+
)
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
33
|
+
field = present_fields.first
|
34
|
+
value = ast_node.arguments.first.value
|
35
|
+
|
36
|
+
if value.is_a?(GraphQL::Language::Nodes::NullValue)
|
37
|
+
add_error(
|
38
|
+
OneOfInputObjectsAreValidError.new(
|
39
|
+
"Argument '#{input_object_type}.#{field}' must be non-null.",
|
40
|
+
path: [*context.path, field],
|
41
|
+
nodes: ast_node.arguments.first,
|
42
|
+
input_object_type: input_object_type
|
43
|
+
)
|
44
|
+
)
|
45
|
+
return
|
46
|
+
end
|
47
|
+
|
48
|
+
if value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
49
|
+
variable_name = value.name
|
50
|
+
variable_type = @declared_variables[variable_name].type
|
51
|
+
|
52
|
+
unless variable_type.is_a?(GraphQL::Language::Nodes::NonNullType)
|
53
|
+
add_error(
|
54
|
+
OneOfInputObjectsAreValidError.new(
|
55
|
+
"Variable '#{variable_name}' must be non-nullable to be used for OneOf Input Object '#{input_object_type}'.",
|
56
|
+
path: [*context.path, field],
|
57
|
+
nodes: ast_node,
|
58
|
+
input_object_type: input_object_type
|
59
|
+
)
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class OneOfInputObjectsAreValidError < StaticValidation::Error
|
5
|
+
attr_reader :input_object_type
|
6
|
+
|
7
|
+
def initialize(message, path:, nodes:, input_object_type:)
|
8
|
+
super(message, path: path, nodes: nodes)
|
9
|
+
@input_object_type = input_object_type
|
10
|
+
end
|
11
|
+
|
12
|
+
# A hash representation of this Message
|
13
|
+
def to_h
|
14
|
+
extensions = {
|
15
|
+
"code" => code,
|
16
|
+
"inputObjectType" => input_object_type
|
17
|
+
}
|
18
|
+
|
19
|
+
super.merge({
|
20
|
+
"extensions" => extensions
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
def code
|
25
|
+
"invalidOneOfInputObject"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -34,12 +34,18 @@ module GraphQL
|
|
34
34
|
used_directives = {}
|
35
35
|
node.directives.each do |ast_directive|
|
36
36
|
directive_name = ast_directive.name
|
37
|
-
if used_directives[directive_name]
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
37
|
+
if (first_node = used_directives[directive_name])
|
38
|
+
@directives_are_unique_errors_by_first_node ||= {}
|
39
|
+
err = @directives_are_unique_errors_by_first_node[first_node] ||= begin
|
40
|
+
error = GraphQL::StaticValidation::UniqueDirectivesPerLocationError.new(
|
41
|
+
"The directive \"#{directive_name}\" can only be used once at this location.",
|
42
|
+
nodes: [used_directives[directive_name]],
|
43
|
+
directive: directive_name,
|
44
|
+
)
|
45
|
+
add_error(error)
|
46
|
+
error
|
47
|
+
end
|
48
|
+
err.nodes << ast_directive
|
43
49
|
elsif !((dir_defn = context.schema_directives[directive_name]) && dir_defn.repeatable?)
|
44
50
|
used_directives[directive_name] = ast_directive
|
45
51
|
end
|
@@ -23,7 +23,7 @@ module GraphQL
|
|
23
23
|
problems = validation_result.problems
|
24
24
|
first_problem = problems && problems.first
|
25
25
|
if first_problem
|
26
|
-
error_message = first_problem["
|
26
|
+
error_message = first_problem["explanation"]
|
27
27
|
end
|
28
28
|
|
29
29
|
error_message ||= "Default value for $#{node.name} doesn't match type #{type.to_type_signature}"
|
@@ -27,13 +27,12 @@ module GraphQL
|
|
27
27
|
# @param max_errors [Integer] Maximum number of errors before aborting validation. Any positive number will limit the number of errors. Defaults to nil for no limit.
|
28
28
|
# @return [Array<Hash>]
|
29
29
|
def validate(query, validate: true, timeout: nil, max_errors: nil)
|
30
|
-
query.
|
31
|
-
|
32
|
-
errors = if validate == false && can_skip_rewrite
|
30
|
+
query.current_trace.validate(validate: validate, query: query) do
|
31
|
+
errors = if validate == false
|
33
32
|
[]
|
34
33
|
else
|
35
34
|
rules_to_use = validate ? @rules : []
|
36
|
-
visitor_class = BaseVisitor.including_rules(rules_to_use
|
35
|
+
visitor_class = BaseVisitor.including_rules(rules_to_use)
|
37
36
|
|
38
37
|
context = GraphQL::StaticValidation::ValidationContext.new(query, visitor_class, max_errors)
|
39
38
|
|
@@ -42,18 +41,6 @@ module GraphQL
|
|
42
41
|
# A timeout value of 0 or nil will execute the block without any timeout.
|
43
42
|
Timeout::timeout(timeout) do
|
44
43
|
catch(:too_many_validation_errors) do
|
45
|
-
# Attach legacy-style rules.
|
46
|
-
# Only loop through rules if it has legacy-style rules
|
47
|
-
unless (legacy_rules = rules_to_use - GraphQL::StaticValidation::ALL_RULES).empty?
|
48
|
-
legacy_rules.each do |rule_class_or_module|
|
49
|
-
if rule_class_or_module.method_defined?(:validate)
|
50
|
-
GraphQL::Deprecation.warn "Legacy validator rules will be removed from GraphQL-Ruby 2.0, use a module instead (see the built-in rules: https://github.com/rmosolgo/graphql-ruby/tree/master/lib/graphql/static_validation/rules)"
|
51
|
-
GraphQL::Deprecation.warn " -> Legacy validator: #{rule_class_or_module}"
|
52
|
-
rule_class_or_module.new.validate(context)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
44
|
context.visitor.visit
|
58
45
|
end
|
59
46
|
end
|
@@ -64,22 +51,13 @@ module GraphQL
|
|
64
51
|
context.errors
|
65
52
|
end
|
66
53
|
|
67
|
-
irep = if errors.empty? && context
|
68
|
-
# Only return this if there are no errors and validation was actually run
|
69
|
-
context.visitor.rewrite_document
|
70
|
-
else
|
71
|
-
nil
|
72
|
-
end
|
73
|
-
|
74
54
|
{
|
75
55
|
errors: errors,
|
76
|
-
irep: irep,
|
77
56
|
}
|
78
57
|
end
|
79
58
|
rescue GraphQL::ExecutionError => e
|
80
59
|
{
|
81
60
|
errors: [e],
|
82
|
-
irep: nil,
|
83
61
|
}
|
84
62
|
end
|
85
63
|
|
@@ -7,7 +7,6 @@ require "graphql/static_validation/validation_context"
|
|
7
7
|
require "graphql/static_validation/validation_timeout_error"
|
8
8
|
require "graphql/static_validation/literal_validator"
|
9
9
|
require "graphql/static_validation/base_visitor"
|
10
|
-
require "graphql/static_validation/no_validate_visitor"
|
11
10
|
|
12
11
|
rules_glob = File.expand_path("../static_validation/rules/*.rb", __FILE__)
|
13
12
|
Dir.glob(rules_glob).each do |file|
|
@@ -15,5 +14,4 @@ Dir.glob(rules_glob).each do |file|
|
|
15
14
|
end
|
16
15
|
|
17
16
|
require "graphql/static_validation/all_rules"
|
18
|
-
require "graphql/static_validation/default_visitor"
|
19
17
|
require "graphql/static_validation/interpreter_visitor"
|
@@ -91,7 +91,13 @@ module GraphQL
|
|
91
91
|
# A per-process map of subscriptions to deliver.
|
92
92
|
# This is provided by Rails, so let's use it
|
93
93
|
@subscriptions = Concurrent::Map.new
|
94
|
-
@events = Concurrent::Map.new
|
94
|
+
@events = Concurrent::Map.new do |h, k|
|
95
|
+
h.compute_if_absent(k) do
|
96
|
+
Concurrent::Map.new do |h2, k2|
|
97
|
+
h2.compute_if_absent(k2) { Concurrent::Array.new }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
95
101
|
@action_cable = action_cable
|
96
102
|
@action_cable_coder = action_cable_coder
|
97
103
|
@serializer = serializer
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
class Subscriptions
|
4
|
-
class DefaultSubscriptionResolveExtension < GraphQL::
|
4
|
+
class DefaultSubscriptionResolveExtension < GraphQL::Schema::FieldExtension
|
5
5
|
def resolve(context:, object:, arguments:)
|
6
6
|
has_override_implementation = @field.resolver ||
|
7
7
|
object.respond_to?(@field.resolver_method)
|
@@ -16,6 +16,43 @@ module GraphQL
|
|
16
16
|
yield(object, arguments)
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
def after_resolve(value:, context:, object:, arguments:, **rest)
|
21
|
+
if value.is_a?(GraphQL::ExecutionError)
|
22
|
+
value
|
23
|
+
elsif (events = context.namespace(:subscriptions)[:events])
|
24
|
+
# This is the first execution, so gather an Event
|
25
|
+
# for the backend to register:
|
26
|
+
event = Subscriptions::Event.new(
|
27
|
+
name: field.name,
|
28
|
+
arguments: arguments_without_field_extras(arguments: arguments),
|
29
|
+
context: context,
|
30
|
+
field: field,
|
31
|
+
)
|
32
|
+
events << event
|
33
|
+
value
|
34
|
+
elsif context.query.subscription_topic == Subscriptions::Event.serialize(
|
35
|
+
field.name,
|
36
|
+
arguments_without_field_extras(arguments: arguments),
|
37
|
+
field,
|
38
|
+
scope: (field.subscription_scope ? context[field.subscription_scope] : nil),
|
39
|
+
)
|
40
|
+
# This is a subscription update. The resolver returned `skip` if it should be skipped,
|
41
|
+
# or else it returned an object to resolve the update.
|
42
|
+
value
|
43
|
+
else
|
44
|
+
# This is a subscription update, but this event wasn't triggered.
|
45
|
+
context.skip
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def arguments_without_field_extras(arguments:)
|
52
|
+
arguments.dup.tap do |event_args|
|
53
|
+
field.extras.each { |k| event_args.delete(k) }
|
54
|
+
end
|
55
|
+
end
|
19
56
|
end
|
20
57
|
end
|
21
58
|
end
|
@@ -9,7 +9,7 @@ module GraphQL
|
|
9
9
|
# @return [String] Corresponds to the Subscription root field name
|
10
10
|
attr_reader :name
|
11
11
|
|
12
|
-
# @return [GraphQL::
|
12
|
+
# @return [GraphQL::Execution::Interpreter::Arguments]
|
13
13
|
attr_reader :arguments
|
14
14
|
|
15
15
|
# @return [GraphQL::Query::Context]
|
@@ -100,13 +100,8 @@ module GraphQL
|
|
100
100
|
arg_name = k.to_s
|
101
101
|
camelized_arg_name = GraphQL::Schema::Member::BuildType.camelize(arg_name)
|
102
102
|
arg_defn = get_arg_definition(arg_owner, camelized_arg_name, context)
|
103
|
-
|
104
|
-
|
105
|
-
normalized_arg_name = camelized_arg_name
|
106
|
-
else
|
107
|
-
normalized_arg_name = arg_name
|
108
|
-
arg_defn = get_arg_definition(arg_owner, normalized_arg_name, context)
|
109
|
-
end
|
103
|
+
arg_defn ||= get_arg_definition(arg_owner, arg_name, context)
|
104
|
+
normalized_arg_name = arg_defn.graphql_name
|
110
105
|
arg_base_type = arg_defn.type.unwrap
|
111
106
|
# In the case where the value being emitted is seen as a "JSON"
|
112
107
|
# type, treat the value as one atomic unit of serialization
|
@@ -9,16 +9,6 @@ module GraphQL
|
|
9
9
|
@schema = schema
|
10
10
|
end
|
11
11
|
|
12
|
-
def instrument(type, field)
|
13
|
-
if type == @schema.subscription.graphql_definition
|
14
|
-
# This is a root field of `subscription`
|
15
|
-
subscribing_resolve_proc = SubscriptionRegistrationResolve.new(field.resolve_proc)
|
16
|
-
field.redefine(resolve: subscribing_resolve_proc)
|
17
|
-
else
|
18
|
-
field
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
12
|
# If needed, prepare to gather events which this query subscribes to
|
23
13
|
def before_query(query)
|
24
14
|
if query.subscription? && !query.subscription_update?
|
@@ -33,47 +23,6 @@ module GraphQL
|
|
33
23
|
@schema.subscriptions.write_subscription(query, events)
|
34
24
|
end
|
35
25
|
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
class SubscriptionRegistrationResolve
|
40
|
-
def initialize(inner_proc)
|
41
|
-
@inner_proc = inner_proc
|
42
|
-
end
|
43
|
-
|
44
|
-
# Wrap the proc with subscription registration logic
|
45
|
-
def call(obj, args, ctx)
|
46
|
-
result = nil
|
47
|
-
if @inner_proc && !@inner_proc.is_a?(GraphQL::Field::Resolve::BuiltInResolve)
|
48
|
-
result = @inner_proc.call(obj, args, ctx)
|
49
|
-
end
|
50
|
-
|
51
|
-
events = ctx.namespace(:subscriptions)[:events]
|
52
|
-
|
53
|
-
if events
|
54
|
-
# This is the first execution, so gather an Event
|
55
|
-
# for the backend to register:
|
56
|
-
events << Subscriptions::Event.new(
|
57
|
-
name: ctx.field.name,
|
58
|
-
arguments: args,
|
59
|
-
context: ctx,
|
60
|
-
)
|
61
|
-
result
|
62
|
-
elsif ctx.irep_node.subscription_topic == ctx.query.subscription_topic
|
63
|
-
if !result.nil?
|
64
|
-
result
|
65
|
-
elsif obj.is_a?(GraphQL::Schema::Object)
|
66
|
-
# The root object is _already_ the subscription update:
|
67
|
-
obj.object
|
68
|
-
else
|
69
|
-
obj
|
70
|
-
end
|
71
|
-
else
|
72
|
-
# This is a subscription update, but this event wasn't triggered.
|
73
|
-
ctx.skip
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
26
|
end
|
78
27
|
end
|
79
28
|
end
|