Skip to content

Commit 64a2a98

Browse files
committed
Introduce ConfiguredGraphQLResolver.
This allows us to pair a `name` of a GraphQL resolver with `config`. We'll be using this in a later PR to allow GraphQL resolvers to be parameterized at the field level.
1 parent 61e0868 commit 64a2a98

22 files changed

Lines changed: 4351 additions & 2145 deletions

File tree

config/schema/artifacts/runtime_metadata.yaml

Lines changed: 2086 additions & 1043 deletions
Large diffs are not rendered by default.

config/schema/artifacts_with_apollo/runtime_metadata.yaml

Lines changed: 2102 additions & 1051 deletions
Large diffs are not rendered by default.

elasticgraph-apollo/spec/unit/elastic_graph/apollo/schema_definition_spec.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
# frozen_string_literal: true
88

99
require "elastic_graph/apollo/schema_definition/api_extension"
10+
require "elastic_graph/spec_support/runtime_metadata_support"
1011
require "elastic_graph/spec_support/schema_definition_helpers"
1112
require "graphql"
1213

1314
module ElasticGraph
1415
module Apollo
1516
RSpec.describe SchemaDefinition do
17+
include SchemaArtifacts::RuntimeMetadata::RuntimeMetadataSupport
1618
include_context "SchemaDefinitionHelpers"
1719

1820
def self.with_both_casing_forms(&block)
@@ -431,8 +433,8 @@ def self.with_both_casing_forms(&block)
431433
results = define_schema(with_apollo: true) { |s| define_some_types_on(s) }
432434
query_type = results.runtime_metadata.object_types_by_name.fetch("Query")
433435

434-
expect(query_type.graphql_fields_by_name.fetch("_entities").resolver).to eq :apollo_entities
435-
expect(query_type.graphql_fields_by_name.fetch("_service").resolver).to eq :apollo_service
436+
expect(query_type.graphql_fields_by_name.fetch("_entities").resolver).to eq configured_graphql_resolver(:apollo_entities)
437+
expect(query_type.graphql_fields_by_name.fetch("_service").resolver).to eq configured_graphql_resolver(:apollo_service)
436438
end
437439

438440
# We use `dont_validate_graphql_schema` here because the validation triggers the example exceptions we assert on from

elasticgraph-graphql/lib/elastic_graph/graphql/resolvers/graphql_adapter_builder.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ def scalar_type_hash
4242
def object_type_hash
4343
@runtime_metadata.object_types_by_name.filter_map do |type_name, type|
4444
fields_hash = type.graphql_fields_by_name.filter_map do |field_name, field|
45-
if (resolver_name = field.resolver)
46-
resolver = @named_resolvers.fetch(resolver_name) do
47-
raise Errors::SchemaError, "Resolver `#{resolver_name}` (for `#{type_name}.#{field_name}`) cannot be found."
45+
if (configured_resolver = field.resolver)
46+
resolver = @named_resolvers.fetch(configured_resolver.name) do
47+
raise Errors::SchemaError, "Resolver `#{configured_resolver.name}` (for `#{type_name}.#{field_name}`) cannot be found."
4848
end
4949

5050
resolver_lambda =

elasticgraph-graphql/lib/elastic_graph/graphql/schema/field.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def initialize(schema, parent_type, graphql_field, runtime_metadata, resolvers_n
2929
@computation_detail = runtime_metadata&.computation_detail
3030
@resolver = runtime_metadata&.resolver
3131
@name_in_index = runtime_metadata&.name_in_index || name
32-
@graphql_field.extras([:lookahead]) if resolvers_needing_lookahead.include?(@resolver)
32+
@graphql_field.extras([:lookahead]) if resolvers_needing_lookahead.include?(@resolver&.name)
3333
end
3434

3535
def type

elasticgraph-graphql/spec/support/query_adapter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def call(parent_type, field, object, args, context)
8383
end
8484

8585
def resolved_with_resolver_that_builds_datastore_query?(schema_field, object)
86-
resolver = @graphql.named_graphql_resolvers.fetch(schema_field.resolver)
86+
resolver = @graphql.named_graphql_resolvers.fetch(schema_field.resolver.name)
8787
@resolvers_that_build_datastore_query.include?(resolver)
8888
end
8989

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright 2024 - 2025 Block, Inc.
2+
#
3+
# Use of this source code is governed by an MIT-style
4+
# license that can be found in the LICENSE file or at
5+
# https://opensource.org/licenses/MIT.
6+
#
7+
# frozen_string_literal: true
8+
9+
require "elastic_graph/schema_artifacts/runtime_metadata/extension_loader"
10+
require "elastic_graph/support/hash_util"
11+
12+
module ElasticGraph
13+
module SchemaArtifacts
14+
module RuntimeMetadata
15+
# @private
16+
class ConfiguredGraphQLResolver < ::Data.define(:name, :config)
17+
NAME = "name"
18+
CONFIG = "config"
19+
20+
def self.from_hash(hash)
21+
new(
22+
name: hash.fetch(NAME).to_sym,
23+
config: Support::HashUtil.symbolize_keys(hash[CONFIG] || {})
24+
)
25+
end
26+
27+
def to_dumpable_hash
28+
{
29+
# Keys here are ordered alphabetically; please keep them that way.
30+
CONFIG => Support::HashUtil.stringify_keys(config),
31+
NAME => name.to_s
32+
}.reject { |_, v| v.empty? }
33+
end
34+
end
35+
end
36+
end
37+
end

elasticgraph-schema_artifacts/lib/elastic_graph/schema_artifacts/runtime_metadata/graphql_field.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# frozen_string_literal: true
88

99
require "elastic_graph/schema_artifacts/runtime_metadata/computation_detail"
10+
require "elastic_graph/schema_artifacts/runtime_metadata/configured_graphql_resolver"
1011
require "elastic_graph/schema_artifacts/runtime_metadata/relation"
1112

1213
module ElasticGraph
@@ -24,7 +25,7 @@ def self.from_hash(hash)
2425
name_in_index: hash[NAME_IN_INDEX],
2526
relation: hash[RELATION]&.then { |rel_hash| Relation.from_hash(rel_hash) },
2627
computation_detail: hash[AGGREGATION_DETAIL]&.then { |agg_hash| ComputationDetail.from_hash(agg_hash) },
27-
resolver: hash[RESOLVER]&.to_sym
28+
resolver: hash[RESOLVER]&.then { |res_hash| ConfiguredGraphQLResolver.from_hash(res_hash) }
2829
)
2930
end
3031

@@ -34,7 +35,7 @@ def to_dumpable_hash
3435
AGGREGATION_DETAIL => computation_detail&.to_dumpable_hash,
3536
NAME_IN_INDEX => name_in_index,
3637
RELATION => relation&.to_dumpable_hash,
37-
RESOLVER => resolver&.to_s
38+
RESOLVER => resolver&.to_dumpable_hash
3839
}
3940
end
4041

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module ElasticGraph
2+
module SchemaArtifacts
3+
module RuntimeMetadata
4+
class ConfiguredGraphQLResolverSupertype
5+
attr_reader name: ::Symbol
6+
attr_reader config: ::Hash[::Symbol, untyped]
7+
8+
def initialize: (
9+
name: ::Symbol,
10+
config: ::Hash[::Symbol, untyped]
11+
) -> void
12+
13+
def with: (
14+
?name: ::Symbol,
15+
?config: ::Hash[::Symbol, untyped]
16+
) -> instance
17+
18+
def self.new:
19+
(name: ::Symbol, config: ::Hash[::Symbol, untyped]) -> instance
20+
| (::Symbol, ::Hash[::Symbol, untyped]) -> instance
21+
end
22+
23+
class ConfiguredGraphQLResolver < ConfiguredGraphQLResolverSupertype
24+
NAME: "name"
25+
CONFIG: "config"
26+
27+
def self.from_hash: (::Hash[::String, untyped]) -> ConfiguredGraphQLResolver
28+
def to_dumpable_hash: () -> ::Hash[::String, untyped]
29+
end
30+
end
31+
end
32+
end

elasticgraph-schema_artifacts/sig/elastic_graph/schema_artifacts/runtime_metadata/graphql_field.rbs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,25 @@ module ElasticGraph
55
attr_reader name_in_index: ::String?
66
attr_reader relation: Relation?
77
attr_reader computation_detail: ComputationDetail?
8-
attr_reader resolver: ::Symbol?
8+
attr_reader resolver: ConfiguredGraphQLResolver?
99

1010
def initialize: (
1111
name_in_index: ::String?,
1212
relation: Relation?,
1313
computation_detail: ComputationDetail?,
14-
resolver: ::Symbol?
14+
resolver: ConfiguredGraphQLResolver?
1515
) -> void
1616

1717
def with: (
1818
?name_in_index: ::String?,
1919
?relation: Relation?,
2020
?computation_detail: ComputationDetail?,
21-
?resolver: ::Symbol?
21+
?resolver: ConfiguredGraphQLResolver?
2222
) -> instance
2323

2424
def self.new:
25-
(name_in_index: ::String?, relation: Relation?, computation_detail: ComputationDetail?, resolver: ::Symbol?) -> instance
26-
| (::String?, Relation?, ComputationDetail?, ::Symbol?) -> instance
25+
(name_in_index: ::String?, relation: Relation?, computation_detail: ComputationDetail?, resolver: ConfiguredGraphQLResolver?) -> instance
26+
| (::String?, Relation?, ComputationDetail?, ConfiguredGraphQLResolver?) -> instance
2727
end
2828

2929
class GraphQLField < GraphQLFieldSupertype

0 commit comments

Comments
 (0)