elasticgraph-apollo 0.19.3.0 → 1.0.0.rc1
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 +4 -4
- data/apollo_tests_implementation/config/products_schema.rb +2 -2
- data/apollo_tests_implementation/lib/product_resolver.rb +1 -1
- data/lib/elastic_graph/apollo/graphql/entities_field_resolver.rb +2 -2
- data/lib/elastic_graph/apollo/schema_definition/api_extension.rb +4 -10
- data/lib/elastic_graph/apollo/schema_definition/interface_type_extension.rb +0 -2
- data/lib/elastic_graph/apollo/schema_definition/object_type_extension.rb +0 -2
- metadata +23 -25
- data/lib/elastic_graph/apollo/graphql/apollo_entity_ref_resolver.rb +0 -72
- data/lib/elastic_graph/apollo/schema_definition/object_and_interface_extension.rb +0 -218
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60fe05fd8a1f0f1419414ab12d49ce2c6f83d3d51a65395a1c337daaf9686504
|
4
|
+
data.tar.gz: b69ab2f7e0a55ded216b2f21985cd5a61c0f85f98fda8d821618b493abc7a071
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '07948b4764320e60d8b006b1191336f85cc8691849e7c8a9b208d4c347eeab1b5c626fc82d1be85a712742c6c1b471ed40b72e3d8f8d8be1593859f6d1cc4778'
|
7
|
+
data.tar.gz: ab665204ae619f74c6f19e2da52094cc1f06fc1c484b74f5286d1a554a765f3c9250eea0f911c1e30d792fc8ad3a4aedb919d699b52e20537400a183a20105d8
|
@@ -48,14 +48,14 @@ module ApolloTestImpl
|
|
48
48
|
schema.on_root_query_type do |type|
|
49
49
|
type.field "product", "Product" do |f|
|
50
50
|
f.argument "id", "ID!"
|
51
|
-
f.
|
51
|
+
f.resolver = :product
|
52
52
|
end
|
53
53
|
|
54
54
|
type.field "deprecatedProduct", "DeprecatedProduct" do |f|
|
55
55
|
f.argument "sku", "String!"
|
56
56
|
f.argument "package", "String!"
|
57
57
|
f.directive "deprecated", reason: "Use product query instead"
|
58
|
-
f.
|
58
|
+
f.resolver = :product
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -24,7 +24,7 @@ class ProductResolver
|
|
24
24
|
query = @datastore_query_builder.new_query(
|
25
25
|
search_index_definitions: [@product_index_def],
|
26
26
|
monotonic_clock_deadline: context[:monotonic_clock_deadline],
|
27
|
-
|
27
|
+
client_filters: [{"id" => {"equalToAnyOf" => [args.fetch("id")]}}],
|
28
28
|
individual_docs_needed: true,
|
29
29
|
request_all_fields: true
|
30
30
|
)
|
@@ -166,7 +166,7 @@ module ElasticGraph
|
|
166
166
|
query.merge_with(
|
167
167
|
document_pagination: {first: representations.length},
|
168
168
|
requested_fields: additional_requested_fields_for(representations),
|
169
|
-
|
169
|
+
internal_filters: [filter]
|
170
170
|
)
|
171
171
|
end
|
172
172
|
|
@@ -242,7 +242,7 @@ module ElasticGraph
|
|
242
242
|
# In the case of representations which don't query Id, we ask for 2 documents so that
|
243
243
|
# if something weird is going on and it matches more than 1, we can detect that and return an error.
|
244
244
|
document_pagination: {first: 2},
|
245
|
-
|
245
|
+
internal_filters: [build_filter_for_hash(fields)]
|
246
246
|
)
|
247
247
|
end
|
248
248
|
|
@@ -8,6 +8,7 @@
|
|
8
8
|
|
9
9
|
require "elastic_graph/errors"
|
10
10
|
require "elastic_graph/version"
|
11
|
+
require "elastic_graph/apollo/graphql/engine_extension"
|
11
12
|
require "elastic_graph/apollo/schema_definition/entity_type_extension"
|
12
13
|
require "elastic_graph/apollo/schema_definition/factory_extension"
|
13
14
|
require "elastic_graph/apollo/schema_definition/state_extension"
|
@@ -124,6 +125,7 @@ module ElasticGraph
|
|
124
125
|
end
|
125
126
|
end
|
126
127
|
|
128
|
+
api.register_graphql_extension GraphQL::EngineExtension, defined_at: "elastic_graph/apollo/graphql/engine_extension"
|
127
129
|
api.state.after_user_definition_complete do
|
128
130
|
api.send(:define_apollo_schema_elements)
|
129
131
|
end
|
@@ -378,19 +380,11 @@ module ElasticGraph
|
|
378
380
|
end
|
379
381
|
end
|
380
382
|
|
381
|
-
require(require_path = "elastic_graph/apollo/graphql/engine_extension")
|
382
|
-
register_graphql_extension GraphQL::EngineExtension, defined_at: require_path
|
383
|
-
|
384
383
|
require(require_path = "elastic_graph/apollo/graphql/entities_field_resolver")
|
385
384
|
register_graphql_resolver :apollo_entities, GraphQL::EntitiesFieldResolver, defined_at: require_path
|
386
385
|
|
387
386
|
require(require_path = "elastic_graph/apollo/graphql/service_field_resolver")
|
388
387
|
register_graphql_resolver :apollo_service, GraphQL::ServiceFieldResolver, defined_at: require_path
|
389
|
-
|
390
|
-
require(require_path = "elastic_graph/apollo/graphql/apollo_entity_ref_resolver")
|
391
|
-
register_graphql_resolver :apollo_entity_ref, GraphQL::ApolloEntityRefResolver::ForSingleId, defined_at: require_path
|
392
|
-
register_graphql_resolver :apollo_entity_ref_list, GraphQL::ApolloEntityRefResolver::ForIdList, defined_at: require_path
|
393
|
-
register_graphql_resolver :apollo_entity_ref_paginated, GraphQL::ApolloEntityRefResolver::ForPaginatedList, defined_at: require_path
|
394
388
|
end
|
395
389
|
|
396
390
|
def apollo_object_type(name, &block)
|
@@ -493,7 +487,7 @@ module ElasticGraph
|
|
493
487
|
EOS
|
494
488
|
end
|
495
489
|
|
496
|
-
f.
|
490
|
+
f.resolver = :apollo_entities
|
497
491
|
end
|
498
492
|
end
|
499
493
|
|
@@ -509,7 +503,7 @@ module ElasticGraph
|
|
509
503
|
Not intended for use by clients other than Apollo.
|
510
504
|
EOS
|
511
505
|
|
512
|
-
f.
|
506
|
+
f.resolver = :apollo_service
|
513
507
|
end
|
514
508
|
end
|
515
509
|
end
|
@@ -7,7 +7,6 @@
|
|
7
7
|
# frozen_string_literal: true
|
8
8
|
|
9
9
|
require "elastic_graph/apollo/schema_definition/apollo_directives"
|
10
|
-
require "elastic_graph/apollo/schema_definition/object_and_interface_extension"
|
11
10
|
|
12
11
|
module ElasticGraph
|
13
12
|
module Apollo
|
@@ -21,7 +20,6 @@ module ElasticGraph
|
|
21
20
|
include ApolloDirectives::Policy
|
22
21
|
include ApolloDirectives::RequiresScopes
|
23
22
|
include ApolloDirectives::Tag
|
24
|
-
include ObjectAndInterfaceExtension
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
@@ -7,7 +7,6 @@
|
|
7
7
|
# frozen_string_literal: true
|
8
8
|
|
9
9
|
require "elastic_graph/apollo/schema_definition/apollo_directives"
|
10
|
-
require "elastic_graph/apollo/schema_definition/object_and_interface_extension"
|
11
10
|
|
12
11
|
module ElasticGraph
|
13
12
|
module Apollo
|
@@ -24,7 +23,6 @@ module ElasticGraph
|
|
24
23
|
include ApolloDirectives::RequiresScopes
|
25
24
|
include ApolloDirectives::Shareable
|
26
25
|
include ApolloDirectives::Tag
|
27
|
-
include ObjectAndInterfaceExtension
|
28
26
|
end
|
29
27
|
end
|
30
28
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elasticgraph-apollo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Myron Marston
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
- Block Engineering
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: elasticgraph-graphql
|
@@ -17,42 +17,42 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - '='
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: 0.
|
20
|
+
version: 1.0.0.rc1
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - '='
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 0.
|
27
|
+
version: 1.0.0.rc1
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: elasticgraph-support
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
32
|
- - '='
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 0.
|
34
|
+
version: 1.0.0.rc1
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - '='
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 0.
|
41
|
+
version: 1.0.0.rc1
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: graphql
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
46
|
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: 2.5.
|
48
|
+
version: 2.5.6
|
49
49
|
type: :runtime
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: 2.5.
|
55
|
+
version: 2.5.6
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: apollo-federation
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -79,70 +79,70 @@ dependencies:
|
|
79
79
|
requirements:
|
80
80
|
- - '='
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.
|
82
|
+
version: 1.0.0.rc1
|
83
83
|
type: :development
|
84
84
|
prerelease: false
|
85
85
|
version_requirements: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - '='
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 0.
|
89
|
+
version: 1.0.0.rc1
|
90
90
|
- !ruby/object:Gem::Dependency
|
91
91
|
name: elasticgraph-admin
|
92
92
|
requirement: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - '='
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 0.
|
96
|
+
version: 1.0.0.rc1
|
97
97
|
type: :development
|
98
98
|
prerelease: false
|
99
99
|
version_requirements: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - '='
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0.
|
103
|
+
version: 1.0.0.rc1
|
104
104
|
- !ruby/object:Gem::Dependency
|
105
105
|
name: elasticgraph-elasticsearch
|
106
106
|
requirement: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - '='
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.
|
110
|
+
version: 1.0.0.rc1
|
111
111
|
type: :development
|
112
112
|
prerelease: false
|
113
113
|
version_requirements: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - '='
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.
|
117
|
+
version: 1.0.0.rc1
|
118
118
|
- !ruby/object:Gem::Dependency
|
119
119
|
name: elasticgraph-opensearch
|
120
120
|
requirement: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - '='
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.
|
124
|
+
version: 1.0.0.rc1
|
125
125
|
type: :development
|
126
126
|
prerelease: false
|
127
127
|
version_requirements: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - '='
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 0.
|
131
|
+
version: 1.0.0.rc1
|
132
132
|
- !ruby/object:Gem::Dependency
|
133
133
|
name: elasticgraph-indexer
|
134
134
|
requirement: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - '='
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 0.
|
138
|
+
version: 1.0.0.rc1
|
139
139
|
type: :development
|
140
140
|
prerelease: false
|
141
141
|
version_requirements: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - '='
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 0.
|
145
|
+
version: 1.0.0.rc1
|
146
146
|
email:
|
147
147
|
- myron@squareup.com
|
148
148
|
executables: []
|
@@ -160,7 +160,6 @@ files:
|
|
160
160
|
- apollo_tests_implementation/docker-compose.yaml
|
161
161
|
- apollo_tests_implementation/lib/product_resolver.rb
|
162
162
|
- apollo_tests_implementation/wait_for_datastore.sh
|
163
|
-
- lib/elastic_graph/apollo/graphql/apollo_entity_ref_resolver.rb
|
164
163
|
- lib/elastic_graph/apollo/graphql/engine_extension.rb
|
165
164
|
- lib/elastic_graph/apollo/graphql/entities_field_resolver.rb
|
166
165
|
- lib/elastic_graph/apollo/graphql/http_endpoint_extension.rb
|
@@ -175,7 +174,6 @@ files:
|
|
175
174
|
- lib/elastic_graph/apollo/schema_definition/field_extension.rb
|
176
175
|
- lib/elastic_graph/apollo/schema_definition/input_type_extension.rb
|
177
176
|
- lib/elastic_graph/apollo/schema_definition/interface_type_extension.rb
|
178
|
-
- lib/elastic_graph/apollo/schema_definition/object_and_interface_extension.rb
|
179
177
|
- lib/elastic_graph/apollo/schema_definition/object_type_extension.rb
|
180
178
|
- lib/elastic_graph/apollo/schema_definition/scalar_type_extension.rb
|
181
179
|
- lib/elastic_graph/apollo/schema_definition/state_extension.rb
|
@@ -188,10 +186,10 @@ licenses:
|
|
188
186
|
- MIT
|
189
187
|
metadata:
|
190
188
|
bug_tracker_uri: https://github.com/block/elasticgraph/issues
|
191
|
-
changelog_uri: https://github.com/block/elasticgraph/releases/tag/
|
192
|
-
documentation_uri: https://block.github.io/elasticgraph/api-docs/
|
189
|
+
changelog_uri: https://github.com/block/elasticgraph/releases/tag/v1.0.0.rc1
|
190
|
+
documentation_uri: https://block.github.io/elasticgraph/api-docs/v1.0.0.rc1/
|
193
191
|
homepage_uri: https://block.github.io/elasticgraph/
|
194
|
-
source_code_uri: https://github.com/block/elasticgraph/tree/
|
192
|
+
source_code_uri: https://github.com/block/elasticgraph/tree/v1.0.0.rc1/elasticgraph-apollo
|
195
193
|
gem_category: extension
|
196
194
|
rdoc_options: []
|
197
195
|
require_paths:
|
@@ -200,7 +198,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
200
198
|
requirements:
|
201
199
|
- - ">="
|
202
200
|
- !ruby/object:Gem::Version
|
203
|
-
version: '3.
|
201
|
+
version: '3.4'
|
204
202
|
- - "<"
|
205
203
|
- !ruby/object:Gem::Version
|
206
204
|
version: '3.5'
|
@@ -210,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
210
208
|
- !ruby/object:Gem::Version
|
211
209
|
version: '0'
|
212
210
|
requirements: []
|
213
|
-
rubygems_version: 3.6.
|
211
|
+
rubygems_version: 3.6.7
|
214
212
|
specification_version: 4
|
215
213
|
summary: An ElasticGraph extension that implements the Apollo federation spec.
|
216
214
|
test_files: []
|
@@ -1,72 +0,0 @@
|
|
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/graphql/resolvers/relay_connection/array_adapter"
|
10
|
-
|
11
|
-
module ElasticGraph
|
12
|
-
module Apollo
|
13
|
-
module GraphQL
|
14
|
-
# Namespace for resolvers which provide Apollo entity references from ids.
|
15
|
-
#
|
16
|
-
# @private
|
17
|
-
module ApolloEntityRefResolver
|
18
|
-
# GraphQL resolver for fields defined with `apollo_entity_ref_field` that are backed by a single id.
|
19
|
-
#
|
20
|
-
# @private
|
21
|
-
class ForSingleId
|
22
|
-
def initialize(elasticgraph_graphql:, config:)
|
23
|
-
@source_id_field = config.fetch(:source_id_field)
|
24
|
-
@exposed_id_field = config.fetch(:exposed_id_field)
|
25
|
-
end
|
26
|
-
|
27
|
-
def resolve(field:, object:, args:, context:)
|
28
|
-
if (id = object.fetch(@source_id_field))
|
29
|
-
{@exposed_id_field => id}
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# GraphQL resolver for fields defined with `apollo_entity_ref_field` that are backed by an list of ids.
|
35
|
-
#
|
36
|
-
# @private
|
37
|
-
class ForIdList
|
38
|
-
def initialize(elasticgraph_graphql:, config:)
|
39
|
-
@source_ids_field = config.fetch(:source_ids_field)
|
40
|
-
@exposed_id_field = config.fetch(:exposed_id_field)
|
41
|
-
end
|
42
|
-
|
43
|
-
def resolve(field:, object:, args:, context:)
|
44
|
-
object
|
45
|
-
.fetch(@source_ids_field)
|
46
|
-
.map { |id| {@exposed_id_field => id} }
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# GraphQL resolver for paginated fields defined with `apollo_entity_ref_paginated_collection_field`.
|
51
|
-
#
|
52
|
-
# @private
|
53
|
-
class ForPaginatedList
|
54
|
-
def initialize(elasticgraph_graphql:, config:)
|
55
|
-
@for_id_list = ForIdList.new(elasticgraph_graphql:, config:)
|
56
|
-
end
|
57
|
-
|
58
|
-
def resolve(field:, object:, args:, context:)
|
59
|
-
array = @for_id_list.resolve(field:, object:, args:, context:)
|
60
|
-
|
61
|
-
::ElasticGraph::GraphQL::Resolvers::RelayConnection::ArrayAdapter.build(
|
62
|
-
array,
|
63
|
-
args,
|
64
|
-
context.fetch(:elastic_graph_schema).element_names,
|
65
|
-
context
|
66
|
-
)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,218 +0,0 @@
|
|
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/apollo/schema_definition/apollo_directives"
|
10
|
-
|
11
|
-
module ElasticGraph
|
12
|
-
module Apollo
|
13
|
-
module SchemaDefinition
|
14
|
-
# Extends {ElasticGraph::SchemaDefinition::SchemaElements::ObjectType} and
|
15
|
-
# {ElasticGraph::SchemaDefinition::SchemaElements::InterfaceType} to offer some Apollo-specific APIs.
|
16
|
-
module ObjectAndInterfaceExtension
|
17
|
-
# Exposes an Apollo entity reference as a new field, backed by an `ID` field.
|
18
|
-
#
|
19
|
-
# When integrating an ElasticGraph project as a subgraph into a larger Apollo supergraph, it's useful to be able
|
20
|
-
# to reference entities owned by other subgraphs. The most straightforward way to do this is to define an
|
21
|
-
# _entity reference_ type (e.g. a type containing just the `@key` fields such as `id: ID` and marked as
|
22
|
-
# `resolvable: false` in the `@key` directive), and then define fields using that type. This approach works
|
23
|
-
# particularly well when you plan ahead and know which `ID` fields to model with entity reference types.
|
24
|
-
#
|
25
|
-
# However, on an existing schema where you've got some raw `ID` fields of external entities, it can be quite
|
26
|
-
# difficult to replace the `ID` fields with full-blown entity reference types, as doing so would require migrating
|
27
|
-
# clients and running a full backfill.
|
28
|
-
#
|
29
|
-
# This API provides an alternate solution for this situation: it defines a GraphQL-only field which returns an entity
|
30
|
-
# reference type using a custom GraphQL resolver.
|
31
|
-
#
|
32
|
-
# See the [Apollo docs on referencing an entity without contributing
|
33
|
-
# fields](https://www.apollographql.com/docs/graphos/schema-design/federated-schemas/entities/contribute-fields#referencing-an-entity-without-contributing-fields)
|
34
|
-
# for more information.
|
35
|
-
#
|
36
|
-
# @param name [String] Name of the field
|
37
|
-
# @param type [String] Name of the entity reference type (which must be defined separately)
|
38
|
-
# @param id_field_name_in_index [String] Name of the backing ID field in the datastore index
|
39
|
-
# @return [void]
|
40
|
-
# @note This can be used for either a singleton or list reference, based on if `type` is a list.
|
41
|
-
# @note The resulting field will be only be available for clients to request as a return field. It will not support filtering,
|
42
|
-
# sorting, grouping, aggregated values, or highlights.
|
43
|
-
# @see #apollo_entity_ref_paginated_collection_field
|
44
|
-
#
|
45
|
-
# @example Expose `Review.product` and `Review.comments` entity reference fields
|
46
|
-
# ElasticGraph.define_schema do |schema|
|
47
|
-
# schema.object_type "Product" do |t|
|
48
|
-
# t.field "id", "ID"
|
49
|
-
# t.apollo_key fields: "id", resolvable: false
|
50
|
-
# end
|
51
|
-
#
|
52
|
-
# schema.object_type "Comment" do |t|
|
53
|
-
# t.field "id", "ID"
|
54
|
-
# t.apollo_key fields: "id", resolvable: false
|
55
|
-
# end
|
56
|
-
#
|
57
|
-
# schema.object_type "Review" do |t|
|
58
|
-
# t.field "id", "ID"
|
59
|
-
# t.field "score", "Int"
|
60
|
-
#
|
61
|
-
# # Fields originally defined in the first version of the schema
|
62
|
-
# t.field "productId", "ID"
|
63
|
-
# t.field "commentIds", "[ID!]!"
|
64
|
-
#
|
65
|
-
# # New field we're adding to expose the existing `productId` field as a `Product` entity reference.
|
66
|
-
# t.apollo_entity_ref_field "product", "Product", id_field_name_in_index: "productId"
|
67
|
-
#
|
68
|
-
# # New field we're adding to expose the existing `commentIds` field as a list of `Comment` entity references.
|
69
|
-
# t.apollo_entity_ref_field "comments", "[Comment!]!", id_field_name_in_index: "commentIds"
|
70
|
-
#
|
71
|
-
# t.index "reviews"
|
72
|
-
# end
|
73
|
-
# end
|
74
|
-
def apollo_entity_ref_field(name, type, id_field_name_in_index:)
|
75
|
-
field(
|
76
|
-
name,
|
77
|
-
type,
|
78
|
-
name_in_index: id_field_name_in_index,
|
79
|
-
**LIMITED_GRAPHQL_ONLY_FIELD_OPTIONS
|
80
|
-
) do |f|
|
81
|
-
validate_entity_ref_options(__method__.to_s, f, id_field_name_in_index, type) do |exposed_id_field|
|
82
|
-
if f.type.list?
|
83
|
-
f.resolve_with :apollo_entity_ref_list, source_ids_field: id_field_name_in_index, exposed_id_field: exposed_id_field
|
84
|
-
else
|
85
|
-
f.resolve_with :apollo_entity_ref, source_id_field: id_field_name_in_index, exposed_id_field: exposed_id_field
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
yield f if block_given?
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Exposes a collection of Apollo entity references as a new paginated field, backed by an `ID` field.
|
94
|
-
#
|
95
|
-
# When integrating an ElasticGraph project as a subgraph into a larger Apollo supergraph, it's useful to be able
|
96
|
-
# to reference entities owned by other subgraphs. The most straightforward way to do this is to define an
|
97
|
-
# _entity reference_ type (e.g. a type containing just the `@key` fields such as `id: ID` and marked as
|
98
|
-
# `resolvable: false` in the `@key` directive), and then define fields using that type. This approach works
|
99
|
-
# particularly well when you plan ahead and know which `ID` fields to model with entity reference types.
|
100
|
-
#
|
101
|
-
# However, on an existing schema where you've got some raw `ID` fields of external entities, it can be quite
|
102
|
-
# difficult to replace the `ID` fields with full-blown entity reference types, as doing so would require migrating
|
103
|
-
# clients and running a full backfill.
|
104
|
-
#
|
105
|
-
# This API provides an alternate solution for this situation: it defines a GraphQL-only field which returns an entity
|
106
|
-
# reference type using a custom GraphQL resolver. In contrast to {#apollo_entity_ref_field}, this defines a field as
|
107
|
-
# a [paginated Relay connection](https://relay.dev/graphql/connections.htm) rather than a simple list.
|
108
|
-
#
|
109
|
-
# See the [Apollo docs on referencing an entity without contributing
|
110
|
-
# fields](https://www.apollographql.com/docs/graphos/schema-design/federated-schemas/entities/contribute-fields#referencing-an-entity-without-contributing-fields)
|
111
|
-
# for more information.
|
112
|
-
#
|
113
|
-
# @param name [String] Name of the field
|
114
|
-
# @param element_type [String] Name of the entity reference type (which must be defined separately)
|
115
|
-
# @param id_field_name_in_index [String] Name of the backing ID field in the datastore index
|
116
|
-
# @return [void]
|
117
|
-
# @note This requires `id_field_name_in_index` to be a list or paginated collection field.
|
118
|
-
# @note The resulting field will be only be available for clients to request as a return field. It will not support filtering,
|
119
|
-
# sorting, grouping, aggregated values, or highlights.
|
120
|
-
# @see #apollo_entity_ref_field
|
121
|
-
# @see ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields#paginated_collection_field
|
122
|
-
#
|
123
|
-
# @example Expose `Review.product` and `Review.comments` entity reference fields
|
124
|
-
# ElasticGraph.define_schema do |schema|
|
125
|
-
# schema.object_type "Comment" do |t|
|
126
|
-
# t.field "id", "ID"
|
127
|
-
# t.apollo_key fields: "id", resolvable: false
|
128
|
-
# end
|
129
|
-
#
|
130
|
-
# schema.object_type "Review" do |t|
|
131
|
-
# t.field "id", "ID"
|
132
|
-
# t.field "score", "Int"
|
133
|
-
#
|
134
|
-
# # Field originally defined in the first version of the schema
|
135
|
-
# t.field "commentIds", "[ID!]!"
|
136
|
-
#
|
137
|
-
# # New field we're adding to expose the existing `commentIds` field as a list of `Comment` entity references.
|
138
|
-
# t.apollo_entity_ref_paginated_collection_field "comments", "Comment", id_field_name_in_index: "commentIds"
|
139
|
-
#
|
140
|
-
# t.index "reviews"
|
141
|
-
# end
|
142
|
-
# end
|
143
|
-
def apollo_entity_ref_paginated_collection_field(name, element_type, id_field_name_in_index:)
|
144
|
-
paginated_collection_field(
|
145
|
-
name,
|
146
|
-
element_type,
|
147
|
-
name_in_index: id_field_name_in_index,
|
148
|
-
**LIMITED_GRAPHQL_ONLY_PAGINATED_FIELD_OPTIONS
|
149
|
-
) do |f|
|
150
|
-
validate_entity_ref_options(__method__.to_s, f, id_field_name_in_index, element_type) do |exposed_id_field|
|
151
|
-
backing_indexing_field = f.backing_indexing_field # : ::ElasticGraph::SchemaDefinition::SchemaElements::Field
|
152
|
-
unless backing_indexing_field.type.list?
|
153
|
-
raise Errors::SchemaError, "`#{f.parent_type.name}.#{f.name}` is invalid: `id_field_name_in_index` must reference an " \
|
154
|
-
"id collection field, but the type of `#{id_field_name_in_index}` is `#{backing_indexing_field.type.name}`."
|
155
|
-
end
|
156
|
-
|
157
|
-
f.resolve_with :apollo_entity_ref_paginated, source_ids_field: id_field_name_in_index, exposed_id_field: exposed_id_field
|
158
|
-
|
159
|
-
yield f if block_given?
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
private
|
165
|
-
|
166
|
-
# The set of options for a GraphQL-only field that has all abilities disabled. A field defined with these options
|
167
|
-
# is available to be returned, but cannot be used for anything else (filtering, grouping, sorting, etc.).
|
168
|
-
LIMITED_GRAPHQL_ONLY_FIELD_OPTIONS = {
|
169
|
-
graphql_only: true,
|
170
|
-
filterable: false,
|
171
|
-
groupable: false,
|
172
|
-
aggregatable: false,
|
173
|
-
sortable: false
|
174
|
-
}
|
175
|
-
|
176
|
-
# Like {LIMITED_GRAPHQL_ONLY_FIELD_OPTIONS} but for
|
177
|
-
# {ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields#paginated_collection_field}.
|
178
|
-
# It does not support the `sortable` option.
|
179
|
-
LIMITED_GRAPHQL_ONLY_PAGINATED_FIELD_OPTIONS = LIMITED_GRAPHQL_ONLY_FIELD_OPTIONS.except(:sortable)
|
180
|
-
|
181
|
-
def validate_entity_ref_options(method_name, field, id_field_name_in_index, entity_ref_type_name)
|
182
|
-
# Defer validation since it depends on the definition of the entity ref type, which may be as yet undefined.
|
183
|
-
schema_def_state.after_user_definition_complete do
|
184
|
-
backing_indexing_field = field.backing_indexing_field # : ::ElasticGraph::SchemaDefinition::SchemaElements::Field
|
185
|
-
backing_indexing_field_type = backing_indexing_field.type.fully_unwrapped.name
|
186
|
-
|
187
|
-
unless backing_indexing_field_type == "ID"
|
188
|
-
raise Errors::SchemaError, "`#{field.parent_type.name}.#{field.name}` is invalid: `id_field_name_in_index` must " \
|
189
|
-
"reference an `ID` field, but the type of `#{id_field_name_in_index}` is `#{backing_indexing_field_type}`."
|
190
|
-
end
|
191
|
-
|
192
|
-
entity_ref_type = schema_def_state.type_ref(entity_ref_type_name).fully_unwrapped.as_object_type
|
193
|
-
unless entity_ref_type
|
194
|
-
raise Errors::SchemaError, "`#{field.parent_type.name}.#{field.name}` is invalid: the referenced type " \
|
195
|
-
"(`#{entity_ref_type_name}`) is not an object type as required by `#{method_name}`."
|
196
|
-
end
|
197
|
-
|
198
|
-
entity_ref_type_fields = entity_ref_type.graphql_fields_by_name.keys
|
199
|
-
|
200
|
-
unless entity_ref_type_fields.size == 1
|
201
|
-
raise Errors::SchemaError, "`#{field.parent_type.name}.#{field.name}` is invalid: `#{method_name}` can only be used " \
|
202
|
-
"for types with a single field, but `#{entity_ref_type.name}` has #{entity_ref_type_fields.size} fields."
|
203
|
-
end
|
204
|
-
|
205
|
-
exposed_id_field = entity_ref_type_fields.first
|
206
|
-
exposed_id_field_type = entity_ref_type.graphql_fields_by_name.fetch(exposed_id_field).type
|
207
|
-
unless exposed_id_field_type.unwrap_non_null.name == "ID"
|
208
|
-
raise Errors::SchemaError, "`#{field.parent_type.name}.#{field.name}` is invalid: `#{method_name}` can only be used for " \
|
209
|
-
"types with a single `ID` field, but the type of `#{entity_ref_type.name}.#{exposed_id_field}` is `#{exposed_id_field_type.name}`."
|
210
|
-
end
|
211
|
-
|
212
|
-
yield exposed_id_field
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|