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
@@ -12,16 +12,6 @@ module GraphQL
|
|
12
12
|
#
|
13
13
|
# Also, `#unsubscribe` terminates the subscription.
|
14
14
|
class Subscription < GraphQL::Schema::Resolver
|
15
|
-
class EarlyTerminationError < StandardError
|
16
|
-
end
|
17
|
-
|
18
|
-
# Raised when `unsubscribe` is called; caught by `subscriptions.rb`
|
19
|
-
class UnsubscribedError < EarlyTerminationError
|
20
|
-
end
|
21
|
-
|
22
|
-
# Raised when `no_update` is returned; caught by `subscriptions.rb`
|
23
|
-
class NoUpdateError < EarlyTerminationError
|
24
|
-
end
|
25
15
|
extend GraphQL::Schema::Resolver::HasPayloadType
|
26
16
|
extend GraphQL::Schema::Member::HasFields
|
27
17
|
|
@@ -39,12 +29,12 @@ module GraphQL
|
|
39
29
|
def resolve(**args)
|
40
30
|
# Dispatch based on `@mode`, which will raise a `NoMethodError` if we ever
|
41
31
|
# have an unexpected `@mode`
|
42
|
-
public_send("resolve_#{@mode}", args)
|
32
|
+
public_send("resolve_#{@mode}", **args)
|
43
33
|
end
|
44
34
|
|
45
35
|
# Wrap the user-defined `#subscribe` hook
|
46
|
-
def resolve_subscribe(args)
|
47
|
-
ret_val = args.any? ? subscribe(args) : subscribe
|
36
|
+
def resolve_subscribe(**args)
|
37
|
+
ret_val = args.any? ? subscribe(**args) : subscribe
|
48
38
|
if ret_val == :no_response
|
49
39
|
context.skip
|
50
40
|
else
|
@@ -62,10 +52,10 @@ module GraphQL
|
|
62
52
|
end
|
63
53
|
|
64
54
|
# Wrap the user-provided `#update` hook
|
65
|
-
def resolve_update(args)
|
66
|
-
ret_val = args.any? ? update(args) : update
|
55
|
+
def resolve_update(**args)
|
56
|
+
ret_val = args.any? ? update(**args) : update
|
67
57
|
if ret_val == :no_update
|
68
|
-
|
58
|
+
throw :graphql_no_subscription_update
|
69
59
|
else
|
70
60
|
ret_val
|
71
61
|
end
|
@@ -90,14 +80,14 @@ module GraphQL
|
|
90
80
|
|
91
81
|
# Call this to halt execution and remove this subscription from the system
|
92
82
|
def unsubscribe
|
93
|
-
|
83
|
+
throw :graphql_subscription_unsubscribed
|
94
84
|
end
|
95
85
|
|
86
|
+
READING_SCOPE = ::Object.new
|
96
87
|
# Call this method to provide a new subscription_scope; OR
|
97
88
|
# call it without an argument to get the subscription_scope
|
98
89
|
# @param new_scope [Symbol]
|
99
90
|
# @return [Symbol]
|
100
|
-
READING_SCOPE = ::Object.new
|
101
91
|
def self.subscription_scope(new_scope = READING_SCOPE)
|
102
92
|
if new_scope != READING_SCOPE
|
103
93
|
@subscription_scope = new_scope
|
@@ -7,7 +7,7 @@ module GraphQL
|
|
7
7
|
# to the `errors` key. Any already-resolved fields will be in the `data` key, so
|
8
8
|
# you'll get a partial response.
|
9
9
|
#
|
10
|
-
# You can subclass `GraphQL::Schema::Timeout` and override
|
10
|
+
# You can subclass `GraphQL::Schema::Timeout` and override `max_seconds` and/or `handle_timeout`
|
11
11
|
# to provide custom logic when a timeout error occurs.
|
12
12
|
#
|
13
13
|
# Note that this will stop a query _in between_ field resolutions, but
|
@@ -33,8 +33,6 @@ module GraphQL
|
|
33
33
|
# end
|
34
34
|
#
|
35
35
|
class Timeout
|
36
|
-
attr_reader :max_seconds
|
37
|
-
|
38
36
|
def self.use(schema, **options)
|
39
37
|
tracer = new(**options)
|
40
38
|
schema.tracer(tracer)
|
@@ -48,32 +46,39 @@ module GraphQL
|
|
48
46
|
def trace(key, data)
|
49
47
|
case key
|
50
48
|
when 'execute_multiplex'
|
51
|
-
timeout_state = {
|
52
|
-
timeout_at: Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) + max_seconds * 1000,
|
53
|
-
timed_out: false
|
54
|
-
}
|
55
|
-
|
56
49
|
data.fetch(:multiplex).queries.each do |query|
|
50
|
+
timeout_duration_s = max_seconds(query)
|
51
|
+
timeout_state = if timeout_duration_s == false
|
52
|
+
# if the method returns `false`, don't apply a timeout
|
53
|
+
false
|
54
|
+
else
|
55
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
56
|
+
timeout_at = now + (max_seconds(query) * 1000)
|
57
|
+
{
|
58
|
+
timeout_at: timeout_at,
|
59
|
+
timed_out: false
|
60
|
+
}
|
61
|
+
end
|
57
62
|
query.context.namespace(self.class)[:state] = timeout_state
|
58
63
|
end
|
59
64
|
|
60
65
|
yield
|
61
66
|
when 'execute_field', 'execute_field_lazy'
|
62
|
-
|
63
|
-
timeout_state =
|
64
|
-
|
67
|
+
query_context = data[:context] || data[:query].context
|
68
|
+
timeout_state = query_context.namespace(self.class).fetch(:state)
|
69
|
+
# If the `:state` is `false`, then `max_seconds(query)` opted out of timeout for this query.
|
70
|
+
if timeout_state != false && Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) > timeout_state.fetch(:timeout_at)
|
65
71
|
error = if data[:context]
|
66
|
-
|
67
|
-
GraphQL::Schema::Timeout::TimeoutError.new(context.parent_type, context.field)
|
72
|
+
GraphQL::Schema::Timeout::TimeoutError.new(query_context.parent_type, query_context.field)
|
68
73
|
else
|
69
74
|
field = data.fetch(:field)
|
70
75
|
GraphQL::Schema::Timeout::TimeoutError.new(field.owner, field)
|
71
76
|
end
|
72
77
|
|
73
78
|
# Only invoke the timeout callback for the first timeout
|
74
|
-
|
79
|
+
if !timeout_state[:timed_out]
|
75
80
|
timeout_state[:timed_out] = true
|
76
|
-
handle_timeout(error, query)
|
81
|
+
handle_timeout(error, query_context.query)
|
77
82
|
end
|
78
83
|
|
79
84
|
error
|
@@ -85,6 +90,15 @@ module GraphQL
|
|
85
90
|
end
|
86
91
|
end
|
87
92
|
|
93
|
+
# Called at the start of each query.
|
94
|
+
# The default implementation returns the `max_seconds:` value from installing this plugin.
|
95
|
+
#
|
96
|
+
# @param query [GraphQL::Query] The query that's about to run
|
97
|
+
# @return [Integer, false] The number of seconds after which to interrupt query execution and call {#handle_error}, or `false` to bypass the timeout.
|
98
|
+
def max_seconds(query)
|
99
|
+
@max_seconds
|
100
|
+
end
|
101
|
+
|
88
102
|
# Invoked when a query times out.
|
89
103
|
# @param error [GraphQL::Schema::Timeout::TimeoutError]
|
90
104
|
# @param query [GraphQL::Error]
|
@@ -113,7 +113,7 @@ Some late-bound types couldn't be resolved:
|
|
113
113
|
# Find the starting points, then visit them
|
114
114
|
visit_roots = [member.query, member.mutation, member.subscription]
|
115
115
|
if @introspection
|
116
|
-
introspection_types = schema.introspection_system.
|
116
|
+
introspection_types = schema.introspection_system.types.values
|
117
117
|
visit_roots.concat(introspection_types)
|
118
118
|
if member.query
|
119
119
|
member.introspection_system.entry_points.each do |introspection_field|
|
@@ -5,29 +5,37 @@ module GraphQL
|
|
5
5
|
module TypeExpression
|
6
6
|
# Fetch a type from a type map by its AST specification.
|
7
7
|
# Return `nil` if not found.
|
8
|
-
# @param
|
8
|
+
# @param type_owner [#get_type] A thing for looking up types by name
|
9
9
|
# @param ast_node [GraphQL::Language::Nodes::AbstractNode]
|
10
|
-
# @return [GraphQL::
|
11
|
-
def self.build_type(
|
10
|
+
# @return [Class, GraphQL::Schema::NonNull, GraphQL::Schema:List]
|
11
|
+
def self.build_type(type_owner, ast_node)
|
12
12
|
case ast_node
|
13
13
|
when GraphQL::Language::Nodes::TypeName
|
14
|
-
|
14
|
+
type_owner.get_type(ast_node.name)
|
15
15
|
when GraphQL::Language::Nodes::NonNullType
|
16
16
|
ast_inner_type = ast_node.of_type
|
17
|
-
inner_type = build_type(
|
18
|
-
wrap_type(inner_type,
|
17
|
+
inner_type = build_type(type_owner, ast_inner_type)
|
18
|
+
wrap_type(inner_type, :to_non_null_type)
|
19
19
|
when GraphQL::Language::Nodes::ListType
|
20
20
|
ast_inner_type = ast_node.of_type
|
21
|
-
inner_type = build_type(
|
22
|
-
wrap_type(inner_type,
|
21
|
+
inner_type = build_type(type_owner, ast_inner_type)
|
22
|
+
wrap_type(inner_type, :to_list_type)
|
23
|
+
else
|
24
|
+
raise "Invariant: unexpected type from ast: #{ast_node.inspect}"
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
class << self
|
29
|
+
private
|
30
|
+
|
31
|
+
def wrap_type(type, wrapper_method)
|
32
|
+
if type.nil?
|
33
|
+
nil
|
34
|
+
elsif wrapper_method == :to_list_type || wrapper_method == :to_non_null_type
|
35
|
+
type.public_send(wrapper_method)
|
36
|
+
else
|
37
|
+
raise ArgumentError, "Unexpected wrapper method: #{wrapper_method.inspect}"
|
38
|
+
end
|
31
39
|
end
|
32
40
|
end
|
33
41
|
end
|
@@ -8,7 +8,7 @@ module GraphQL
|
|
8
8
|
# TODO: Not yet implemented for interfaces.
|
9
9
|
class TypeMembership
|
10
10
|
# @return [Class<GraphQL::Schema::Object>]
|
11
|
-
|
11
|
+
attr_accessor :object_type
|
12
12
|
|
13
13
|
# @return [Class<GraphQL::Schema::Union>, Module<GraphQL::Schema::Interface>]
|
14
14
|
attr_reader :abstract_type
|
@@ -19,7 +19,7 @@ module GraphQL
|
|
19
19
|
# @param abstract_type [Class<GraphQL::Schema::Union>, Module<GraphQL::Schema::Interface>]
|
20
20
|
# @param object_type [Class<GraphQL::Schema::Object>]
|
21
21
|
# @param options [Hash] Any options passed to `.possible_types` or `.implements`
|
22
|
-
def initialize(abstract_type, object_type, options)
|
22
|
+
def initialize(abstract_type, object_type, **options)
|
23
23
|
@abstract_type = abstract_type
|
24
24
|
@object_type = object_type
|
25
25
|
@options = options
|
data/lib/graphql/schema/union.rb
CHANGED
@@ -3,12 +3,19 @@ module GraphQL
|
|
3
3
|
class Schema
|
4
4
|
class Union < GraphQL::Schema::Member
|
5
5
|
extend GraphQL::Schema::Member::AcceptsDefinition
|
6
|
+
extend GraphQL::Schema::Member::HasUnresolvedTypeError
|
6
7
|
|
7
8
|
class << self
|
9
|
+
def inherited(child_class)
|
10
|
+
add_unresolved_type_error(child_class)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
8
14
|
def possible_types(*types, context: GraphQL::Query::NullContext, **options)
|
9
15
|
if types.any?
|
10
16
|
types.each do |t|
|
11
|
-
|
17
|
+
assert_valid_union_member(t)
|
18
|
+
type_memberships << type_membership_class.new(self, t, **options)
|
12
19
|
end
|
13
20
|
else
|
14
21
|
visible_types = []
|
@@ -25,6 +32,7 @@ module GraphQL
|
|
25
32
|
type_defn = GraphQL::UnionType.new
|
26
33
|
type_defn.name = graphql_name
|
27
34
|
type_defn.description = description
|
35
|
+
type_defn.ast_node = ast_node
|
28
36
|
type_defn.type_memberships = type_memberships
|
29
37
|
if respond_to?(:resolve_type)
|
30
38
|
type_defn.resolve_type = method(:resolve_type)
|
@@ -45,11 +53,37 @@ module GraphQL
|
|
45
53
|
GraphQL::TypeKinds::UNION
|
46
54
|
end
|
47
55
|
|
48
|
-
private
|
49
|
-
|
50
56
|
def type_memberships
|
51
57
|
@type_memberships ||= []
|
52
58
|
end
|
59
|
+
|
60
|
+
# Update a type membership whose `.object_type` is a string or late-bound type
|
61
|
+
# so that the type membership's `.object_type` is the given `object_type`.
|
62
|
+
# (This is used for updating the union after the schema as lazily loaded the union member.)
|
63
|
+
# @api private
|
64
|
+
def assign_type_membership_object_type(object_type)
|
65
|
+
assert_valid_union_member(object_type)
|
66
|
+
type_memberships.each { |tm|
|
67
|
+
possible_type = tm.object_type
|
68
|
+
if possible_type.is_a?(String) && (possible_type == object_type.name)
|
69
|
+
# This is a match of Ruby class names, not graphql names,
|
70
|
+
# since strings are used to refer to constants.
|
71
|
+
tm.object_type = object_type
|
72
|
+
elsif possible_type.is_a?(LateBoundType) && possible_type.graphql_name == object_type.graphql_name
|
73
|
+
tm.object_type = object_type
|
74
|
+
end
|
75
|
+
}
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def assert_valid_union_member(type_defn)
|
82
|
+
if type_defn.is_a?(Module) && !type_defn.is_a?(Class)
|
83
|
+
# it's an interface type, defined as a module
|
84
|
+
raise ArgumentError, "Union possible_types can only be object types (not interface types), remove #{type_defn.graphql_name} (#{type_defn.inspect})"
|
85
|
+
end
|
86
|
+
end
|
53
87
|
end
|
54
88
|
end
|
55
89
|
end
|
@@ -27,8 +27,7 @@ module GraphQL
|
|
27
27
|
# @param node_id [String] A unique ID generated by {.encode}
|
28
28
|
# @return [Array<(String, String)>] The type name & value passed to {.encode}
|
29
29
|
def decode(node_id, separator: self.default_id_separator)
|
30
|
-
|
31
|
-
Base64Bp.urlsafe_decode64(node_id).split(separator, 2)
|
30
|
+
GraphQL::Schema::Base64Encoder.decode(node_id).split(separator, 2)
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|
@@ -133,9 +133,15 @@ module GraphQL
|
|
133
133
|
end
|
134
134
|
}
|
135
135
|
|
136
|
+
DEPRECATED_ARGUMENTS_ARE_OPTIONAL = ->(argument) {
|
137
|
+
if argument.deprecation_reason && argument.type.non_null?
|
138
|
+
"must be optional because it's deprecated"
|
139
|
+
end
|
140
|
+
}
|
141
|
+
|
136
142
|
TYPE_IS_VALID_INPUT_TYPE = ->(type) {
|
137
143
|
outer_type = type.type
|
138
|
-
inner_type = outer_type.
|
144
|
+
inner_type = outer_type.respond_to?(:unwrap) ? outer_type.unwrap : nil
|
139
145
|
|
140
146
|
case inner_type
|
141
147
|
when GraphQL::ScalarType, GraphQL::InputObjectType, GraphQL::EnumType
|
@@ -154,7 +160,7 @@ module GraphQL
|
|
154
160
|
}
|
155
161
|
|
156
162
|
SCHEMA_CAN_FETCH_IDS = ->(schema) {
|
157
|
-
has_node_field = schema.query && schema.query.
|
163
|
+
has_node_field = schema.query && schema.query.fields.each_value.any?(&:relay_node_field)
|
158
164
|
if has_node_field && schema.object_from_id_proc.nil?
|
159
165
|
"schema contains `node(id:...)` field, so you must define a `object_from_id -> (id, ctx) { ... }` function"
|
160
166
|
else
|
@@ -265,8 +271,10 @@ module GraphQL
|
|
265
271
|
Rules::NAME_IS_STRING,
|
266
272
|
Rules::RESERVED_NAME,
|
267
273
|
Rules::DESCRIPTION_IS_STRING_OR_NIL,
|
274
|
+
Rules.assert_property(:deprecation_reason, String, NilClass),
|
268
275
|
Rules::TYPE_IS_VALID_INPUT_TYPE,
|
269
276
|
Rules::DEFAULT_VALUE_IS_VALID_FOR_TYPE,
|
277
|
+
Rules::DEPRECATED_ARGUMENTS_ARE_OPTIONAL,
|
270
278
|
],
|
271
279
|
GraphQL::BaseType => [
|
272
280
|
Rules::NAME_IS_STRING,
|
@@ -40,22 +40,33 @@ module GraphQL
|
|
40
40
|
# @param filter [<#call(member)>] Objects are hidden when `.call(member, ctx)` returns true
|
41
41
|
# @param context [GraphQL::Query::Context]
|
42
42
|
# @param schema [GraphQL::Schema]
|
43
|
-
# @param deep_check [Boolean]
|
44
43
|
def initialize(filter, context:, schema:)
|
45
|
-
@schema = schema
|
44
|
+
@schema = schema.interpreter? ? schema : schema.graphql_definition
|
45
|
+
# Cache these to avoid repeated hits to the inheritance chain when one isn't present
|
46
|
+
@query = @schema.query
|
47
|
+
@mutation = @schema.mutation
|
48
|
+
@subscription = @schema.subscription
|
46
49
|
@context = context
|
47
|
-
@visibility_cache = read_through { |m| filter.call(m,
|
50
|
+
@visibility_cache = read_through { |m| filter.call(m, context) }
|
48
51
|
end
|
49
52
|
|
50
|
-
# @return [
|
53
|
+
# @return [Hash<String, GraphQL::BaseType>] Visible types in the schema
|
51
54
|
def types
|
52
|
-
@types ||=
|
55
|
+
@types ||= begin
|
56
|
+
vis_types = {}
|
57
|
+
@schema.types.each do |n, t|
|
58
|
+
if visible_type?(t)
|
59
|
+
vis_types[n] = t
|
60
|
+
end
|
61
|
+
end
|
62
|
+
vis_types
|
63
|
+
end
|
53
64
|
end
|
54
65
|
|
55
66
|
# @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
|
56
67
|
def get_type(type_name)
|
57
68
|
@visible_types ||= read_through do |name|
|
58
|
-
type_defn = @schema.
|
69
|
+
type_defn = @schema.get_type(name)
|
59
70
|
if type_defn && visible_type?(type_defn)
|
60
71
|
type_defn
|
61
72
|
else
|
@@ -79,11 +90,10 @@ module GraphQL
|
|
79
90
|
|
80
91
|
# @return [GraphQL::Field, nil] The field named `field_name` on `parent_type`, if it exists
|
81
92
|
def get_field(parent_type, field_name)
|
82
|
-
|
83
93
|
@visible_parent_fields ||= read_through do |type|
|
84
94
|
read_through do |f_name|
|
85
95
|
field_defn = @schema.get_field(type, f_name)
|
86
|
-
if field_defn && visible_field?(field_defn)
|
96
|
+
if field_defn && visible_field?(type, field_defn)
|
87
97
|
field_defn
|
88
98
|
else
|
89
99
|
nil
|
@@ -94,23 +104,32 @@ module GraphQL
|
|
94
104
|
@visible_parent_fields[parent_type][field_name]
|
95
105
|
end
|
96
106
|
|
107
|
+
# @return [GraphQL::Argument, nil] The argument named `argument_name` on `parent_type`, if it exists and is visible
|
108
|
+
def get_argument(parent_type, argument_name)
|
109
|
+
argument = parent_type.get_argument(argument_name)
|
110
|
+
return argument if argument && visible_argument?(argument)
|
111
|
+
end
|
112
|
+
|
97
113
|
# @return [Array<GraphQL::BaseType>] The types which may be member of `type_defn`
|
98
114
|
def possible_types(type_defn)
|
99
|
-
@visible_possible_types ||= read_through { |type_defn|
|
115
|
+
@visible_possible_types ||= read_through { |type_defn|
|
116
|
+
pt = @schema.possible_types(type_defn, @context)
|
117
|
+
pt.select { |t| visible_type?(t) }
|
118
|
+
}
|
100
119
|
@visible_possible_types[type_defn]
|
101
120
|
end
|
102
121
|
|
103
122
|
# @param type_defn [GraphQL::ObjectType, GraphQL::InterfaceType]
|
104
123
|
# @return [Array<GraphQL::Field>] Fields on `type_defn`
|
105
124
|
def fields(type_defn)
|
106
|
-
@visible_fields ||= read_through { |t| @schema.get_fields(t).each_value.select { |f| visible_field?(f) } }
|
125
|
+
@visible_fields ||= read_through { |t| @schema.get_fields(t).each_value.select { |f| visible_field?(t, f) } }
|
107
126
|
@visible_fields[type_defn]
|
108
127
|
end
|
109
128
|
|
110
129
|
# @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
|
111
130
|
# @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
|
112
131
|
def arguments(argument_owner)
|
113
|
-
@visible_arguments ||= read_through { |o| o.arguments.each_value.select { |a|
|
132
|
+
@visible_arguments ||= read_through { |o| o.arguments.each_value.select { |a| visible_argument?(a) } }
|
114
133
|
@visible_arguments[argument_owner]
|
115
134
|
end
|
116
135
|
|
@@ -122,7 +141,7 @@ module GraphQL
|
|
122
141
|
|
123
142
|
# @return [Array<GraphQL::InterfaceType>] Visible interfaces implemented by `obj_type`
|
124
143
|
def interfaces(obj_type)
|
125
|
-
@visible_interfaces ||= read_through { |t| t.interfaces.select { |i| visible?(i) } }
|
144
|
+
@visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i| visible?(i) } }
|
126
145
|
@visible_interfaces[obj_type]
|
127
146
|
end
|
128
147
|
|
@@ -146,33 +165,88 @@ module GraphQL
|
|
146
165
|
@unions[obj_type]
|
147
166
|
end
|
148
167
|
|
149
|
-
def
|
150
|
-
visible?(
|
168
|
+
def visible_argument?(arg_defn)
|
169
|
+
visible?(arg_defn) && visible_type?(arg_defn.type.unwrap)
|
151
170
|
end
|
152
171
|
|
153
|
-
def
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
172
|
+
def visible_field?(owner_type, field_defn)
|
173
|
+
# This field is visible in its own right
|
174
|
+
visible?(field_defn) &&
|
175
|
+
# This field's return type is visible
|
176
|
+
visible_type?(field_defn.type.unwrap) &&
|
177
|
+
# This field is either defined on this object type,
|
178
|
+
# or the interface it's inherited from is also visible
|
179
|
+
((field_defn.respond_to?(:owner) && field_defn.owner == owner_type) || field_on_visible_interface?(field_defn, owner_type))
|
180
|
+
end
|
181
|
+
|
182
|
+
# We need this to tell whether a field was inherited by an interface
|
183
|
+
# even when that interface is hidden from `#interfaces`
|
184
|
+
def unfiltered_interfaces(type_defn)
|
185
|
+
@unfiltered_interfaces ||= read_through(&:interfaces)
|
186
|
+
@unfiltered_interfaces[type_defn]
|
187
|
+
end
|
188
|
+
|
189
|
+
# If this field was inherited from an interface, and the field on that interface is _hidden_,
|
190
|
+
# then treat this inherited field as hidden.
|
191
|
+
# (If it _wasn't_ inherited, then don't hide it for this reason.)
|
192
|
+
def field_on_visible_interface?(field_defn, type_defn)
|
193
|
+
if type_defn.kind.object?
|
194
|
+
any_interface_has_field = false
|
195
|
+
any_interface_has_visible_field = false
|
196
|
+
ints = unfiltered_interfaces(type_defn)
|
197
|
+
ints.each do |interface_type|
|
198
|
+
if (iface_field_defn = interface_type.get_field(field_defn.graphql_name))
|
199
|
+
any_interface_has_field = true
|
200
|
+
|
201
|
+
if interfaces(type_defn).include?(interface_type) && visible_field?(interface_type, iface_field_defn)
|
202
|
+
any_interface_has_visible_field = true
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
if any_interface_has_field
|
208
|
+
any_interface_has_visible_field
|
209
|
+
else
|
210
|
+
# it's the object's own field
|
211
|
+
true
|
212
|
+
end
|
162
213
|
else
|
163
|
-
|
214
|
+
true
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def visible_type?(type_defn)
|
219
|
+
@type_visibility ||= read_through do |type_defn|
|
220
|
+
next false unless visible?(type_defn)
|
221
|
+
next true if root_type?(type_defn) || type_defn.introspection?
|
222
|
+
|
223
|
+
if type_defn.kind.union?
|
224
|
+
visible_possible_types?(type_defn) && (referenced?(type_defn) || orphan_type?(type_defn))
|
225
|
+
elsif type_defn.kind.interface?
|
226
|
+
visible_possible_types?(type_defn)
|
227
|
+
else
|
228
|
+
referenced?(type_defn) || visible_abstract_type?(type_defn)
|
229
|
+
end
|
164
230
|
end
|
231
|
+
|
232
|
+
@type_visibility[type_defn]
|
165
233
|
end
|
166
234
|
|
167
235
|
def root_type?(type_defn)
|
168
|
-
@
|
236
|
+
@query == type_defn ||
|
237
|
+
@mutation == type_defn ||
|
238
|
+
@subscription == type_defn
|
169
239
|
end
|
170
240
|
|
171
241
|
def referenced?(type_defn)
|
172
|
-
|
242
|
+
@references_to ||= @schema.references_to
|
243
|
+
graphql_name = type_defn.unwrap.graphql_name
|
244
|
+
members = @references_to[graphql_name] || NO_REFERENCES
|
173
245
|
members.any? { |m| visible?(m) }
|
174
246
|
end
|
175
247
|
|
248
|
+
NO_REFERENCES = [].freeze
|
249
|
+
|
176
250
|
def orphan_type?(type_defn)
|
177
251
|
@schema.orphan_types.include?(type_defn)
|
178
252
|
end
|
@@ -185,7 +259,7 @@ module GraphQL
|
|
185
259
|
end
|
186
260
|
|
187
261
|
def visible_possible_types?(type_defn)
|
188
|
-
|
262
|
+
possible_types(type_defn).any? { |t| visible_type?(t) }
|
189
263
|
end
|
190
264
|
|
191
265
|
def visible?(member)
|
@@ -206,9 +280,21 @@ module GraphQL
|
|
206
280
|
root_type = root_type_for_operation(op_name)
|
207
281
|
unvisited_types << root_type if root_type
|
208
282
|
end
|
209
|
-
unvisited_types.concat(@schema.introspection_system.
|
283
|
+
unvisited_types.concat(@schema.introspection_system.types.values)
|
284
|
+
|
285
|
+
directives.each do |dir_class|
|
286
|
+
dir_class.arguments.values.each do |arg_defn|
|
287
|
+
arg_t = arg_defn.type.unwrap
|
288
|
+
if get_type(arg_t.graphql_name)
|
289
|
+
unvisited_types << arg_t
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
210
294
|
@schema.orphan_types.each do |orphan_type|
|
211
|
-
|
295
|
+
if get_type(orphan_type.graphql_name)
|
296
|
+
unvisited_types << orphan_type
|
297
|
+
end
|
212
298
|
end
|
213
299
|
|
214
300
|
until unvisited_types.empty?
|