elasticgraph-apollo 0.18.0.0
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +63 -0
- data/apollo_tests_implementation/Dockerfile +66 -0
- data/apollo_tests_implementation/Gemfile +27 -0
- data/apollo_tests_implementation/Rakefile +22 -0
- data/apollo_tests_implementation/config/products_schema.rb +173 -0
- data/apollo_tests_implementation/config/settings.yaml +34 -0
- data/apollo_tests_implementation/config.ru +122 -0
- data/apollo_tests_implementation/docker-compose.yaml +18 -0
- data/apollo_tests_implementation/lib/test_implementation_extension.rb +58 -0
- data/apollo_tests_implementation/wait_for_datastore.sh +17 -0
- data/elasticgraph-apollo.gemspec +27 -0
- data/lib/elastic_graph/apollo/graphql/engine_extension.rb +52 -0
- data/lib/elastic_graph/apollo/graphql/entities_field_resolver.rb +305 -0
- data/lib/elastic_graph/apollo/graphql/http_endpoint_extension.rb +45 -0
- data/lib/elastic_graph/apollo/graphql/service_field_resolver.rb +30 -0
- data/lib/elastic_graph/apollo/schema_definition/api_extension.rb +385 -0
- data/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb +119 -0
- data/lib/elastic_graph/apollo/schema_definition/argument_extension.rb +20 -0
- data/lib/elastic_graph/apollo/schema_definition/entity_type_extension.rb +30 -0
- data/lib/elastic_graph/apollo/schema_definition/enum_type_extension.rb +23 -0
- data/lib/elastic_graph/apollo/schema_definition/enum_value_extension.rb +20 -0
- data/lib/elastic_graph/apollo/schema_definition/factory_extension.rb +104 -0
- data/lib/elastic_graph/apollo/schema_definition/field_extension.rb +59 -0
- data/lib/elastic_graph/apollo/schema_definition/graphql_sdl_enumerator_extension.rb +69 -0
- data/lib/elastic_graph/apollo/schema_definition/input_type_extension.rb +20 -0
- data/lib/elastic_graph/apollo/schema_definition/interface_type_extension.rb +25 -0
- data/lib/elastic_graph/apollo/schema_definition/object_type_extension.rb +28 -0
- data/lib/elastic_graph/apollo/schema_definition/scalar_type_extension.rb +23 -0
- data/lib/elastic_graph/apollo/schema_definition/state_extension.rb +23 -0
- data/lib/elastic_graph/apollo/schema_definition/union_type_extension.rb +20 -0
- data/script/boot_eg_apollo_implementation +22 -0
- data/script/export_docker_env_vars.sh +15 -0
- data/script/test_compatibility +54 -0
- metadata +472 -0
@@ -0,0 +1,385 @@
|
|
1
|
+
# Copyright 2024 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/error"
|
10
|
+
require "elastic_graph/version"
|
11
|
+
require "elastic_graph/apollo/graphql/engine_extension"
|
12
|
+
require "elastic_graph/apollo/schema_definition/entity_type_extension"
|
13
|
+
require "elastic_graph/apollo/schema_definition/factory_extension"
|
14
|
+
require "elastic_graph/apollo/schema_definition/state_extension"
|
15
|
+
|
16
|
+
module ElasticGraph
|
17
|
+
module Apollo
|
18
|
+
module SchemaDefinition
|
19
|
+
# Module designed to be extended onto an `ElasticGraph::SchemaDefinition::API` instance
|
20
|
+
# to customize the schema artifacts based on the Apollo Federation subgraph spec:
|
21
|
+
#
|
22
|
+
# https://www.apollographql.com/docs/federation/subgraph-spec/
|
23
|
+
#
|
24
|
+
# Note that at this time we do not yet support extending a type owned by another
|
25
|
+
# subgraph (which the `@requires`, `@provides`, `@extends`, and `@external`
|
26
|
+
# directives are used for).
|
27
|
+
module APIExtension
|
28
|
+
def results
|
29
|
+
register_graphql_extension GraphQL::EngineExtension, defined_at: "elastic_graph/apollo/graphql/engine_extension"
|
30
|
+
define_apollo_schema_elements
|
31
|
+
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
# Called from the public API, as:
|
36
|
+
# schema.tag_built_in_types_with "tag-name", except: ["IntAggregatedValues", ...]
|
37
|
+
def tag_built_in_types_with(name, except: [])
|
38
|
+
except_set = except.to_set
|
39
|
+
on_built_in_types do |type|
|
40
|
+
type.directive("tag", name: name) unless except_set.include?(type.name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Picks which version of Apollo federation to target. By default, the latest supported version is
|
45
|
+
# targeted, but you can call this to pick an earlier version, which may be necessary if your
|
46
|
+
# organization is running an old version of Apollo studio.
|
47
|
+
def target_apollo_federation_version(version)
|
48
|
+
# Allow the version to have the `v` prefix, but don't require it.
|
49
|
+
version = version.delete_prefix("v")
|
50
|
+
|
51
|
+
state.apollo_directive_definitions = DIRECTIVE_DEFINITIONS_BY_FEDERATION_VERSION.fetch(version) do
|
52
|
+
supported_version_descriptions = DIRECTIVE_DEFINITIONS_BY_FEDERATION_VERSION.keys.map do |version_number|
|
53
|
+
"v#{version_number}"
|
54
|
+
end.join(", ")
|
55
|
+
|
56
|
+
raise SchemaError, "elasticgraph-apollo v#{ElasticGraph::VERSION} does not support Apollo federation v#{version}. " \
|
57
|
+
"Pick one of the supported versions (#{supported_version_descriptions}) instead."
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.extended(api)
|
62
|
+
api.factory.extend FactoryExtension
|
63
|
+
api.state.extend StateExtension
|
64
|
+
|
65
|
+
latest_federation_version = DIRECTIVE_DEFINITIONS_BY_FEDERATION_VERSION
|
66
|
+
.keys
|
67
|
+
.max_by { |v| v.split(".").map(&:to_i) } # : ::String
|
68
|
+
|
69
|
+
api.target_apollo_federation_version latest_federation_version
|
70
|
+
|
71
|
+
api.on_built_in_types do |type|
|
72
|
+
# Built-in types like `PageInfo` need to be tagged with `@shareable` on Federation V2 since other subgraphs may
|
73
|
+
# have them and they aren't entity types. `Query`, as the root, is a special case that must be skipped.
|
74
|
+
(_ = type).apollo_shareable if type.respond_to?(:apollo_shareable) && type.name != "Query"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# These directive definitions come straight from the Apollo federation spec:
|
81
|
+
# https://github.com/apollographql/federation/blob/25beb382fff253ac38ef6d7a5454af60da0addbb/docs/source/subgraph-spec.mdx#L57-L70
|
82
|
+
# https://github.com/apollographql/apollo-federation-subgraph-compatibility/blob/2.0.0/COMPATIBILITY.md#products-schema-to-be-implemented-by-library-maintainers
|
83
|
+
#
|
84
|
+
# I've updated them here to match the "canonical form" that the GraphQL
|
85
|
+
# gem dumps for directives (e.g. it sorts the `on` clauses alphabetically) so that
|
86
|
+
# we can use this from our tests to assert the resulting GraphQL SDL.
|
87
|
+
directives_for_fed_v2_6 = [
|
88
|
+
<<~EOS.strip,
|
89
|
+
extend schema
|
90
|
+
@link(import: ["@authenticated", "@composeDirective", "@extends", "@external", "@inaccessible", "@interfaceObject", "@key", "@override", "@policy", "@provides", "@requires", "@requiresScopes", "@shareable", "@tag", "FieldSet"], url: "https://specs.apollo.dev/federation/v2.6")
|
91
|
+
EOS
|
92
|
+
"directive @authenticated on ENUM | FIELD_DEFINITION | INTERFACE | OBJECT | SCALAR",
|
93
|
+
"directive @composeDirective(name: String!) repeatable on SCHEMA",
|
94
|
+
"directive @extends on INTERFACE | OBJECT",
|
95
|
+
"directive @external on FIELD_DEFINITION | OBJECT",
|
96
|
+
"directive @inaccessible on ARGUMENT_DEFINITION | ENUM | ENUM_VALUE | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | INPUT_OBJECT | INTERFACE | OBJECT | SCALAR | UNION",
|
97
|
+
"directive @interfaceObject on OBJECT",
|
98
|
+
"directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT",
|
99
|
+
"directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA",
|
100
|
+
"directive @override(from: String!) on FIELD_DEFINITION",
|
101
|
+
"directive @policy(policies: [[federation__Policy!]!]!) on ENUM | FIELD_DEFINITION | INTERFACE | OBJECT | SCALAR",
|
102
|
+
"directive @provides(fields: FieldSet!) on FIELD_DEFINITION",
|
103
|
+
"directive @requires(fields: FieldSet!) on FIELD_DEFINITION",
|
104
|
+
"directive @requiresScopes(scopes: [[federation__Scope!]!]!) on ENUM | FIELD_DEFINITION | INTERFACE | OBJECT | SCALAR",
|
105
|
+
"directive @shareable on FIELD_DEFINITION | OBJECT",
|
106
|
+
"directive @tag(name: String!) repeatable on ARGUMENT_DEFINITION | ENUM | ENUM_VALUE | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | INPUT_OBJECT | INTERFACE | OBJECT | SCALAR | UNION"
|
107
|
+
]
|
108
|
+
|
109
|
+
# Differences between federation v2.5 and v2.6
|
110
|
+
#
|
111
|
+
# - v2.5 has no @policy directive (v2.6 has this).
|
112
|
+
# - The link URL reflects the version
|
113
|
+
directives_for_fed_v2_5 = directives_for_fed_v2_6.filter_map do |directive|
|
114
|
+
if directive.include?("extend schema")
|
115
|
+
directive
|
116
|
+
.sub(', "@policy"', "")
|
117
|
+
.sub("v2.6", "v2.5")
|
118
|
+
elsif directive.include?("directive @policy")
|
119
|
+
nil
|
120
|
+
else
|
121
|
+
directive
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Differences between federation v2.3 and v2.5
|
126
|
+
#
|
127
|
+
# - v2.3 has no @authenticated directive (v2.5 has this).
|
128
|
+
# - v2.3 has no @requiresScopes directive (v2.5 has this).
|
129
|
+
# - The link URL reflects the version
|
130
|
+
directives_for_fed_v2_3 = directives_for_fed_v2_5.filter_map do |directive|
|
131
|
+
if directive.include?("extend schema")
|
132
|
+
directive
|
133
|
+
.sub('"@authenticated", ', "")
|
134
|
+
.sub(', "@requiresScopes"', "")
|
135
|
+
.sub("v2.5", "v2.3")
|
136
|
+
elsif directive.include?("directive @authenticated") || directive.include?("directive @requiresScopes")
|
137
|
+
nil
|
138
|
+
else
|
139
|
+
directive
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Differences between federation v2.0 and v2.3
|
144
|
+
#
|
145
|
+
# - v2.0 has no @composeDirective directive (v2.3 has this).
|
146
|
+
# - v2.0 has no @interfaceObject directive (v2.3 has this).
|
147
|
+
# - The link URL reflects the version
|
148
|
+
directives_for_fed_v2_0 = directives_for_fed_v2_3.filter_map do |directive|
|
149
|
+
if directive.include?("extend schema")
|
150
|
+
directive
|
151
|
+
.sub('"@composeDirective", ', "")
|
152
|
+
.sub(', "@interfaceObject"', "")
|
153
|
+
.sub("v2.3", "v2.0")
|
154
|
+
elsif directive.include?("directive @interfaceObject") || directive.include?("directive @composeDirective")
|
155
|
+
nil
|
156
|
+
else
|
157
|
+
directive
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
DIRECTIVE_DEFINITIONS_BY_FEDERATION_VERSION = {
|
162
|
+
"2.6" => directives_for_fed_v2_6,
|
163
|
+
"2.5" => directives_for_fed_v2_5,
|
164
|
+
"2.3" => directives_for_fed_v2_3,
|
165
|
+
"2.0" => directives_for_fed_v2_0
|
166
|
+
}
|
167
|
+
|
168
|
+
def define_apollo_schema_elements
|
169
|
+
state.apollo_directive_definitions.each { |directive| raw_sdl directive }
|
170
|
+
|
171
|
+
apollo_scalar_type "link__Import" do |t|
|
172
|
+
t.documentation "Scalar type used by the `@link` directive required for Apollo Federation V2."
|
173
|
+
# `scalar_type` requires we set these but this scalar type is only in GraphQL.
|
174
|
+
t.mapping type: nil
|
175
|
+
t.json_schema type: "null"
|
176
|
+
end
|
177
|
+
|
178
|
+
apollo_scalar_type "federation__Scope" do |t|
|
179
|
+
t.documentation "Scalar type used by the `@requiresScopes` directive required for Apollo Federation V2.5+."
|
180
|
+
# `scalar_type` requires we set these but this scalar type is only in GraphQL.
|
181
|
+
t.mapping type: nil
|
182
|
+
t.json_schema type: "null"
|
183
|
+
end
|
184
|
+
|
185
|
+
apollo_scalar_type "federation__Policy" do |t|
|
186
|
+
t.documentation "Scalar type used by the `@policy` directive required for Apollo Federation V2.6+."
|
187
|
+
# `scalar_type` requires we set these but this scalar type is only in GraphQL.
|
188
|
+
t.mapping type: nil
|
189
|
+
t.json_schema type: "null"
|
190
|
+
end
|
191
|
+
|
192
|
+
# Copied from https://github.com/apollographql/federation/blob/b3a3cb84d8d67d1d6e817dc85b9ae0ecdd9908d1/docs/source/subgraph-spec.mdx#subgraph-schema-additions
|
193
|
+
apollo_enum_type "link__Purpose" do |t|
|
194
|
+
t.documentation "Enum type used by the `@link` directive required for Apollo Federation V2."
|
195
|
+
|
196
|
+
t.value "SECURITY" do |v|
|
197
|
+
v.documentation "`SECURITY` features provide metadata necessary to securely resolve fields."
|
198
|
+
end
|
199
|
+
|
200
|
+
t.value "EXECUTION" do |v|
|
201
|
+
v.documentation "`EXECUTION` features provide metadata necessary for operation execution."
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
apollo_scalar_type "FieldSet" do |t|
|
206
|
+
t.documentation <<~EOS
|
207
|
+
A custom scalar type required by the [Apollo Federation subgraph
|
208
|
+
spec](https://www.apollographql.com/docs/federation/subgraph-spec/#scalar-fieldset):
|
209
|
+
|
210
|
+
> This string-serialized scalar represents a set of fields that's passed to a federated directive,
|
211
|
+
> such as `@key`, `@requires`, or `@provides`.
|
212
|
+
>
|
213
|
+
> Grammatically, a `FieldSet` is a [selection set](http://spec.graphql.org/draft/#sec-Selection-Sets)
|
214
|
+
> minus the outermost curly braces. It can represent a single field (`"upc"`), multiple fields
|
215
|
+
> (`"id countryCode"`), and even nested selection sets (`"id organization { id }"`).
|
216
|
+
|
217
|
+
Not intended for use by clients other than Apollo.
|
218
|
+
EOS
|
219
|
+
|
220
|
+
# `scalar_type` requires we set these but this scalar type is only in GraphQL.
|
221
|
+
t.mapping type: nil
|
222
|
+
t.json_schema type: "null"
|
223
|
+
end
|
224
|
+
|
225
|
+
apollo_scalar_type "_Any" do |t|
|
226
|
+
t.documentation <<~EOS
|
227
|
+
A custom scalar type required by the [Apollo Federation subgraph
|
228
|
+
spec](https://www.apollographql.com/docs/federation/subgraph-spec/#scalar-_any):
|
229
|
+
|
230
|
+
> This scalar is the type used for entity **representations** that the graph router
|
231
|
+
> passes to the `Query._entities` field. An `_Any` scalar is validated by matching
|
232
|
+
> its `__typename` and `@key` fields against entities defined in the subgraph schema.
|
233
|
+
>
|
234
|
+
> An `_Any` is serialized as a JSON object, like so:
|
235
|
+
>
|
236
|
+
> ```
|
237
|
+
> {
|
238
|
+
> "__typename": "Product",
|
239
|
+
> "upc": "abc123"
|
240
|
+
> }
|
241
|
+
> ```
|
242
|
+
|
243
|
+
Not intended for use by clients other than Apollo.
|
244
|
+
EOS
|
245
|
+
|
246
|
+
# `scalar_type` requires we set these but this scalar type is only in GraphQL.
|
247
|
+
t.mapping type: nil
|
248
|
+
t.json_schema type: "null"
|
249
|
+
end
|
250
|
+
|
251
|
+
apollo_object_type "_Service" do |t|
|
252
|
+
t.documentation <<~EOS
|
253
|
+
An object type required by the [Apollo Federation subgraph
|
254
|
+
spec](https://www.apollographql.com/docs/federation/subgraph-spec/#type-_service):
|
255
|
+
|
256
|
+
> This object type must have an `sdl: String!` field, which returns the SDL of the subgraph schema as a string.
|
257
|
+
>
|
258
|
+
> - The returned schema string _must_ include all uses of federation-specific directives (`@key`, `@requires`, etc.).
|
259
|
+
> - **If supporting Federation 1,** the schema _must not_ include any definitions from [Subgraph schema additions](https://www.apollographql.com/docs/federation/subgraph-spec/#subgraph-schema-additions).
|
260
|
+
>
|
261
|
+
> For details, see [Enhanced introspection with `Query._service`](https://www.apollographql.com/docs/federation/subgraph-spec/#enhanced-introspection-with-query_service).
|
262
|
+
|
263
|
+
Not intended for use by clients other than Apollo.
|
264
|
+
EOS
|
265
|
+
|
266
|
+
t.field "sdl", "String", graphql_only: true do |f|
|
267
|
+
f.documentation <<~EOS
|
268
|
+
A field required by the [Apollo Federation subgraph
|
269
|
+
spec](https://www.apollographql.com/docs/federation/subgraph-spec/#required-resolvers-for-introspection):
|
270
|
+
|
271
|
+
> The returned `sdl` string has the following requirements:
|
272
|
+
>
|
273
|
+
> - It must **include** all uses of all federation-specific directives, such as `@key`.
|
274
|
+
> - All of these directives are shown in [Subgraph schema additions](https://www.apollographql.com/docs/federation/subgraph-spec/#subgraph-schema-additions).
|
275
|
+
> - **If supporting Federation 1,** `sdl` must **omit** all automatically added definitions from
|
276
|
+
> [Subgraph schema additions](https://www.apollographql.com/docs/federation/subgraph-spec/#subgraph-schema-additions),
|
277
|
+
> such as `Query._service` and `_Service.sdl`!
|
278
|
+
> - If your library is _only_ supporting Federation 2, `sdl` can include these definitions.
|
279
|
+
|
280
|
+
Not intended for use by clients other than Apollo.
|
281
|
+
EOS
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
entity_types = state.object_types_by_name.values.select do |object_type|
|
286
|
+
object_type.directives.any? do |directive|
|
287
|
+
directive.name == "key" && directive.arguments[:resolvable]
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
validate_entity_types_can_all_be_resolved(entity_types)
|
292
|
+
|
293
|
+
entity_type_names = entity_types
|
294
|
+
# As per the GraphQL spec[1], only object types can be in a union, and interface
|
295
|
+
# types cannot be in a union. The GraphQL gem has validation[2] for this and will raise
|
296
|
+
# an error if we violate it, so we must filter to only object types here.
|
297
|
+
#
|
298
|
+
# [1] https://spec.graphql.org/October2021/#sec-Unions.Type-Validation
|
299
|
+
# [2] https://github.com/rmosolgo/graphql-ruby/pull/3024
|
300
|
+
.grep(ElasticGraph::SchemaDefinition::SchemaElements::ObjectType)
|
301
|
+
.map(&:name)
|
302
|
+
|
303
|
+
unless entity_type_names.empty?
|
304
|
+
apollo_union_type "_Entity" do |t|
|
305
|
+
t.extend EntityTypeExtension
|
306
|
+
t.documentation <<~EOS
|
307
|
+
A union type required by the [Apollo Federation subgraph
|
308
|
+
spec](https://www.apollographql.com/docs/federation/subgraph-spec/#union-_entity):
|
309
|
+
|
310
|
+
> **⚠️ This union type is generated dynamically based on the input subgraph schema!**
|
311
|
+
>
|
312
|
+
> This union's possible types must include all entities that the subgraph defines.
|
313
|
+
> It's the return type of the `Query._entities` field, which the graph router uses
|
314
|
+
> to directly access a subgraph's entity fields.
|
315
|
+
>
|
316
|
+
> For details, see [Defining the `_Entity` union](https://www.apollographql.com/docs/federation/subgraph-spec/#defining-the-_entity-union).
|
317
|
+
|
318
|
+
In an ElasticGraph schema, this is a union of all indexed types.
|
319
|
+
|
320
|
+
Not intended for use by clients other than Apollo.
|
321
|
+
EOS
|
322
|
+
|
323
|
+
t.subtypes(*entity_type_names)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def apollo_object_type(name, &block)
|
329
|
+
object_type name do |type|
|
330
|
+
type.graphql_only true
|
331
|
+
yield type
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def apollo_union_type(name, &block)
|
336
|
+
union_type name do |type|
|
337
|
+
type.graphql_only true
|
338
|
+
yield type
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
def apollo_scalar_type(name, &block)
|
343
|
+
scalar_type name do |type|
|
344
|
+
type.graphql_only true
|
345
|
+
yield type
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def apollo_enum_type(name, &block)
|
350
|
+
enum_type name do |type|
|
351
|
+
type.graphql_only true
|
352
|
+
yield type
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
# state comes from object we extend with this module.
|
357
|
+
# @dynamic state
|
358
|
+
|
359
|
+
def validate_entity_types_can_all_be_resolved(entity_types)
|
360
|
+
entity_types.reject(&:indexed?).each do |object_type|
|
361
|
+
key_field_names = object_type.directives
|
362
|
+
.select { |dir| dir.name == "key" }
|
363
|
+
# https://rubular.com/r/JEuYKzqnyR712A
|
364
|
+
.flat_map { |dir| dir.arguments[:fields].to_s.gsub(/{.*}/, "").split(" ") }
|
365
|
+
.to_set
|
366
|
+
unresolvable_fields = object_type.graphql_fields_by_name.values.reject do |field|
|
367
|
+
key_field_names.include?(field.name) ||
|
368
|
+
field.relationship ||
|
369
|
+
field.directives.any? { |directive| directive.name == "external" }
|
370
|
+
end
|
371
|
+
if unresolvable_fields.any?
|
372
|
+
raise SchemaError, <<~EOS
|
373
|
+
`#{object_type.name}` has fields that ElasticGraph will be unable to resolve when Apollo requests it as an entity:
|
374
|
+
#{unresolvable_fields.map { |field| " * `#{field.name}`" }.join("\n")}
|
375
|
+
On a non-indexed entity type like this, ElasticGraph can only resolve `@key` fields and `relates_to_(one|many)` fields.
|
376
|
+
To fix this, add these fields to the `apollo_key`, redefine them as a relationship, use `field.apollo_external` so Apollo
|
377
|
+
knows how to treat them, or remove them.
|
378
|
+
EOS
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# Copyright 2024 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
|
+
module ElasticGraph
|
10
|
+
module Apollo
|
11
|
+
module SchemaDefinition
|
12
|
+
module ApolloDirectives
|
13
|
+
module Authenticated
|
14
|
+
# Extension method designed to support Apollo's authenticated directive:
|
15
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#authenticated
|
16
|
+
def apollo_authenticated
|
17
|
+
directive "authenticated"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Extends
|
22
|
+
# Extension method designed to support Apollo's extends directive:
|
23
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#extends
|
24
|
+
def apollo_extends
|
25
|
+
directive "extends"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module External
|
30
|
+
# Extension method designed to support Apollo's external directive:
|
31
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#external
|
32
|
+
def apollo_external
|
33
|
+
directive "external"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module Inaccessible
|
38
|
+
# Extension method designed to support Apollo's inaccessible directive:
|
39
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#inaccessible
|
40
|
+
def apollo_inaccessible
|
41
|
+
directive "inaccessible"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module InterfaceObject
|
46
|
+
# Extension method designed to support Apollo's interfaceObject directive:
|
47
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#interfaceObject
|
48
|
+
def apollo_interface_object
|
49
|
+
directive "interfaceObject"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module Key
|
54
|
+
# Extension method designed to support Apollo's key directive:
|
55
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#key
|
56
|
+
def apollo_key(fields:, resolvable: true)
|
57
|
+
directive "key", fields: fields, resolvable: resolvable
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
module Override
|
62
|
+
# Extension method designed to support Apollo's override directive:
|
63
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#override
|
64
|
+
def apollo_override(from:)
|
65
|
+
directive "override", from: from
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module Policy
|
70
|
+
# Extension method designed to support Apollo's policy directive:
|
71
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#policy
|
72
|
+
def apollo_policy(policies:)
|
73
|
+
directive "policy", policies: policies
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module Provides
|
78
|
+
# Extension method designed to support Apollo's provides directive:
|
79
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#provides
|
80
|
+
def apollo_provides(fields:)
|
81
|
+
directive "provides", fields: fields
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
module Requires
|
86
|
+
# Extension method designed to support Apollo's requires directive:
|
87
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#requires
|
88
|
+
def apollo_requires(fields:)
|
89
|
+
directive "requires", fields: fields
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
module RequiresScopes
|
94
|
+
# Extension method designed to support Apollo's requiresScopes directive:
|
95
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#requiresscopes
|
96
|
+
def apollo_requires_scopes(scopes:)
|
97
|
+
directive "requiresScopes", scopes: scopes
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
module Shareable
|
102
|
+
# Extension method designed to support Apollo's shareable directive:
|
103
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#shareable
|
104
|
+
def apollo_shareable
|
105
|
+
directive "shareable"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
module Tag
|
110
|
+
# Extension method designed to support Apollo's tag directive:
|
111
|
+
# https://www.apollographql.com/docs/federation/federated-types/federated-directives/#tag
|
112
|
+
def apollo_tag(name:)
|
113
|
+
directive "tag", name: name
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright 2024 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/apollo/schema_definition/apollo_directives"
|
10
|
+
|
11
|
+
module ElasticGraph
|
12
|
+
module Apollo
|
13
|
+
module SchemaDefinition
|
14
|
+
module ArgumentExtension
|
15
|
+
include ApolloDirectives::Inaccessible
|
16
|
+
include ApolloDirectives::Tag
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright 2024 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
|
+
module ElasticGraph
|
10
|
+
module Apollo
|
11
|
+
module SchemaDefinition
|
12
|
+
# The Apollo `_Entity` type is a type union of _all_ entity subtypes in an ElasticGraph schema.
|
13
|
+
# However, unlike a normal union type:
|
14
|
+
#
|
15
|
+
# - `_Entity` is never an indexed type, and should not be treated as one (even though its subtypes are all indexed, which would
|
16
|
+
# usually cause it to be treated as indexed!).
|
17
|
+
# - A merged set of `graphql_fields_by_name` cannot be safely computed. That method raises errors if a field with the same name
|
18
|
+
# has conflicting definitions on different subtypes, but we must allow that on `_Entity` subtypes.
|
19
|
+
module EntityTypeExtension
|
20
|
+
def graphql_fields_by_name
|
21
|
+
{}
|
22
|
+
end
|
23
|
+
|
24
|
+
def indexed?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Copyright 2024 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/apollo/schema_definition/apollo_directives"
|
10
|
+
|
11
|
+
module ElasticGraph
|
12
|
+
module Apollo
|
13
|
+
module SchemaDefinition
|
14
|
+
module EnumTypeExtension
|
15
|
+
include ApolloDirectives::Authenticated
|
16
|
+
include ApolloDirectives::Inaccessible
|
17
|
+
include ApolloDirectives::Policy
|
18
|
+
include ApolloDirectives::RequiresScopes
|
19
|
+
include ApolloDirectives::Tag
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright 2024 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/apollo/schema_definition/apollo_directives"
|
10
|
+
|
11
|
+
module ElasticGraph
|
12
|
+
module Apollo
|
13
|
+
module SchemaDefinition
|
14
|
+
module EnumValueExtension
|
15
|
+
include ApolloDirectives::Inaccessible
|
16
|
+
include ApolloDirectives::Tag
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|