graphql 1.13.19 → 2.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/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 +162 -119
- 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/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +2 -15
- data/lib/graphql/introspection/type_type.rb +8 -1
- 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/lexer.ri +744 -0
- data/lib/graphql/language/nodes.rb +41 -33
- data/lib/graphql/language/parser.rb +375 -363
- data/lib/graphql/language/parser.y +48 -43
- 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 +11 -22
- 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 +214 -327
- 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 +15 -19
- data/lib/graphql/schema/member/build_type.rb +5 -7
- data/lib/graphql/schema/member/has_arguments.rb +144 -53
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +71 -56
- data/lib/graphql/schema/member/has_fields.rb +15 -3
- data/lib/graphql/schema/member/has_interfaces.rb +47 -18
- data/lib/graphql/schema/member/has_validators.rb +31 -5
- data/lib/graphql/schema/member/relay_shortcuts.rb +28 -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 +23 -6
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +240 -968
- 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 +66 -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 -41
- 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 +5 -25
- data/lib/graphql/types/relay/default_relay.rb +5 -9
- data/lib/graphql/types/relay/edge_behaviors.rb +1 -4
- data/lib/graphql/types/relay/node_behaviors.rb +5 -1
- data/lib/graphql/types/relay.rb +0 -2
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +11 -72
- metadata +31 -132
- 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/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
data/lib/graphql/schema/field.rb
CHANGED
@@ -5,9 +5,8 @@ require "graphql/schema/field/scope_extension"
|
|
5
5
|
module GraphQL
|
6
6
|
class Schema
|
7
7
|
class Field
|
8
|
-
include GraphQL::Schema::Member::CachedGraphQLDefinition
|
9
|
-
include GraphQL::Schema::Member::AcceptsDefinition
|
10
8
|
include GraphQL::Schema::Member::HasArguments
|
9
|
+
include GraphQL::Schema::Member::HasArguments::FieldConfigured
|
11
10
|
include GraphQL::Schema::Member::HasAstNode
|
12
11
|
include GraphQL::Schema::Member::HasPath
|
13
12
|
include GraphQL::Schema::Member::HasValidators
|
@@ -30,8 +29,17 @@ module GraphQL
|
|
30
29
|
# @return [String] Method or hash key on the underlying object to look up
|
31
30
|
attr_reader :method_str
|
32
31
|
|
32
|
+
attr_reader :hash_key
|
33
|
+
attr_reader :dig_keys
|
34
|
+
|
33
35
|
# @return [Symbol] The method on the type to look up
|
34
|
-
|
36
|
+
def resolver_method
|
37
|
+
if @resolver_class
|
38
|
+
@resolver_class.resolver_method
|
39
|
+
else
|
40
|
+
@resolver_method
|
41
|
+
end
|
42
|
+
end
|
35
43
|
|
36
44
|
# @return [Class] The thing this field was defined on (type, mutation, resolver)
|
37
45
|
attr_accessor :owner
|
@@ -70,7 +78,10 @@ module GraphQL
|
|
70
78
|
attr_reader :trace
|
71
79
|
|
72
80
|
# @return [String, nil]
|
73
|
-
|
81
|
+
def subscription_scope
|
82
|
+
@subscription_scope || (@resolver_class.respond_to?(:subscription_scope) ? @resolver_class.subscription_scope : nil)
|
83
|
+
end
|
84
|
+
attr_writer :subscription_scope
|
74
85
|
|
75
86
|
# Create a field instance from a list of arguments, keyword arguments, and a block.
|
76
87
|
#
|
@@ -84,21 +95,9 @@ module GraphQL
|
|
84
95
|
# @return [GraphQL::Schema:Field] an instance of `self
|
85
96
|
# @see {.initialize} for other options
|
86
97
|
def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
|
87
|
-
if
|
88
|
-
if kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodeField.graphql_definition
|
89
|
-
GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.field` is being added to a class-based type. See `GraphQL::Types::Relay::NodeField` for a replacement.")
|
90
|
-
return GraphQL::Types::Relay::NodeField
|
91
|
-
elsif kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodesField.graphql_definition
|
92
|
-
GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.plural_field` is being added to a class-based type. See `GraphQL::Types::Relay::NodesField` for a replacement.")
|
93
|
-
return GraphQL::Types::Relay::NodesField
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
if (parent_config = resolver || mutation || subscription)
|
98
|
-
# Get the parent config, merge in local overrides
|
99
|
-
kwargs = parent_config.field_options.merge(kwargs)
|
98
|
+
if (resolver_class = resolver || mutation || subscription)
|
100
99
|
# Add a reference to that parent class
|
101
|
-
kwargs[:resolver_class] =
|
100
|
+
kwargs[:resolver_class] = resolver_class
|
102
101
|
end
|
103
102
|
|
104
103
|
if name
|
@@ -106,9 +105,6 @@ module GraphQL
|
|
106
105
|
end
|
107
106
|
|
108
107
|
if !type.nil?
|
109
|
-
if type.is_a?(GraphQL::Field)
|
110
|
-
raise ArgumentError, "A GraphQL::Field was passed as the second argument, use the `field:` keyword for this instead."
|
111
|
-
end
|
112
108
|
if desc
|
113
109
|
if kwargs[:description]
|
114
110
|
raise ArgumentError, "Provide description as a positional argument or `description:` keyword, but not both (#{desc.inspect}, #{kwargs[:description].inspect})"
|
@@ -116,8 +112,8 @@ module GraphQL
|
|
116
112
|
|
117
113
|
kwargs[:description] = desc
|
118
114
|
kwargs[:type] = type
|
119
|
-
elsif (
|
120
|
-
# The return type should be copied from
|
115
|
+
elsif (resolver || mutation) && type.is_a?(String)
|
116
|
+
# The return type should be copied from the resolver, and the second positional argument is the description
|
121
117
|
kwargs[:description] = type
|
122
118
|
else
|
123
119
|
kwargs[:type] = type
|
@@ -134,10 +130,10 @@ module GraphQL
|
|
134
130
|
def connection?
|
135
131
|
if @connection.nil?
|
136
132
|
# Provide default based on type name
|
137
|
-
return_type_name = if
|
138
|
-
Member::BuildType.to_type_name(contains_type.type)
|
139
|
-
elsif @return_type_expr
|
133
|
+
return_type_name = if @return_type_expr
|
140
134
|
Member::BuildType.to_type_name(@return_type_expr)
|
135
|
+
elsif @resolver_class && @resolver_class.type
|
136
|
+
Member::BuildType.to_type_name(@resolver_class.type)
|
141
137
|
else
|
142
138
|
# As a last ditch, try to force loading the return type:
|
143
139
|
type.unwrap.name
|
@@ -153,8 +149,18 @@ module GraphQL
|
|
153
149
|
if !@scope.nil?
|
154
150
|
# The default was overridden
|
155
151
|
@scope
|
152
|
+
elsif @return_type_expr
|
153
|
+
# Detect a list return type, but don't call `type` since that may eager-load an otherwise lazy-loaded type
|
154
|
+
@return_type_expr.is_a?(Array) ||
|
155
|
+
(@return_type_expr.is_a?(String) && @return_type_expr.include?("[")) ||
|
156
|
+
connection?
|
157
|
+
elsif @resolver_class
|
158
|
+
resolver_type = @resolver_class.type_expr
|
159
|
+
resolver_type.is_a?(Array) ||
|
160
|
+
(resolver_type.is_a?(String) && resolver_type.include?("[")) ||
|
161
|
+
connection?
|
156
162
|
else
|
157
|
-
|
163
|
+
false
|
158
164
|
end
|
159
165
|
end
|
160
166
|
|
@@ -187,7 +193,7 @@ module GraphQL
|
|
187
193
|
# @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
|
188
194
|
# @param type [Class, GraphQL::BaseType, Array] The return type of this field
|
189
195
|
# @param owner [Class] The type that this field belongs to
|
190
|
-
# @param null [Boolean] `true` if this field may return `null`, `false` if it is never `null`
|
196
|
+
# @param null [Boolean] (defaults to `true`) `true` if this field may return `null`, `false` if it is never `null`
|
191
197
|
# @param description [String] Field description
|
192
198
|
# @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
|
193
199
|
# @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
|
@@ -197,10 +203,8 @@ module GraphQL
|
|
197
203
|
# @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
|
198
204
|
# @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
|
199
205
|
# @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
|
206
|
+
# @param default_page_size [Integer, nil] For connections, the default number of items to return from this field, or `nil` to return unlimited results.
|
200
207
|
# @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
|
201
|
-
# @param resolve [<#call(obj, args, ctx)>] **deprecated** for compatibility with <1.8.0
|
202
|
-
# @param field [GraphQL::Field, GraphQL::Schema::Field] **deprecated** for compatibility with <1.8.0
|
203
|
-
# @param function [GraphQL::Function] **deprecated** for compatibility with <1.8.0
|
204
208
|
# @param resolver_class [Class] (Private) A {Schema::Resolver} which this field was derived from. Use `resolver:` to create a field with a resolver.
|
205
209
|
# @param arguments [{String=>GraphQL::Schema::Argument, Hash}] Arguments for this field (may be added in the block, also)
|
206
210
|
# @param camelize [Boolean] If true, the field name will be camelized when building the schema
|
@@ -214,32 +218,25 @@ module GraphQL
|
|
214
218
|
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
215
219
|
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
216
220
|
# @param validates [Array<Hash>] Configurations for validating this field
|
217
|
-
# @
|
218
|
-
def initialize(type: nil, name: nil, owner: nil, null:
|
221
|
+
# @fallback_value [Object] A fallback value if the method is not defined
|
222
|
+
def initialize(type: nil, name: nil, owner: nil, null: nil, description: NOT_CONFIGURED, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: NOT_CONFIGURED, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: :not_given, &definition_block)
|
219
223
|
if name.nil?
|
220
224
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
221
225
|
end
|
222
|
-
if !(
|
226
|
+
if !(resolver_class)
|
223
227
|
if type.nil?
|
224
228
|
raise ArgumentError, "missing second `type` argument or keyword `type:`"
|
225
229
|
end
|
226
230
|
end
|
227
|
-
if (field || function || resolve) && extras.any?
|
228
|
-
raise ArgumentError, "keyword `extras:` may only be used with method-based resolve and class-based field such as mutation class, please remove `field:`, `function:` or `resolve:`"
|
229
|
-
end
|
230
231
|
@original_name = name
|
231
232
|
name_s = -name.to_s
|
232
233
|
|
233
234
|
@underscored_name = -Member::BuildType.underscore(name_s)
|
234
235
|
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
|
236
|
+
|
235
237
|
@description = description
|
236
|
-
if
|
237
|
-
|
238
|
-
else
|
239
|
-
@field = field
|
240
|
-
end
|
241
|
-
@function = function
|
242
|
-
@resolve = resolve
|
238
|
+
@type = @owner_type = @own_validators = @own_directives = @own_arguments = nil # these will be prepared later if necessary
|
239
|
+
|
243
240
|
self.deprecation_reason = deprecation_reason
|
244
241
|
|
245
242
|
if method && hash_key && dig
|
@@ -256,24 +253,31 @@ module GraphQL
|
|
256
253
|
end
|
257
254
|
end
|
258
255
|
|
259
|
-
# TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
|
260
256
|
method_name = method || hash_key || name_s
|
261
257
|
@dig_keys = dig
|
262
258
|
if hash_key
|
263
259
|
@hash_key = hash_key
|
260
|
+
@hash_key_str = hash_key.to_s
|
261
|
+
else
|
262
|
+
@hash_key = NOT_CONFIGURED
|
263
|
+
@hash_key_str = NOT_CONFIGURED
|
264
264
|
end
|
265
265
|
|
266
|
-
resolver_method ||= name_s.to_sym
|
267
|
-
|
268
266
|
@method_str = -method_name.to_s
|
269
267
|
@method_sym = method_name.to_sym
|
270
|
-
@resolver_method = resolver_method
|
268
|
+
@resolver_method = (resolver_method || name_s).to_sym
|
271
269
|
@complexity = complexity
|
272
270
|
@return_type_expr = type
|
273
|
-
@return_type_null = null
|
271
|
+
@return_type_null = if !null.nil?
|
272
|
+
null
|
273
|
+
elsif resolver_class
|
274
|
+
nil
|
275
|
+
else
|
276
|
+
true
|
277
|
+
end
|
274
278
|
@connection = connection
|
275
|
-
@
|
276
|
-
@
|
279
|
+
@max_page_size = max_page_size
|
280
|
+
@default_page_size = default_page_size
|
277
281
|
@introspection = introspection
|
278
282
|
@extras = extras
|
279
283
|
@broadcastable = broadcastable
|
@@ -284,7 +288,7 @@ module GraphQL
|
|
284
288
|
@relay_nodes_field = relay_nodes_field
|
285
289
|
@ast_node = ast_node
|
286
290
|
@method_conflict_warning = method_conflict_warning
|
287
|
-
@
|
291
|
+
@fallback_value = fallback_value
|
288
292
|
|
289
293
|
arguments.each do |name, arg|
|
290
294
|
case arg
|
@@ -321,13 +325,19 @@ module GraphQL
|
|
321
325
|
self.extensions(extensions)
|
322
326
|
end
|
323
327
|
|
328
|
+
if resolver_class && resolver_class.extensions.any?
|
329
|
+
self.extensions(resolver_class.extensions)
|
330
|
+
end
|
331
|
+
|
324
332
|
if directives.any?
|
325
333
|
directives.each do |(dir_class, options)|
|
326
334
|
self.directive(dir_class, **options)
|
327
335
|
end
|
328
336
|
end
|
329
337
|
|
330
|
-
|
338
|
+
if !validates.empty?
|
339
|
+
self.validates(validates)
|
340
|
+
end
|
331
341
|
|
332
342
|
if definition_block
|
333
343
|
if definition_block.arity == 1
|
@@ -345,7 +355,13 @@ module GraphQL
|
|
345
355
|
# @return [Boolean, nil]
|
346
356
|
# @see GraphQL::Subscriptions::BroadcastAnalyzer
|
347
357
|
def broadcastable?
|
348
|
-
@broadcastable
|
358
|
+
if !NOT_CONFIGURED.equal?(@broadcastable)
|
359
|
+
@broadcastable
|
360
|
+
elsif @resolver_class
|
361
|
+
@resolver_class.broadcastable?
|
362
|
+
else
|
363
|
+
nil
|
364
|
+
end
|
349
365
|
end
|
350
366
|
|
351
367
|
# @param text [String]
|
@@ -353,8 +369,12 @@ module GraphQL
|
|
353
369
|
def description(text = nil)
|
354
370
|
if text
|
355
371
|
@description = text
|
356
|
-
|
372
|
+
elsif !NOT_CONFIGURED.equal?(@description)
|
357
373
|
@description
|
374
|
+
elsif @resolver_class
|
375
|
+
@resolver_class.description
|
376
|
+
else
|
377
|
+
nil
|
358
378
|
end
|
359
379
|
end
|
360
380
|
|
@@ -418,7 +438,12 @@ module GraphQL
|
|
418
438
|
def extras(new_extras = nil)
|
419
439
|
if new_extras.nil?
|
420
440
|
# Read the value
|
421
|
-
@extras
|
441
|
+
field_extras = @extras
|
442
|
+
if @resolver_class && @resolver_class.extras.any?
|
443
|
+
field_extras + @resolver_class.extras
|
444
|
+
else
|
445
|
+
field_extras
|
446
|
+
end
|
422
447
|
else
|
423
448
|
if @extras.frozen?
|
424
449
|
@extras = @extras.dup
|
@@ -446,11 +471,11 @@ module GraphQL
|
|
446
471
|
end
|
447
472
|
|
448
473
|
if max_possible_page_size.nil?
|
449
|
-
max_possible_page_size = max_page_size || query.schema.default_max_page_size
|
474
|
+
max_possible_page_size = default_page_size || query.schema.default_page_size || max_page_size || query.schema.default_max_page_size
|
450
475
|
end
|
451
476
|
|
452
477
|
if max_possible_page_size.nil?
|
453
|
-
raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `max_page_size` or `default_max_page_size`"
|
478
|
+
raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `default_page_size`, `max_page_size` or `default_max_page_size`"
|
454
479
|
else
|
455
480
|
metadata_complexity = 0
|
456
481
|
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
@@ -507,7 +532,11 @@ module GraphQL
|
|
507
532
|
when Numeric
|
508
533
|
@complexity = new_complexity
|
509
534
|
when nil
|
510
|
-
@
|
535
|
+
if @resolver_class
|
536
|
+
@complexity || @resolver_class.complexity || 1
|
537
|
+
else
|
538
|
+
@complexity || 1
|
539
|
+
end
|
511
540
|
else
|
512
541
|
raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
|
513
542
|
end
|
@@ -515,105 +544,49 @@ module GraphQL
|
|
515
544
|
|
516
545
|
# @return [Boolean] True if this field's {#max_page_size} should override the schema default.
|
517
546
|
def has_max_page_size?
|
518
|
-
@has_max_page_size
|
547
|
+
!NOT_CONFIGURED.equal?(@max_page_size) || (@resolver_class && @resolver_class.has_max_page_size?)
|
519
548
|
end
|
520
549
|
|
521
550
|
# @return [Integer, nil] Applied to connections if {#has_max_page_size?}
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
def to_graphql
|
528
|
-
field_defn = if @field
|
529
|
-
@field.dup
|
530
|
-
elsif @function
|
531
|
-
GraphQL::Function.build_field(@function)
|
551
|
+
def max_page_size
|
552
|
+
if !NOT_CONFIGURED.equal?(@max_page_size)
|
553
|
+
@max_page_size
|
554
|
+
elsif @resolver_class && @resolver_class.has_max_page_size?
|
555
|
+
@resolver_class.max_page_size
|
532
556
|
else
|
533
|
-
|
534
|
-
end
|
535
|
-
|
536
|
-
field_defn.name = @name
|
537
|
-
if @return_type_expr
|
538
|
-
field_defn.type = -> { type }
|
557
|
+
nil
|
539
558
|
end
|
559
|
+
end
|
540
560
|
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
if self.deprecation_reason
|
546
|
-
field_defn.deprecation_reason = self.deprecation_reason
|
547
|
-
end
|
548
|
-
|
549
|
-
if @resolver_class
|
550
|
-
if @resolver_class < GraphQL::Schema::Mutation
|
551
|
-
field_defn.mutation = @resolver_class
|
552
|
-
end
|
553
|
-
field_defn.metadata[:resolver] = @resolver_class
|
554
|
-
end
|
555
|
-
|
556
|
-
if !@trace.nil?
|
557
|
-
field_defn.trace = @trace
|
558
|
-
end
|
559
|
-
|
560
|
-
if @relay_node_field
|
561
|
-
field_defn.relay_node_field = @relay_node_field
|
562
|
-
end
|
563
|
-
|
564
|
-
if @relay_nodes_field
|
565
|
-
field_defn.relay_nodes_field = @relay_nodes_field
|
566
|
-
end
|
567
|
-
|
568
|
-
if @legacy_edge_class
|
569
|
-
field_defn.edge_class = @legacy_edge_class
|
570
|
-
end
|
571
|
-
|
572
|
-
field_defn.resolve = self.method(:resolve_field)
|
573
|
-
field_defn.connection = connection?
|
574
|
-
field_defn.connection_max_page_size = max_page_size
|
575
|
-
field_defn.introspection = @introspection
|
576
|
-
field_defn.complexity = @complexity
|
577
|
-
field_defn.subscription_scope = @subscription_scope
|
578
|
-
field_defn.ast_node = ast_node
|
579
|
-
|
580
|
-
all_argument_definitions.each do |defn|
|
581
|
-
arg_graphql = defn.deprecated_to_graphql
|
582
|
-
field_defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
|
583
|
-
end
|
561
|
+
# @return [Boolean] True if this field's {#default_page_size} should override the schema default.
|
562
|
+
def has_default_page_size?
|
563
|
+
!NOT_CONFIGURED.equal?(@default_page_size) || (@resolver_class && @resolver_class.has_default_page_size?)
|
564
|
+
end
|
584
565
|
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
566
|
+
# @return [Integer, nil] Applied to connections if {#has_default_page_size?}
|
567
|
+
def default_page_size
|
568
|
+
if !NOT_CONFIGURED.equal?(@default_page_size)
|
569
|
+
@default_page_size
|
570
|
+
elsif @resolver_class && @resolver_class.has_default_page_size?
|
571
|
+
@resolver_class.default_page_size
|
572
|
+
else
|
573
|
+
nil
|
592
574
|
end
|
593
|
-
|
594
|
-
# Ok, `self` isn't a class, but this is for consistency with the classes
|
595
|
-
field_defn.metadata[:type_class] = self
|
596
|
-
field_defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(field_defn)
|
597
|
-
field_defn
|
598
575
|
end
|
599
576
|
|
600
577
|
class MissingReturnTypeError < GraphQL::Error; end
|
601
578
|
attr_writer :type
|
602
579
|
|
603
580
|
def type
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
elsif @return_type_expr.nil?
|
609
|
-
# Not enough info to determine type
|
610
|
-
message = "Can't determine the return type for #{self.path}"
|
611
|
-
if @resolver_class
|
612
|
-
message += " (it has `resolver: #{@resolver_class}`, consider configuration a `type ...` for that class)"
|
581
|
+
if @resolver_class
|
582
|
+
return_type = @return_type_expr || @resolver_class.type_expr
|
583
|
+
if return_type.nil?
|
584
|
+
raise MissingReturnTypeError, "Can't determine the return type for #{self.path} (it has `resolver: #{@resolver_class}`, perhaps that class is missing a `type ...` declaration, or perhaps its type causes a cyclical loading issue)"
|
613
585
|
end
|
614
|
-
|
586
|
+
nullable = @return_type_null.nil? ? @resolver_class.null : @return_type_null
|
587
|
+
Member::BuildType.parse_type(return_type, null: nullable)
|
615
588
|
else
|
616
|
-
Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
589
|
+
@type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
617
590
|
end
|
618
591
|
rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
|
619
592
|
# Let this propagate up
|
@@ -630,14 +603,6 @@ module GraphQL
|
|
630
603
|
end
|
631
604
|
end
|
632
605
|
|
633
|
-
def accessible?(context)
|
634
|
-
if @resolver_class
|
635
|
-
@resolver_class.accessible?(context)
|
636
|
-
else
|
637
|
-
true
|
638
|
-
end
|
639
|
-
end
|
640
|
-
|
641
606
|
def authorized?(object, args, context)
|
642
607
|
if @resolver_class
|
643
608
|
# The resolver _instance_ will check itself during `resolve()`
|
@@ -681,70 +646,115 @@ module GraphQL
|
|
681
646
|
end
|
682
647
|
end
|
683
648
|
|
684
|
-
# Implement {GraphQL::Field}'s resolve API.
|
685
|
-
#
|
686
|
-
# Eventually, we might hook up field instances to execution in another way. TBD.
|
687
|
-
# @see #resolve for how the interpreter hooks up to it
|
688
|
-
def resolve_field(obj, args, ctx)
|
689
|
-
ctx.schema.after_lazy(obj) do |after_obj|
|
690
|
-
# First, apply auth ...
|
691
|
-
query_ctx = ctx.query.context
|
692
|
-
# Some legacy fields can have `nil` here, not exactly sure why.
|
693
|
-
# @see https://github.com/rmosolgo/graphql-ruby/issues/1990 before removing
|
694
|
-
inner_obj = after_obj && after_obj.object
|
695
|
-
ctx.schema.after_lazy(to_ruby_args(after_obj, args, ctx)) do |ruby_args|
|
696
|
-
if authorized?(inner_obj, ruby_args, query_ctx)
|
697
|
-
# Then if it passed, resolve the field
|
698
|
-
if @resolve_proc
|
699
|
-
# Might be nil, still want to call the func in that case
|
700
|
-
with_extensions(inner_obj, ruby_args, query_ctx) do |extended_obj, extended_args|
|
701
|
-
# Pass the GraphQL args here for compatibility:
|
702
|
-
@resolve_proc.call(extended_obj, args, ctx)
|
703
|
-
end
|
704
|
-
else
|
705
|
-
public_send_field(after_obj, ruby_args, query_ctx)
|
706
|
-
end
|
707
|
-
else
|
708
|
-
err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
|
709
|
-
query_ctx.schema.unauthorized_field(err)
|
710
|
-
end
|
711
|
-
end
|
712
|
-
end
|
713
|
-
end
|
714
|
-
|
715
649
|
# This method is called by the interpreter for each field.
|
716
650
|
# You can extend it in your base field classes.
|
717
651
|
# @param object [GraphQL::Schema::Object] An instance of some type class, wrapping an application object
|
718
652
|
# @param args [Hash] A symbol-keyed hash of Ruby keyword arguments. (Empty if no args)
|
719
653
|
# @param ctx [GraphQL::Query::Context]
|
720
|
-
def resolve(object, args,
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
654
|
+
def resolve(object, args, query_ctx)
|
655
|
+
# Unwrap the GraphQL object to get the application object.
|
656
|
+
application_object = object.object
|
657
|
+
method_receiver = nil
|
658
|
+
method_to_call = nil
|
659
|
+
method_args = nil
|
660
|
+
|
661
|
+
Schema::Validator.validate!(validators, application_object, query_ctx, args)
|
662
|
+
|
663
|
+
query_ctx.schema.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
|
664
|
+
if is_authorized
|
665
|
+
with_extensions(object, args, query_ctx) do |obj, ruby_kwargs|
|
666
|
+
method_args = ruby_kwargs
|
667
|
+
if @resolver_class
|
668
|
+
if obj.is_a?(GraphQL::Schema::Object)
|
669
|
+
obj = obj.object
|
670
|
+
end
|
671
|
+
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
672
|
+
end
|
727
673
|
|
728
|
-
|
674
|
+
inner_object = obj.object
|
729
675
|
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
676
|
+
if !NOT_CONFIGURED.equal?(@hash_key)
|
677
|
+
hash_value = if inner_object.is_a?(Hash)
|
678
|
+
inner_object.key?(@hash_key) ? inner_object[@hash_key] : inner_object[@hash_key_str]
|
679
|
+
elsif inner_object.respond_to?(:[])
|
680
|
+
inner_object[@hash_key]
|
681
|
+
else
|
682
|
+
nil
|
683
|
+
end
|
684
|
+
if hash_value == false
|
685
|
+
hash_value
|
686
|
+
else
|
687
|
+
hash_value || (@fallback_value != :not_given ? @fallback_value : nil)
|
688
|
+
end
|
689
|
+
elsif obj.respond_to?(resolver_method)
|
690
|
+
method_to_call = resolver_method
|
691
|
+
method_receiver = obj
|
692
|
+
# Call the method with kwargs, if there are any
|
693
|
+
if ruby_kwargs.any?
|
694
|
+
obj.public_send(resolver_method, **ruby_kwargs)
|
695
|
+
else
|
696
|
+
obj.public_send(resolver_method)
|
697
|
+
end
|
698
|
+
elsif inner_object.is_a?(Hash)
|
699
|
+
if @dig_keys
|
700
|
+
inner_object.dig(*@dig_keys)
|
701
|
+
elsif inner_object.key?(@method_sym)
|
702
|
+
inner_object[@method_sym]
|
703
|
+
elsif inner_object.key?(@method_str)
|
704
|
+
inner_object[@method_str]
|
705
|
+
elsif @fallback_value != :not_given
|
706
|
+
@fallback_value
|
707
|
+
else
|
708
|
+
nil
|
709
|
+
end
|
710
|
+
elsif inner_object.respond_to?(@method_sym)
|
711
|
+
method_to_call = @method_sym
|
712
|
+
method_receiver = obj.object
|
713
|
+
if ruby_kwargs.any?
|
714
|
+
inner_object.public_send(@method_sym, **ruby_kwargs)
|
715
|
+
else
|
716
|
+
inner_object.public_send(@method_sym)
|
717
|
+
end
|
718
|
+
elsif @fallback_value != :not_given
|
719
|
+
@fallback_value
|
720
|
+
else
|
721
|
+
raise <<-ERR
|
722
|
+
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
723
|
+
|
724
|
+
- `#{obj.class}##{resolver_method}`, which did not exist
|
725
|
+
- `#{inner_object.class}##{@method_sym}`, which did not exist
|
726
|
+
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{inner_object}`, but it wasn't a Hash
|
727
|
+
|
728
|
+
To implement this field, define one of the methods above (and check for typos), or supply a `fallback_value`.
|
729
|
+
ERR
|
730
|
+
end
|
735
731
|
end
|
732
|
+
else
|
733
|
+
raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: query_ctx, field: self)
|
736
734
|
end
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
735
|
+
end
|
736
|
+
rescue GraphQL::UnauthorizedFieldError => err
|
737
|
+
err.field ||= self
|
738
|
+
begin
|
739
|
+
query_ctx.schema.unauthorized_field(err)
|
740
|
+
rescue GraphQL::ExecutionError => err
|
741
|
+
err
|
742
|
+
end
|
743
|
+
rescue GraphQL::UnauthorizedError => err
|
744
|
+
begin
|
745
|
+
query_ctx.schema.unauthorized_object(err)
|
746
|
+
rescue GraphQL::ExecutionError => err
|
747
|
+
err
|
748
|
+
end
|
749
|
+
rescue ArgumentError
|
750
|
+
if method_receiver && method_to_call
|
751
|
+
assert_satisfactory_implementation(method_receiver, method_to_call, method_args)
|
752
|
+
end
|
753
|
+
# if the line above doesn't raise, re-raise
|
754
|
+
raise
|
745
755
|
end
|
746
756
|
|
747
|
-
# @param ctx [GraphQL::Query::Context
|
757
|
+
# @param ctx [GraphQL::Query::Context]
|
748
758
|
def fetch_extra(extra_name, ctx)
|
749
759
|
if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
|
750
760
|
self.public_send(extra_name)
|
@@ -757,129 +767,6 @@ module GraphQL
|
|
757
767
|
|
758
768
|
private
|
759
769
|
|
760
|
-
NO_ARGS = {}.freeze
|
761
|
-
|
762
|
-
# Convert a GraphQL arguments instance into a Ruby-style hash.
|
763
|
-
#
|
764
|
-
# @param obj [GraphQL::Schema::Object] The object where this field is being resolved
|
765
|
-
# @param graphql_args [GraphQL::Query::Arguments]
|
766
|
-
# @param field_ctx [GraphQL::Query::Context::FieldResolutionContext]
|
767
|
-
# @return [Hash<Symbol => Any>]
|
768
|
-
def to_ruby_args(obj, graphql_args, field_ctx)
|
769
|
-
if graphql_args.any? || @extras.any?
|
770
|
-
# Splat the GraphQL::Arguments to Ruby keyword arguments
|
771
|
-
ruby_kwargs = graphql_args.to_kwargs
|
772
|
-
maybe_lazies = []
|
773
|
-
# Apply any `prepare` methods. Not great code organization, can this go somewhere better?
|
774
|
-
arguments(field_ctx).each do |name, arg_defn|
|
775
|
-
ruby_kwargs_key = arg_defn.keyword
|
776
|
-
|
777
|
-
if ruby_kwargs.key?(ruby_kwargs_key)
|
778
|
-
loads = arg_defn.loads
|
779
|
-
value = ruby_kwargs[ruby_kwargs_key]
|
780
|
-
loaded_value = if loads && !arg_defn.from_resolver?
|
781
|
-
if arg_defn.type.list?
|
782
|
-
loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, field_ctx.query.context) }
|
783
|
-
field_ctx.schema.after_any_lazies(loaded_values) { |result| result }
|
784
|
-
else
|
785
|
-
load_application_object(arg_defn, loads, value, field_ctx.query.context)
|
786
|
-
end
|
787
|
-
elsif arg_defn.type.list? && value.is_a?(Array)
|
788
|
-
field_ctx.schema.after_any_lazies(value, &:itself)
|
789
|
-
else
|
790
|
-
value
|
791
|
-
end
|
792
|
-
|
793
|
-
maybe_lazies << field_ctx.schema.after_lazy(loaded_value) do |loaded_value|
|
794
|
-
prepared_value = if arg_defn.prepare
|
795
|
-
arg_defn.prepare_value(obj, loaded_value)
|
796
|
-
else
|
797
|
-
loaded_value
|
798
|
-
end
|
799
|
-
|
800
|
-
ruby_kwargs[ruby_kwargs_key] = prepared_value
|
801
|
-
end
|
802
|
-
end
|
803
|
-
end
|
804
|
-
|
805
|
-
@extras.each do |extra_arg|
|
806
|
-
ruby_kwargs[extra_arg] = fetch_extra(extra_arg, field_ctx)
|
807
|
-
end
|
808
|
-
|
809
|
-
field_ctx.schema.after_any_lazies(maybe_lazies) do
|
810
|
-
ruby_kwargs
|
811
|
-
end
|
812
|
-
else
|
813
|
-
NO_ARGS
|
814
|
-
end
|
815
|
-
end
|
816
|
-
|
817
|
-
def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
|
818
|
-
with_extensions(unextended_obj, unextended_ruby_kwargs, query_ctx) do |obj, ruby_kwargs|
|
819
|
-
begin
|
820
|
-
method_receiver = nil
|
821
|
-
method_to_call = nil
|
822
|
-
if @resolver_class
|
823
|
-
if obj.is_a?(GraphQL::Schema::Object)
|
824
|
-
obj = obj.object
|
825
|
-
end
|
826
|
-
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
827
|
-
end
|
828
|
-
|
829
|
-
# Find a way to resolve this field, checking:
|
830
|
-
#
|
831
|
-
# - A method on the type instance;
|
832
|
-
# - Hash keys, if the wrapped object is a hash or responds to `#[]`
|
833
|
-
# - A method on the wrapped object;
|
834
|
-
# - Or, raise not implemented.
|
835
|
-
#
|
836
|
-
if obj.respond_to?(@resolver_method)
|
837
|
-
method_to_call = @resolver_method
|
838
|
-
method_receiver = obj
|
839
|
-
# Call the method with kwargs, if there are any
|
840
|
-
if ruby_kwargs.any?
|
841
|
-
obj.public_send(@resolver_method, **ruby_kwargs)
|
842
|
-
else
|
843
|
-
obj.public_send(@resolver_method)
|
844
|
-
end
|
845
|
-
elsif obj.object.is_a?(Hash)
|
846
|
-
inner_object = obj.object
|
847
|
-
if @dig_keys
|
848
|
-
inner_object.dig(*@dig_keys)
|
849
|
-
elsif inner_object.key?(@method_sym)
|
850
|
-
inner_object[@method_sym]
|
851
|
-
else
|
852
|
-
inner_object[@method_str]
|
853
|
-
end
|
854
|
-
elsif defined?(@hash_key) && obj.object.respond_to?(:[])
|
855
|
-
obj.object[@hash_key]
|
856
|
-
elsif obj.object.respond_to?(@method_sym)
|
857
|
-
method_to_call = @method_sym
|
858
|
-
method_receiver = obj.object
|
859
|
-
if ruby_kwargs.any?
|
860
|
-
obj.object.public_send(@method_sym, **ruby_kwargs)
|
861
|
-
else
|
862
|
-
obj.object.public_send(@method_sym)
|
863
|
-
end
|
864
|
-
else
|
865
|
-
raise <<-ERR
|
866
|
-
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
867
|
-
|
868
|
-
- `#{obj.class}##{@resolver_method}`, which did not exist
|
869
|
-
- `#{obj.object.class}##{@method_sym}`, which did not exist
|
870
|
-
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
|
871
|
-
|
872
|
-
To implement this field, define one of the methods above (and check for typos)
|
873
|
-
ERR
|
874
|
-
end
|
875
|
-
rescue ArgumentError
|
876
|
-
assert_satisfactory_implementation(method_receiver, method_to_call, ruby_kwargs)
|
877
|
-
# if the line above doesn't raise, re-raise
|
878
|
-
raise
|
879
|
-
end
|
880
|
-
end
|
881
|
-
end
|
882
|
-
|
883
770
|
def assert_satisfactory_implementation(receiver, method_name, ruby_kwargs)
|
884
771
|
method_defn = receiver.method(method_name)
|
885
772
|
unsatisfied_ruby_kwargs = ruby_kwargs.dup
|
@@ -910,7 +797,7 @@ module GraphQL
|
|
910
797
|
|
911
798
|
if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
|
912
799
|
raise FieldImplementationFailed.new, <<-ERR
|
913
|
-
Failed to call
|
800
|
+
Failed to call `#{method_name.inspect}` on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
|
914
801
|
|
915
802
|
#{ unsatisfied_ruby_kwargs
|
916
803
|
.map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }
|