Skip to content

Commit

Permalink
Align GraphQL resolvers to resolver interface of the GraphQL gem.
Browse files Browse the repository at this point in the history
The GraphQL gem has a resolver interface involving a `call` method with
5 arguments. We had our own interface that was slightly different. I'm
working on optimizing our GraphQL resolver implementation where we just
pass a map of resolvers to the GraphQL gem and allow it to dispatch each
field to the appropriate resolver. This is a step in that direction.
  • Loading branch information
myronmarston committed Feb 8, 2025
1 parent 46ec32a commit 80a940f
Show file tree
Hide file tree
Showing 15 changed files with 37 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def can_resolve?(field:, object:)
field.parent_type.name == :Query && field.name == :product
end

def resolve(field:, object:, args:, context:)
def call(parent_type, graphql_field, object, args, context)
query = @datastore_query_builder.new_query(
search_index_definitions: [@product_index_def],
monotonic_clock_deadline: context[:monotonic_clock_deadline],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ def can_resolve?(field:, object:)
field.parent_type.name == :Query && field.name == :_entities
end

def resolve(field:, object:, args:, context:)
def call(parent_type, graphql_field, object, args, context)
schema = context.fetch(:elastic_graph_schema)
field = schema.field_named(parent_type.graphql_name, graphql_field.name)

representations = args.fetch(:representations).map.with_index do |rep, index|
try_parse_representation(rep, schema) do |error_description|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def can_resolve?(field:, object:)
field.parent_type.name == :Query && field.name == :_service
end

def resolve(field:, object:, args:, context:)
def call(parent_type, field, object, args, context)
{"sdl" => service_sdl(context.fetch(:elastic_graph_schema).graphql_schema)}
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ def can_resolve?(field:, object:)
true
end

def resolve(field:, object:, args:, context:)
def call(parent_type, graphql_field, object, args, context)
field = context.fetch(:elastic_graph_schema).field_named(parent_type.graphql_name, graphql_field.name)
return with(field_path: field_path + [PathSegment.for(field: field, lookahead: args.fetch(:lookahead))]) if field.type.object?

key = Key::AggregatedValue.new(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ def can_resolve?(field:, object:)
true
end

def resolve(field:, object:, args:, context:)
def call(parent_type, graphql_field, object, args, context)
field = context.fetch(:elastic_graph_schema).field_named(parent_type.graphql_name, graphql_field.name)
new_field_path = field_path + [PathSegment.for(field: field, lookahead: args.fetch(:lookahead))]
return with(field_path: new_field_path) if field.type.object?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def can_resolve?(field:, object:)
true
end

def resolve(field:, object:, args:, context:)
def call(parent_type, graphql_field, object, args, context)
field = context.fetch(:elastic_graph_schema).field_named(parent_type.graphql_name, graphql_field.name)
path_segment = PathSegment.for(field: field, lookahead: args.fetch(:lookahead))
new_field_path = field_path + [path_segment]
return with(field_path: new_field_path) unless field.type.elasticgraph_category == :nested_sub_aggregation_connection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ def can_resolve?(field:, object:)
object.is_a?(DatastoreResponse::Document) || object.is_a?(::Hash)
end

def resolve(field:, object:, args:, context:)
def call(parent_type, graphql_field, object, args, context)
field = context.fetch(:elastic_graph_schema).field_named(parent_type.graphql_name, graphql_field.name)
field_name = field.name_in_index.to_s
data =
case object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def call(parent_type, field, object, args, context)
ERROR
end

result = resolver.resolve(field: schema_field, object: object, args: args, context: context)
result = resolver.call(parent_type, field, object, args, context)

# Give the field a chance to coerce the result before returning it. Initially, this is only used to deal with
# enum value overrides (e.g. so that if `DayOfWeek.MONDAY` has been overridden to `DayOfWeek.MON`, we can coerce
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ def can_resolve?(field:, object:)
field.parent_type.name == :Query && field.type.collection?
end

def resolve(field:, context:, args:, object:)
def call(parent_type, graphql_field, object, args, context)
field = context.fetch(:elastic_graph_schema).field_named(parent_type.graphql_name, graphql_field.name)
lookahead = args.fetch(:lookahead)
args = field.args_to_schema_form(args.except(:lookahead))
query = @resolver_query_adapter.build_query_from(field: field, args: args, lookahead: lookahead, context: context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def can_resolve?(field:, object:)
!!field.relation_join
end

def resolve(object:, field:, context:, args:)
def call(parent_type, graphql_field, object, args, context)
field = context.fetch(:elastic_graph_schema).field_named(parent_type.graphql_name, graphql_field.name)
log_warning = ->(**options) { log_field_problem_warning(field: field, **options) }
join = field.relation_join
id_or_ids = join.extract_id_or_ids_from(object, log_warning)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def self.new(*fields, &block)
end
end

def resolve(field:, object:, context:, args:)
def call(parent_type, graphql_field, object, args, context)
field = context.fetch(:elastic_graph_schema).field_named(parent_type.graphql_name, graphql_field.name)
args = field.args_to_schema_form(args.except(:lookahead))
method_name = canonical_name_for(field.name, "Field")
public_send(method_name, **args_to_canonical_form(args))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ module ElasticGraph

interface _Resolver
def can_resolve?: (field: Schema::Field, object: untyped) -> bool
def resolve: (
field: Schema::Field,
object: untyped,
context: ::GraphQL::Query::Context,
args: fieldArgs
def call: (
::GraphQL::Schema::_Type,
::GraphQL::Schema::Field,
untyped,
fieldArgs,
::GraphQL::Query::Context
) -> untyped
end
end
Expand Down
3 changes: 2 additions & 1 deletion elasticgraph-graphql/spec/support/resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def resolve(type_name, field_name, document = nil, query_overrides: {}, **args)
query: nil,
schema: graphql.schema.graphql_schema,
values: {
elastic_graph_schema: graphql.schema,
schema_element_names: graphql.runtime_metadata.schema_element_names,
dataloader: dataloader,
elastic_graph_query_tracker: query_details_tracker,
Expand All @@ -38,7 +39,7 @@ def resolve(type_name, field_name, document = nil, query_overrides: {}, **args)
# [^1]: https://github.com/rmosolgo/graphql-ruby/blob/v2.1.0/lib/graphql/pagination/connection.rb#L94-L96
# [^2]: https://github.com/rmosolgo/graphql-ruby/blob/v2.1.0/lib/graphql/execution/interpreter/runtime.rb#L935-L941
::Thread.current[:__graphql_runtime_info] = ::Hash.new { |h, k| h[k] = ::GraphQL::Execution::Interpreter::Runtime::CurrentState.new }
resolver.resolve(field: field, object: document, context: context, args: args)
resolver.call(field.parent_type.graphql_type, field.graphql_field, document, args, context)
ensure
::Thread.current[:__graphql_runtime_info] = nil
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ def can_resolve?(field:, object:)
field.name == :multiply
end

def resolve(field:, object:, args:, context:)
def call(parent_type, field, object, args, context)
[
args.dig(:operands, "x"),
args.dig(:operands, "y"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,16 @@ module Resolvers
end

def resolve(args: {}, **options)
person, field = person_object_and_schema_field(**options)
person, schema_field = person_object_and_schema_field(**options)
lookahead = instance_double("GraphQL::Execution::Lookahead")
person.resolve(field: field, object: person, context: {}, args: args.merge(lookahead: lookahead))

person.call(
schema_field.parent_type.graphql_type,
schema_field.graphql_field,
person,
args.merge(lookahead: lookahead),
{elastic_graph_schema: schema_field.schema}
)
end
end

Expand Down

0 comments on commit 80a940f

Please sign in to comment.