graphql 1.13.14 → 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 +163 -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/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 +10 -1
- data/lib/graphql/query/null_context.rb +0 -3
- data/lib/graphql/query/validation_pipeline.rb +12 -37
- data/lib/graphql/query/variable_validation_error.rb +2 -2
- data/lib/graphql/query/variables.rb +35 -21
- data/lib/graphql/query.rb +32 -43
- 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 +29 -41
- 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 +245 -343
- data/lib/graphql/schema/input_object.rb +57 -69
- 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 +18 -9
- 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 +146 -55
- 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 +16 -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 +28 -2
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/member.rb +0 -6
- data/lib/graphql/schema/mutation.rb +0 -9
- data/lib/graphql/schema/non_null.rb +3 -9
- 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 +8 -23
- 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 +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 -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 -41
- 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 -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/opentelemetry_tracing.rb +0 -101
- 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,31 +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
|
233
|
+
|
232
234
|
@underscored_name = -Member::BuildType.underscore(name_s)
|
233
235
|
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
|
236
|
+
|
234
237
|
@description = description
|
235
|
-
if
|
236
|
-
|
237
|
-
else
|
238
|
-
@field = field
|
239
|
-
end
|
240
|
-
@function = function
|
241
|
-
@resolve = resolve
|
238
|
+
@type = @owner_type = @own_validators = @own_directives = @own_arguments = nil # these will be prepared later if necessary
|
239
|
+
|
242
240
|
self.deprecation_reason = deprecation_reason
|
243
241
|
|
244
242
|
if method && hash_key && dig
|
@@ -255,20 +253,31 @@ module GraphQL
|
|
255
253
|
end
|
256
254
|
end
|
257
255
|
|
258
|
-
# TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
|
259
256
|
method_name = method || hash_key || name_s
|
260
257
|
@dig_keys = dig
|
261
|
-
|
258
|
+
if hash_key
|
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
|
+
end
|
262
265
|
|
263
266
|
@method_str = -method_name.to_s
|
264
267
|
@method_sym = method_name.to_sym
|
265
|
-
@resolver_method = resolver_method
|
268
|
+
@resolver_method = (resolver_method || name_s).to_sym
|
266
269
|
@complexity = complexity
|
267
270
|
@return_type_expr = type
|
268
|
-
@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
|
269
278
|
@connection = connection
|
270
|
-
@
|
271
|
-
@
|
279
|
+
@max_page_size = max_page_size
|
280
|
+
@default_page_size = default_page_size
|
272
281
|
@introspection = introspection
|
273
282
|
@extras = extras
|
274
283
|
@broadcastable = broadcastable
|
@@ -279,7 +288,7 @@ module GraphQL
|
|
279
288
|
@relay_nodes_field = relay_nodes_field
|
280
289
|
@ast_node = ast_node
|
281
290
|
@method_conflict_warning = method_conflict_warning
|
282
|
-
@
|
291
|
+
@fallback_value = fallback_value
|
283
292
|
|
284
293
|
arguments.each do |name, arg|
|
285
294
|
case arg
|
@@ -316,13 +325,19 @@ module GraphQL
|
|
316
325
|
self.extensions(extensions)
|
317
326
|
end
|
318
327
|
|
328
|
+
if resolver_class && resolver_class.extensions.any?
|
329
|
+
self.extensions(resolver_class.extensions)
|
330
|
+
end
|
331
|
+
|
319
332
|
if directives.any?
|
320
333
|
directives.each do |(dir_class, options)|
|
321
334
|
self.directive(dir_class, **options)
|
322
335
|
end
|
323
336
|
end
|
324
337
|
|
325
|
-
|
338
|
+
if !validates.empty?
|
339
|
+
self.validates(validates)
|
340
|
+
end
|
326
341
|
|
327
342
|
if definition_block
|
328
343
|
if definition_block.arity == 1
|
@@ -340,7 +355,13 @@ module GraphQL
|
|
340
355
|
# @return [Boolean, nil]
|
341
356
|
# @see GraphQL::Subscriptions::BroadcastAnalyzer
|
342
357
|
def broadcastable?
|
343
|
-
@broadcastable
|
358
|
+
if !NOT_CONFIGURED.equal?(@broadcastable)
|
359
|
+
@broadcastable
|
360
|
+
elsif @resolver_class
|
361
|
+
@resolver_class.broadcastable?
|
362
|
+
else
|
363
|
+
nil
|
364
|
+
end
|
344
365
|
end
|
345
366
|
|
346
367
|
# @param text [String]
|
@@ -348,8 +369,12 @@ module GraphQL
|
|
348
369
|
def description(text = nil)
|
349
370
|
if text
|
350
371
|
@description = text
|
351
|
-
|
372
|
+
elsif !NOT_CONFIGURED.equal?(@description)
|
352
373
|
@description
|
374
|
+
elsif @resolver_class
|
375
|
+
@resolver_class.description
|
376
|
+
else
|
377
|
+
nil
|
353
378
|
end
|
354
379
|
end
|
355
380
|
|
@@ -413,7 +438,12 @@ module GraphQL
|
|
413
438
|
def extras(new_extras = nil)
|
414
439
|
if new_extras.nil?
|
415
440
|
# Read the value
|
416
|
-
@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
|
417
447
|
else
|
418
448
|
if @extras.frozen?
|
419
449
|
@extras = @extras.dup
|
@@ -441,11 +471,11 @@ module GraphQL
|
|
441
471
|
end
|
442
472
|
|
443
473
|
if max_possible_page_size.nil?
|
444
|
-
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
|
445
475
|
end
|
446
476
|
|
447
477
|
if max_possible_page_size.nil?
|
448
|
-
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`"
|
449
479
|
else
|
450
480
|
metadata_complexity = 0
|
451
481
|
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
@@ -473,7 +503,13 @@ module GraphQL
|
|
473
503
|
case defined_complexity
|
474
504
|
when Proc
|
475
505
|
arguments = query.arguments_for(nodes.first, self)
|
476
|
-
|
506
|
+
if arguments.is_a?(GraphQL::ExecutionError)
|
507
|
+
return child_complexity
|
508
|
+
elsif arguments.respond_to?(:keyword_arguments)
|
509
|
+
arguments = arguments.keyword_arguments
|
510
|
+
end
|
511
|
+
|
512
|
+
defined_complexity.call(query.context, arguments, child_complexity)
|
477
513
|
when Numeric
|
478
514
|
defined_complexity + child_complexity
|
479
515
|
else
|
@@ -496,7 +532,11 @@ module GraphQL
|
|
496
532
|
when Numeric
|
497
533
|
@complexity = new_complexity
|
498
534
|
when nil
|
499
|
-
@
|
535
|
+
if @resolver_class
|
536
|
+
@complexity || @resolver_class.complexity || 1
|
537
|
+
else
|
538
|
+
@complexity || 1
|
539
|
+
end
|
500
540
|
else
|
501
541
|
raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
|
502
542
|
end
|
@@ -504,105 +544,49 @@ module GraphQL
|
|
504
544
|
|
505
545
|
# @return [Boolean] True if this field's {#max_page_size} should override the schema default.
|
506
546
|
def has_max_page_size?
|
507
|
-
@has_max_page_size
|
547
|
+
!NOT_CONFIGURED.equal?(@max_page_size) || (@resolver_class && @resolver_class.has_max_page_size?)
|
508
548
|
end
|
509
549
|
|
510
550
|
# @return [Integer, nil] Applied to connections if {#has_max_page_size?}
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
def to_graphql
|
517
|
-
field_defn = if @field
|
518
|
-
@field.dup
|
519
|
-
elsif @function
|
520
|
-
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
|
521
556
|
else
|
522
|
-
|
523
|
-
end
|
524
|
-
|
525
|
-
field_defn.name = @name
|
526
|
-
if @return_type_expr
|
527
|
-
field_defn.type = -> { type }
|
528
|
-
end
|
529
|
-
|
530
|
-
if @description
|
531
|
-
field_defn.description = @description
|
532
|
-
end
|
533
|
-
|
534
|
-
if self.deprecation_reason
|
535
|
-
field_defn.deprecation_reason = self.deprecation_reason
|
557
|
+
nil
|
536
558
|
end
|
559
|
+
end
|
537
560
|
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
field_defn.metadata[:resolver] = @resolver_class
|
543
|
-
end
|
544
|
-
|
545
|
-
if !@trace.nil?
|
546
|
-
field_defn.trace = @trace
|
547
|
-
end
|
548
|
-
|
549
|
-
if @relay_node_field
|
550
|
-
field_defn.relay_node_field = @relay_node_field
|
551
|
-
end
|
552
|
-
|
553
|
-
if @relay_nodes_field
|
554
|
-
field_defn.relay_nodes_field = @relay_nodes_field
|
555
|
-
end
|
556
|
-
|
557
|
-
if @legacy_edge_class
|
558
|
-
field_defn.edge_class = @legacy_edge_class
|
559
|
-
end
|
560
|
-
|
561
|
-
field_defn.resolve = self.method(:resolve_field)
|
562
|
-
field_defn.connection = connection?
|
563
|
-
field_defn.connection_max_page_size = max_page_size
|
564
|
-
field_defn.introspection = @introspection
|
565
|
-
field_defn.complexity = @complexity
|
566
|
-
field_defn.subscription_scope = @subscription_scope
|
567
|
-
field_defn.ast_node = ast_node
|
568
|
-
|
569
|
-
all_argument_definitions.each do |defn|
|
570
|
-
arg_graphql = defn.deprecated_to_graphql
|
571
|
-
field_defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
|
572
|
-
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
|
573
565
|
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
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
|
581
574
|
end
|
582
|
-
|
583
|
-
# Ok, `self` isn't a class, but this is for consistency with the classes
|
584
|
-
field_defn.metadata[:type_class] = self
|
585
|
-
field_defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(field_defn)
|
586
|
-
field_defn
|
587
575
|
end
|
588
576
|
|
589
577
|
class MissingReturnTypeError < GraphQL::Error; end
|
590
578
|
attr_writer :type
|
591
579
|
|
592
580
|
def type
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
elsif @return_type_expr.nil?
|
598
|
-
# Not enough info to determine type
|
599
|
-
message = "Can't determine the return type for #{self.path}"
|
600
|
-
if @resolver_class
|
601
|
-
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)"
|
602
585
|
end
|
603
|
-
|
586
|
+
nullable = @return_type_null.nil? ? @resolver_class.null : @return_type_null
|
587
|
+
Member::BuildType.parse_type(return_type, null: nullable)
|
604
588
|
else
|
605
|
-
Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
589
|
+
@type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
606
590
|
end
|
607
591
|
rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
|
608
592
|
# Let this propagate up
|
@@ -619,14 +603,6 @@ module GraphQL
|
|
619
603
|
end
|
620
604
|
end
|
621
605
|
|
622
|
-
def accessible?(context)
|
623
|
-
if @resolver_class
|
624
|
-
@resolver_class.accessible?(context)
|
625
|
-
else
|
626
|
-
true
|
627
|
-
end
|
628
|
-
end
|
629
|
-
|
630
606
|
def authorized?(object, args, context)
|
631
607
|
if @resolver_class
|
632
608
|
# The resolver _instance_ will check itself during `resolve()`
|
@@ -640,62 +616,33 @@ module GraphQL
|
|
640
616
|
arg_values = args
|
641
617
|
using_arg_values = false
|
642
618
|
end
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
if
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
application_arg_value.
|
619
|
+
if args.size > 0
|
620
|
+
args = context.warden.arguments(self)
|
621
|
+
args.each do |arg|
|
622
|
+
arg_key = arg.keyword
|
623
|
+
if arg_values.key?(arg_key)
|
624
|
+
arg_value = arg_values[arg_key]
|
625
|
+
if using_arg_values
|
626
|
+
if arg_value.default_used?
|
627
|
+
# pass -- no auth required for default used
|
628
|
+
next
|
629
|
+
else
|
630
|
+
application_arg_value = arg_value.value
|
631
|
+
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
|
632
|
+
application_arg_value.keyword_arguments
|
633
|
+
end
|
656
634
|
end
|
635
|
+
else
|
636
|
+
application_arg_value = arg_value
|
657
637
|
end
|
658
|
-
else
|
659
|
-
application_arg_value = arg_value
|
660
|
-
end
|
661
638
|
|
662
|
-
|
663
|
-
|
664
|
-
end
|
665
|
-
end
|
666
|
-
end
|
667
|
-
true
|
668
|
-
end
|
669
|
-
end
|
670
|
-
|
671
|
-
# Implement {GraphQL::Field}'s resolve API.
|
672
|
-
#
|
673
|
-
# Eventually, we might hook up field instances to execution in another way. TBD.
|
674
|
-
# @see #resolve for how the interpreter hooks up to it
|
675
|
-
def resolve_field(obj, args, ctx)
|
676
|
-
ctx.schema.after_lazy(obj) do |after_obj|
|
677
|
-
# First, apply auth ...
|
678
|
-
query_ctx = ctx.query.context
|
679
|
-
# Some legacy fields can have `nil` here, not exactly sure why.
|
680
|
-
# @see https://github.com/rmosolgo/graphql-ruby/issues/1990 before removing
|
681
|
-
inner_obj = after_obj && after_obj.object
|
682
|
-
ctx.schema.after_lazy(to_ruby_args(after_obj, args, ctx)) do |ruby_args|
|
683
|
-
if authorized?(inner_obj, ruby_args, query_ctx)
|
684
|
-
# Then if it passed, resolve the field
|
685
|
-
if @resolve_proc
|
686
|
-
# Might be nil, still want to call the func in that case
|
687
|
-
with_extensions(inner_obj, ruby_args, query_ctx) do |extended_obj, extended_args|
|
688
|
-
# Pass the GraphQL args here for compatibility:
|
689
|
-
@resolve_proc.call(extended_obj, args, ctx)
|
639
|
+
if !arg.authorized?(object, application_arg_value, context)
|
640
|
+
return false
|
690
641
|
end
|
691
|
-
else
|
692
|
-
public_send_field(after_obj, ruby_args, query_ctx)
|
693
642
|
end
|
694
|
-
else
|
695
|
-
err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
|
696
|
-
query_ctx.schema.unauthorized_field(err)
|
697
643
|
end
|
698
644
|
end
|
645
|
+
true
|
699
646
|
end
|
700
647
|
end
|
701
648
|
|
@@ -704,34 +651,110 @@ module GraphQL
|
|
704
651
|
# @param object [GraphQL::Schema::Object] An instance of some type class, wrapping an application object
|
705
652
|
# @param args [Hash] A symbol-keyed hash of Ruby keyword arguments. (Empty if no args)
|
706
653
|
# @param ctx [GraphQL::Query::Context]
|
707
|
-
def resolve(object, args,
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
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
|
714
673
|
|
715
|
-
|
674
|
+
inner_object = obj.object
|
716
675
|
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
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
|
722
731
|
end
|
732
|
+
else
|
733
|
+
raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: query_ctx, field: self)
|
723
734
|
end
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
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
|
732
755
|
end
|
733
756
|
|
734
|
-
# @param ctx [GraphQL::Query::Context
|
757
|
+
# @param ctx [GraphQL::Query::Context]
|
735
758
|
def fetch_extra(extra_name, ctx)
|
736
759
|
if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
|
737
760
|
self.public_send(extra_name)
|
@@ -744,127 +767,6 @@ module GraphQL
|
|
744
767
|
|
745
768
|
private
|
746
769
|
|
747
|
-
NO_ARGS = {}.freeze
|
748
|
-
|
749
|
-
# Convert a GraphQL arguments instance into a Ruby-style hash.
|
750
|
-
#
|
751
|
-
# @param obj [GraphQL::Schema::Object] The object where this field is being resolved
|
752
|
-
# @param graphql_args [GraphQL::Query::Arguments]
|
753
|
-
# @param field_ctx [GraphQL::Query::Context::FieldResolutionContext]
|
754
|
-
# @return [Hash<Symbol => Any>]
|
755
|
-
def to_ruby_args(obj, graphql_args, field_ctx)
|
756
|
-
if graphql_args.any? || @extras.any?
|
757
|
-
# Splat the GraphQL::Arguments to Ruby keyword arguments
|
758
|
-
ruby_kwargs = graphql_args.to_kwargs
|
759
|
-
maybe_lazies = []
|
760
|
-
# Apply any `prepare` methods. Not great code organization, can this go somewhere better?
|
761
|
-
arguments(field_ctx).each do |name, arg_defn|
|
762
|
-
ruby_kwargs_key = arg_defn.keyword
|
763
|
-
|
764
|
-
if ruby_kwargs.key?(ruby_kwargs_key)
|
765
|
-
loads = arg_defn.loads
|
766
|
-
value = ruby_kwargs[ruby_kwargs_key]
|
767
|
-
loaded_value = if loads && !arg_defn.from_resolver?
|
768
|
-
if arg_defn.type.list?
|
769
|
-
loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, field_ctx.query.context) }
|
770
|
-
field_ctx.schema.after_any_lazies(loaded_values) { |result| result }
|
771
|
-
else
|
772
|
-
load_application_object(arg_defn, loads, value, field_ctx.query.context)
|
773
|
-
end
|
774
|
-
elsif arg_defn.type.list? && value.is_a?(Array)
|
775
|
-
field_ctx.schema.after_any_lazies(value, &:itself)
|
776
|
-
else
|
777
|
-
value
|
778
|
-
end
|
779
|
-
|
780
|
-
maybe_lazies << field_ctx.schema.after_lazy(loaded_value) do |loaded_value|
|
781
|
-
prepared_value = if arg_defn.prepare
|
782
|
-
arg_defn.prepare_value(obj, loaded_value)
|
783
|
-
else
|
784
|
-
loaded_value
|
785
|
-
end
|
786
|
-
|
787
|
-
ruby_kwargs[ruby_kwargs_key] = prepared_value
|
788
|
-
end
|
789
|
-
end
|
790
|
-
end
|
791
|
-
|
792
|
-
@extras.each do |extra_arg|
|
793
|
-
ruby_kwargs[extra_arg] = fetch_extra(extra_arg, field_ctx)
|
794
|
-
end
|
795
|
-
|
796
|
-
field_ctx.schema.after_any_lazies(maybe_lazies) do
|
797
|
-
ruby_kwargs
|
798
|
-
end
|
799
|
-
else
|
800
|
-
NO_ARGS
|
801
|
-
end
|
802
|
-
end
|
803
|
-
|
804
|
-
def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
|
805
|
-
with_extensions(unextended_obj, unextended_ruby_kwargs, query_ctx) do |obj, ruby_kwargs|
|
806
|
-
begin
|
807
|
-
method_receiver = nil
|
808
|
-
method_to_call = nil
|
809
|
-
if @resolver_class
|
810
|
-
if obj.is_a?(GraphQL::Schema::Object)
|
811
|
-
obj = obj.object
|
812
|
-
end
|
813
|
-
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
814
|
-
end
|
815
|
-
|
816
|
-
# Find a way to resolve this field, checking:
|
817
|
-
#
|
818
|
-
# - A method on the type instance;
|
819
|
-
# - Hash keys, if the wrapped object is a hash;
|
820
|
-
# - A method on the wrapped object;
|
821
|
-
# - Or, raise not implemented.
|
822
|
-
#
|
823
|
-
if obj.respond_to?(@resolver_method)
|
824
|
-
method_to_call = @resolver_method
|
825
|
-
method_receiver = obj
|
826
|
-
# Call the method with kwargs, if there are any
|
827
|
-
if ruby_kwargs.any?
|
828
|
-
obj.public_send(@resolver_method, **ruby_kwargs)
|
829
|
-
else
|
830
|
-
obj.public_send(@resolver_method)
|
831
|
-
end
|
832
|
-
elsif obj.object.is_a?(Hash)
|
833
|
-
inner_object = obj.object
|
834
|
-
if @dig_keys
|
835
|
-
inner_object.dig(*@dig_keys)
|
836
|
-
elsif inner_object.key?(@method_sym)
|
837
|
-
inner_object[@method_sym]
|
838
|
-
else
|
839
|
-
inner_object[@method_str]
|
840
|
-
end
|
841
|
-
elsif obj.object.respond_to?(@method_sym)
|
842
|
-
method_to_call = @method_sym
|
843
|
-
method_receiver = obj.object
|
844
|
-
if ruby_kwargs.any?
|
845
|
-
obj.object.public_send(@method_sym, **ruby_kwargs)
|
846
|
-
else
|
847
|
-
obj.object.public_send(@method_sym)
|
848
|
-
end
|
849
|
-
else
|
850
|
-
raise <<-ERR
|
851
|
-
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
852
|
-
|
853
|
-
- `#{obj.class}##{@resolver_method}`, which did not exist
|
854
|
-
- `#{obj.object.class}##{@method_sym}`, which did not exist
|
855
|
-
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
|
856
|
-
|
857
|
-
To implement this field, define one of the methods above (and check for typos)
|
858
|
-
ERR
|
859
|
-
end
|
860
|
-
rescue ArgumentError
|
861
|
-
assert_satisfactory_implementation(method_receiver, method_to_call, ruby_kwargs)
|
862
|
-
# if the line above doesn't raise, re-raise
|
863
|
-
raise
|
864
|
-
end
|
865
|
-
end
|
866
|
-
end
|
867
|
-
|
868
770
|
def assert_satisfactory_implementation(receiver, method_name, ruby_kwargs)
|
869
771
|
method_defn = receiver.method(method_name)
|
870
772
|
unsatisfied_ruby_kwargs = ruby_kwargs.dup
|
@@ -895,7 +797,7 @@ module GraphQL
|
|
895
797
|
|
896
798
|
if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
|
897
799
|
raise FieldImplementationFailed.new, <<-ERR
|
898
|
-
Failed to call
|
800
|
+
Failed to call `#{method_name.inspect}` on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
|
899
801
|
|
900
802
|
#{ unsatisfied_ruby_kwargs
|
901
803
|
.map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }
|