Class: GraphQL::Schema::Resolver
- Inherits:
-
Object
- Object
- GraphQL::Schema::Resolver
- Extended by:
- Member::BaseDSLMethods, Member::HasArguments, Member::HasPath
- Includes:
- Member::GraphQLTypeNames, Member::HasPath
- Defined in:
- lib/graphql/schema/resolver.rb
Overview
A class-based container for field configuration and resolution logic. It supports:
- Arguments, via
.argument(...)
helper, which will be applied to the field. - Return type, via
.type(..., null: ...)
, which will be applied to the field. - Description, via
.description(...)
, which will be applied to the field - Resolution, via
#resolve(**args)
method, which will be called to resolve the field. #object
and#context
accessors for use during#resolve
.
Resolvers can be attached with the resolver:
option in a field(...)
call.
A resolver's configuration may be overridden with other keywords in the field(...)
call.
See the Resolver.field_options to see how a Resolver becomes a set of field configuration options.
Direct Known Subclasses
Defined Under Namespace
Classes: LoadApplicationObjectFailedError
Constant Summary
Constants included from Member::GraphQLTypeNames
Member::GraphQLTypeNames::Boolean, Member::GraphQLTypeNames::ID, Member::GraphQLTypeNames::Int
Instance Attribute Summary collapse
- #context ⇒ GraphQL::Query::Context readonly
-
#object ⇒ Object
readonly
The application object this field is being resolved on.
Class Method Summary collapse
-
.argument(name, type, *rest, loads: nil, **kwargs, &block) ⇒ Object
Add an argument to this field's signature, but also add some preparation hook methods which will be used for this argument.
- .arguments_loads_as_type ⇒ Object private
-
.complexity(new_complexity = nil) ⇒ Integer, Proc
Specifies the complexity of the field.
-
.extras(new_extras = nil) ⇒ Object
Additional info injected into #resolve.
- .field_options ⇒ Object
-
.null(allow_null = nil) ⇒ Object
Specifies whether or not the field is nullable.
-
.resolve_method(new_method = nil) ⇒ Symbol
Default
:resolve
set below. -
.type(new_type = nil, null: nil) ⇒ Class
Call this method to get the return type of the field, or use it as a configuration method to assign a return type instead of generating one.
-
.type_expr ⇒ Object
A non-normalized type configuration, without
null
applied.
Instance Method Summary collapse
-
#authorized?(**args) ⇒ Boolean, early_return_data
Called after arguments are loaded, but before resolving.
-
#initialize(object:, context:) ⇒ Resolver
constructor
A new instance of Resolver.
-
#ready?(**args) ⇒ Boolean, early_return_data
Called before arguments are prepared.
-
#resolve(**args) ⇒ Object
Do the work.
-
#resolve_with_support(**args) ⇒ Object
private
This method is actually called by the runtime, it does some preparation and then eventually calls the user-defined
#resolve
method.
Methods included from Member::BaseDSLMethods
accessible?, default_graphql_name, description, graphql_name, introspection, mutation, name, overridden_graphql_name, to_graphql, visible?
Methods included from Member::HasArguments
add_argument, argument, argument_class, arguments, own_arguments
Methods included from Member::HasPath
Constructor Details
#initialize(object:, context:) ⇒ Resolver
Returns a new instance of Resolver.
31 32 33 34 35 36 37 38 39 40 |
# File 'lib/graphql/schema/resolver.rb', line 31 def initialize(object:, context:) @object = object @context = context # Since this hash is constantly rebuilt, cache it for this call @arguments_by_keyword = {} self.class.arguments.each do |name, arg| @arguments_by_keyword[arg.keyword] = arg end @arguments_loads_as_type = self.class.arguments_loads_as_type end |
Instance Attribute Details
#context ⇒ GraphQL::Query::Context (readonly)
46 47 48 |
# File 'lib/graphql/schema/resolver.rb', line 46 def context @context end |
#object ⇒ Object (readonly)
Returns The application object this field is being resolved on.
43 44 45 |
# File 'lib/graphql/schema/resolver.rb', line 43 def object @object end |
Class Method Details
.argument(name, type, *rest, loads: nil, **kwargs, &block) ⇒ Object
Add an argument to this field's signature, but also add some preparation hook methods which will be used for this argument
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'lib/graphql/schema/resolver.rb', line 325 def argument(name, type, *rest, loads: nil, **kwargs, &block) if loads name_as_string = name.to_s inferred_arg_name = case name_as_string when /_id$/ name_as_string.sub(/_id$/, "").to_sym when /_ids$/ name_as_string.sub(/_ids$/, "") .sub(/([^s])$/, "\\1s") .to_sym else name end kwargs[:as] ||= inferred_arg_name own_arguments_loads_as_type[kwargs[:as]] = loads end arg_defn = super(name, type, *rest, **kwargs, &block) if loads && arg_defn.type.list? class_eval <<-RUBY, __FILE__, __LINE__ + 1 def load_#{arg_defn.keyword}(values) GraphQL::Execution::Lazy.all(values.map { |value| load_application_object(:#{arg_defn.keyword}, value) }) end RUBY elsif loads class_eval <<-RUBY, __FILE__, __LINE__ + 1 def load_#{arg_defn.keyword}(value) load_application_object(:#{arg_defn.keyword}, value) end RUBY else class_eval <<-RUBY, __FILE__, __LINE__ + 1 def load_#{arg_defn.keyword}(value) value end RUBY end arg_defn end |
.arguments_loads_as_type ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
370 371 372 373 |
# File 'lib/graphql/schema/resolver.rb', line 370 def arguments_loads_as_type inherited_lookups = superclass.respond_to?(:arguments_loads_as_type) ? superclass.arguments_loads_as_type : {} inherited_lookups.merge(own_arguments_loads_as_type) end |
.complexity(new_complexity = nil) ⇒ Integer, Proc
Specifies the complexity of the field. Defaults to 1
297 298 299 300 301 302 |
# File 'lib/graphql/schema/resolver.rb', line 297 def complexity(new_complexity = nil) if new_complexity @complexity = new_complexity end @complexity || (superclass.respond_to?(:complexity) ? superclass.complexity : 1) end |
.extras(new_extras = nil) ⇒ Object
Additional info injected into #resolve
251 252 253 254 255 256 257 |
# File 'lib/graphql/schema/resolver.rb', line 251 def extras(new_extras = nil) if new_extras @own_extras = new_extras end own_extras = @own_extras || [] own_extras + (superclass.respond_to?(:extras) ? superclass.extras : []) end |
.field_options ⇒ Object
304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/graphql/schema/resolver.rb', line 304 def { type: type_expr, description: description, extras: extras, method: :resolve_with_support, resolver_class: self, arguments: arguments, null: null, complexity: complexity, } end |
.null(allow_null = nil) ⇒ Object
Specifies whether or not the field is nullable. Defaults to true
TODO unify with #type
262 263 264 265 266 267 268 |
# File 'lib/graphql/schema/resolver.rb', line 262 def null(allow_null = nil) if !allow_null.nil? @null = allow_null end @null.nil? ? (superclass.respond_to?(:null) ? superclass.null : true) : @null end |
.resolve_method(new_method = nil) ⇒ Symbol
Default :resolve
set below.
242 243 244 245 246 247 |
# File 'lib/graphql/schema/resolver.rb', line 242 def resolve_method(new_method = nil) if new_method @resolve_method = new_method end @resolve_method || (superclass.respond_to?(:resolve_method) ? superclass.resolve_method : :resolve) end |
.type(new_type = nil, null: nil) ⇒ Class
Call this method to get the return type of the field, or use it as a configuration method to assign a return type instead of generating one. TODO unify with #null
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/graphql/schema/resolver.rb', line 277 def type(new_type = nil, null: nil) if new_type if null.nil? raise ArgumentError, "required argument `null:` is missing" end @type_expr = new_type @null = null else if @type_expr GraphQL::Schema::Member::BuildType.parse_type(@type_expr, null: @null) elsif superclass.respond_to?(:type) superclass.type else nil end end end |
.type_expr ⇒ Object
A non-normalized type configuration, without null
applied
318 319 320 |
# File 'lib/graphql/schema/resolver.rb', line 318 def type_expr @type_expr || (superclass.respond_to?(:type_expr) ? superclass.type_expr : nil) end |
Instance Method Details
#authorized?(**args) ⇒ Boolean, early_return_data
Called after arguments are loaded, but before resolving.
Override it to check everything before calling the mutation.
129 130 131 |
# File 'lib/graphql/schema/resolver.rb', line 129 def (**args) true end |
#ready?(**args) ⇒ Boolean, early_return_data
Called before arguments are prepared. Implement this hook to make checks before doing any work.
If it returns a lazy object (like a promise), it will be synced by GraphQL (but the resulting value won't be used).
118 119 120 |
# File 'lib/graphql/schema/resolver.rb', line 118 def ready?(**args) true end |
#resolve(**args) ⇒ Object
Do the work. Everything happens here.
104 105 106 |
# File 'lib/graphql/schema/resolver.rb', line 104 def resolve(**args) raise NotImplementedError, "#{self.class.name}#resolve should execute the field's logic" end |
#resolve_with_support(**args) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method is actually called by the runtime,
it does some preparation and then eventually calls
the user-defined #resolve
method.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/graphql/schema/resolver.rb', line 52 def resolve_with_support(**args) # First call the ready? hook which may raise ready_val = if args.any? ready?(**args) else ready? end context.schema.after_lazy(ready_val) do |is_ready, ready_early_return| if ready_early_return if is_ready != false raise "Unexpected result from #ready? (expected `true`, `false` or `[false, {...}]`): [#{.inspect}, #{ready_early_return.inspect}]" else ready_early_return end elsif is_ready # Then call each prepare hook, which may return a different value # for that argument, or may return a lazy object load_arguments_val = load_arguments(args) context.schema.after_lazy(load_arguments_val) do |loaded_args| # Then call `authorized?`, which may raise or may return a lazy object = if loaded_args.any? (loaded_args) else end context.schema.after_lazy() do |(, early_return)| # If the `authorized?` returned two values, `false, early_return`, # then use the early return value instead of continuing if early_return if == false early_return else raise "Unexpected result from #authorized? (expected `true`, `false` or `[false, {...}]`): [#{.inspect}, #{early_return.inspect}]" end elsif # Finally, all the hooks have passed, so resolve it if loaded_args.any? public_send(self.class.resolve_method, **loaded_args) else public_send(self.class.resolve_method) end else nil end end end end end end |