Skip to content

Commit

Permalink
Use extended instead of originals in after_resolve
Browse files Browse the repository at this point in the history
Field Extensions let you extend (modify) the resolver object and
arguments in the `resolve` hook. Previously the `after_resolve` hook
would receive the *original* object and arguments and not the extended
ones. This was a lossy process with no way for `after_resolve` to access
the extended values.

This changes `after_resolve` to receive the extended values instead. If
you need access to the original non-extended values, the `memo` argument
can be used.

Example:

```ruby
class MyExtension < GraphQL::Schema::FieldExtension
  def apply(field)
    field.argument(:my_new_arg, :string, required: false)
  end

  def resolve(object:, arguments:, context:)
    next_args = arguments.dup
    next_args.delete(:my_new_arg)
    yield(object, next_args, { original_arguments: arguments })
  end

  def after_resolve(value:, context:, arguments:, memo:, **_args)
    # `arguments` => extended/modified arguments
    # `memo` => hash with `original_arguments`
  end
end
```
  • Loading branch information
swalkinshaw committed Sep 25, 2020
1 parent 183f318 commit 026040a
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 13 deletions.
13 changes: 7 additions & 6 deletions lib/graphql/schema/field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -725,20 +725,21 @@ def with_extensions(obj, args, ctx)
if @extensions.empty?
yield(obj, args)
else
# Save these so that the originals can be re-given to `after_resolve` handlers.
original_args = args
original_obj = obj
extended_obj = obj
extended_args = args

memos = []
value = run_extensions_before_resolve(memos, obj, args, ctx) do |extended_obj, extended_args|
yield(extended_obj, extended_args)
value = run_extensions_before_resolve(memos, obj, args, ctx) do |obj, args|
extended_obj = obj
extended_args = args
yield(obj, args)
end

ctx.schema.after_lazy(value) do |resolved_value|
@extensions.each_with_index do |ext, idx|
memo = memos[idx]
# TODO after_lazy?
resolved_value = ext.after_resolve(object: original_obj, arguments: original_args, context: ctx, value: resolved_value, memo: memo)
resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
end
resolved_value
end
Expand Down
15 changes: 8 additions & 7 deletions lib/graphql/schema/field/connection_extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ def resolve(object:, arguments:, context:)
next_args.delete(:last)
next_args.delete(:before)
next_args.delete(:after)
yield(object, next_args)
yield(object, next_args, arguments)
end

def after_resolve(value:, object:, arguments:, context:, memo:)
original_arguments = memo
# rename some inputs to avoid conflicts inside the block
maybe_lazy = value
value = nil
Expand All @@ -37,10 +38,10 @@ def after_resolve(value:, object:, arguments:, context:, memo:)
# update the connection with some things that may not have been provided
value.context ||= context
value.parent ||= object.object
value.first_value ||= arguments[:first]
value.after_value ||= arguments[:after]
value.last_value ||= arguments[:last]
value.before_value ||= arguments[:before]
value.first_value ||= original_arguments[:first]
value.after_value ||= original_arguments[:after]
value.last_value ||= original_arguments[:last]
value.before_value ||= original_arguments[:before]
if field.has_max_page_size? && !value.has_max_page_size_override?
value.max_page_size = field.max_page_size
end
Expand All @@ -50,15 +51,15 @@ def after_resolve(value:, object:, arguments:, context:, memo:)
value
elsif context.schema.new_connections?
wrappers = context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
context.schema.connections.wrap(field, object.object, value, arguments, context, wrappers: wrappers)
context.schema.connections.wrap(field, object.object, value, original_arguments, context, wrappers: wrappers)
else
if object.is_a?(GraphQL::Schema::Object)
object = object.object
end
connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(value)
connection_class.new(
value,
arguments,
original_arguments,
field: field,
max_page_size: field.max_page_size,
parent: object,
Expand Down

0 comments on commit 026040a

Please sign in to comment.