apollo-federation 3.10.3 → 3.10.5
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/CHANGELOG.md +17 -0
- data/lib/apollo-federation/entities_field.rb +79 -56
- data/lib/apollo-federation/next_execution_support.rb +18 -0
- data/lib/apollo-federation/service.rb +2 -1
- data/lib/apollo-federation/service_field.rb +10 -3
- data/lib/apollo-federation/version.rb +1 -1
- metadata +4 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0b6e50afd09ae68365aa079f13a4e53ad681628d8a537166985d4da3eb6ef6ce
|
|
4
|
+
data.tar.gz: 8af107ff7dd73927fd241ad852916924ffe131db58da81facb37c8f75c88c95d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 742d3beea298bcac5bad03cd49181f587735d1a42e08d4fd1fb31b2ddcb5d948c30be2c6cbd24d453d8922e5992d9a225f314fb96ad6c5260369a86d84adb5ac
|
|
7
|
+
data.tar.gz: bc802e2a591d2c902c972f566362904b156054af8afe1800c1b861c1d2d062fbe552940f69d6814950c481fe06a839ed0e787c8edc49867dab90c1b288a0b28f
|
data/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,23 @@
|
|
|
10
10
|
|
|
11
11
|
* Revert "chore(release): 3.10.2 [skip ci]" (#309) ([a3937c6](https://github.com/Gusto/apollo-federation-ruby/commit/a3937c64f0ce9648edc10f74a80a4e825e01b4d4)), closes [#309](https://github.com/Gusto/apollo-federation-ruby/issues/309)
|
|
12
12
|
|
|
13
|
+
## [3.10.5](https://github.com/Gusto/apollo-federation-ruby/compare/v3.10.4...v3.10.5) (2026-10-01)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* add environment: release to the Publish Gem job ([#323](https://github.com/Gusto/apollo-federation-ruby/issues/323)) ([abbe9c6](https://github.com/Gusto/apollo-federation-ruby/commit/abbe9c652bf4fcfd5a23c238981a91bc5ad47da1))
|
|
19
|
+
|
|
20
|
+
## [3.10.4](https://github.com/Gusto/apollo-federation-ruby/compare/v3.10.3...v3.10.4) (2026-09-30)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* authenticate release-please-action with a GitHub App token, not GITHUB_TOKEN ([#320](https://github.com/Gusto/apollo-federation-ruby/issues/320)) ([0231a15](https://github.com/Gusto/apollo-federation-ruby/commit/0231a1573253739573fa2a8b17aeb9a124e73728))
|
|
26
|
+
* Query._entities crashing under GraphQL::Execution::Next ([#317](https://github.com/Gusto/apollo-federation-ruby/issues/317)) ([4b869ba](https://github.com/Gusto/apollo-federation-ruby/commit/4b869ba7b4e5377cef0a08c8967386f38b6b7b97))
|
|
27
|
+
* regenerate Gemfile.lock on the release PR after version bumps ([#322](https://github.com/Gusto/apollo-federation-ruby/issues/322)) ([c6122dc](https://github.com/Gusto/apollo-federation-ruby/commit/c6122dcccb8d246642bc799f5b4e7fb8b749b84c))
|
|
28
|
+
* restore environment: release on the release-please job ([#321](https://github.com/Gusto/apollo-federation-ruby/issues/321)) ([61904d8](https://github.com/Gusto/apollo-federation-ruby/commit/61904d86023f14f6fbd661417e60ecc7ce166ec4))
|
|
29
|
+
|
|
13
30
|
## [3.10.1](https://github.com/Gusto/apollo-federation-ruby/compare/v3.10.0...v3.10.1) (2025-04-02)
|
|
14
31
|
|
|
15
32
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'graphql'
|
|
4
4
|
require 'apollo-federation/any'
|
|
5
|
+
require 'apollo-federation/next_execution_support'
|
|
5
6
|
|
|
6
7
|
module ApolloFederation
|
|
7
8
|
module EntitiesField
|
|
@@ -20,80 +21,102 @@ module ApolloFederation
|
|
|
20
21
|
possible_types(*possible_entities)
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
# resolve_static so Next dispatches to resolve_entities_for_next, not root_value; a
|
|
25
|
+
# separate method from _entities since Next needs a fully-synced Array, not a Lazy.
|
|
26
|
+
if ApolloFederation::RESOLVE_STATIC_SUPPORTED
|
|
27
|
+
entities_field_options = { resolve_static: :resolve_entities_for_next }
|
|
28
|
+
else
|
|
29
|
+
entities_field_options = {}
|
|
30
|
+
end
|
|
31
|
+
field(:_entities, [entity_type, null: true], null: false, **entities_field_options) do
|
|
24
32
|
argument :representations, [Any], required: true
|
|
25
33
|
end
|
|
26
34
|
end
|
|
27
|
-
end
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
representations
|
|
33
|
-
.map
|
|
34
|
-
.with_index { |r, i| [r, i] }
|
|
35
|
-
.group_by { |(r, _i)| r[:__typename] }
|
|
36
|
-
|
|
37
|
-
maybe_lazies = grouped_references_with_indices.map do |typename, references_with_indices|
|
|
38
|
-
references = references_with_indices.map(&:first)
|
|
39
|
-
indices = references_with_indices.map(&:last)
|
|
40
|
-
|
|
41
|
-
# TODO: Use warden or schema?
|
|
42
|
-
type = context.warden.get_type(typename)
|
|
43
|
-
if type.nil? || type.kind != GraphQL::TypeKinds::OBJECT
|
|
44
|
-
# TODO: Raise a specific error class?
|
|
45
|
-
raise "The _entities resolver tried to load an entity for type \"#{typename}\"," \
|
|
46
|
-
' but no object type of that name was found in the schema'
|
|
47
|
-
end
|
|
36
|
+
def _entities(context, representations:)
|
|
37
|
+
build_entities(context, representations)
|
|
38
|
+
end
|
|
48
39
|
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
def resolve_entities_for_next(context, representations:)
|
|
41
|
+
final_result = build_entities(context, representations).value
|
|
42
|
+
# Resolving the outer Lazy doesn't resolve each entry: a per-reference resolve_reference
|
|
43
|
+
# lazy value comes back wrapped in its own Lazy from the after_lazy call in build_entities.
|
|
44
|
+
final_result.map { |entry| entry.is_a?(GraphQL::Execution::Lazy) ? entry.value : entry }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def build_entities(context, representations)
|
|
50
|
+
final_result = Array.new(representations.size)
|
|
51
|
+
grouped_references_with_indices =
|
|
52
|
+
representations
|
|
53
|
+
.map
|
|
54
|
+
.with_index { |r, i| [r, i] }
|
|
55
|
+
.group_by { |(r, _i)| r[:__typename] }
|
|
56
|
+
|
|
57
|
+
maybe_lazies = grouped_references_with_indices.map do |typename, references_with_indices|
|
|
58
|
+
references = references_with_indices.map(&:first)
|
|
59
|
+
indices = references_with_indices.map(&:last)
|
|
60
|
+
|
|
61
|
+
# TODO: Use warden or schema?
|
|
62
|
+
type = context.warden.get_type(typename)
|
|
63
|
+
if type.nil? || type.kind != GraphQL::TypeKinds::OBJECT
|
|
64
|
+
# TODO: Raise a specific error class?
|
|
65
|
+
raise "The _entities resolver tried to load an entity for type \"#{typename}\"," \
|
|
66
|
+
' but no object type of that name was found in the schema'
|
|
67
|
+
end
|
|
51
68
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
69
|
+
# TODO: What if the type is an interface?
|
|
70
|
+
type_class = class_of_type(type)
|
|
71
|
+
|
|
72
|
+
if type_class.underscore_reference_keys
|
|
73
|
+
references.map! do |reference|
|
|
74
|
+
reference.transform_keys do |key|
|
|
75
|
+
GraphQL::Schema::Member::BuildType.underscore(key.to_s).to_sym
|
|
76
|
+
end
|
|
56
77
|
end
|
|
57
78
|
end
|
|
58
|
-
end
|
|
59
79
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
80
|
+
if type_class.respond_to?(:resolve_references)
|
|
81
|
+
results = type_class.resolve_references(references, context)
|
|
82
|
+
elsif type_class.respond_to?(:resolve_reference)
|
|
83
|
+
results = references.map { |reference| type_class.resolve_reference(reference, context) }
|
|
84
|
+
else
|
|
85
|
+
results = references
|
|
86
|
+
end
|
|
67
87
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
88
|
+
context.schema.after_lazy(results) do |resolved_results|
|
|
89
|
+
resolved_results.zip(indices).each do |result, i|
|
|
90
|
+
final_result[i] = context.schema.after_lazy(result) do |resolved_value|
|
|
91
|
+
# TODO: This isn't 100% correct: if (for some reason) 2 different resolve_reference
|
|
92
|
+
# calls return the same object, it might not have the right type
|
|
93
|
+
# Right now, apollo-federation just adds a __typename property to the result,
|
|
94
|
+
# but I don't really like the idea of modifying the resolved object
|
|
95
|
+
context[resolved_value] = type
|
|
96
|
+
resolved_value
|
|
97
|
+
end
|
|
77
98
|
end
|
|
78
99
|
end
|
|
79
100
|
end
|
|
101
|
+
|
|
102
|
+
# Make sure we've resolved the outer level of lazies so we can return an array with a possibly lazy
|
|
103
|
+
# entry for each requested entity
|
|
104
|
+
GraphQL::Execution::Lazy.all(maybe_lazies).then do
|
|
105
|
+
final_result
|
|
106
|
+
end
|
|
80
107
|
end
|
|
81
108
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
109
|
+
def class_of_type(type)
|
|
110
|
+
if defined?(GraphQL::ObjectType) && type.is_a?(GraphQL::ObjectType)
|
|
111
|
+
type.metadata[:type_class]
|
|
112
|
+
else
|
|
113
|
+
type
|
|
114
|
+
end
|
|
86
115
|
end
|
|
87
116
|
end
|
|
88
117
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def class_of_type(type)
|
|
92
|
-
if defined?(GraphQL::ObjectType) && type.is_a?(GraphQL::ObjectType)
|
|
93
|
-
type.metadata[:type_class]
|
|
94
|
-
else
|
|
95
|
-
type
|
|
96
|
-
end
|
|
118
|
+
def _entities(representations:)
|
|
119
|
+
self.class._entities(context, representations: representations)
|
|
97
120
|
end
|
|
98
121
|
end
|
|
99
122
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'graphql'
|
|
4
|
+
|
|
5
|
+
module ApolloFederation
|
|
6
|
+
# `resolve_static:` (and GraphQL::Execution::Next generally) doesn't exist on every
|
|
7
|
+
# graphql-ruby version this gem supports, so detect it via a capability the Next-era
|
|
8
|
+
# GraphQL::Schema::Field always defines, rather than assuming a minimum graphql-ruby version.
|
|
9
|
+
# Checking Field#initialize's own parameter list (an earlier version of this check) breaks
|
|
10
|
+
# under graphql-pro, which prepends a `(*args, streamable:, **kwargs)`-shaped `initialize` onto
|
|
11
|
+
# Field -- `instance_method(:initialize)` then reports *that* signature, not the one
|
|
12
|
+
# underneath, so the check silently reads as unsupported. `execution_mode` is a plain
|
|
13
|
+
# `attr_reader`, untouched by that prepend either way. Shared by any field this gem defines
|
|
14
|
+
# directly on the Query type (currently _entities and _service), since those are resolved
|
|
15
|
+
# against the wrapped Query object under classic but the (nil, by default) Query root_value
|
|
16
|
+
# under Next's default :direct_send -- resolve_static is what makes them agree.
|
|
17
|
+
RESOLVE_STATIC_SUPPORTED = GraphQL::Schema::Field.method_defined?(:execution_mode)
|
|
18
|
+
end
|
|
@@ -9,6 +9,7 @@ module ApolloFederation
|
|
|
9
9
|
'directives, removes federation types, and includes rest of full schema after schema ' \
|
|
10
10
|
'directives have been applied'
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# hash_key: so Next reads the { sdl: ... } Hash (see ServiceField#_service) directly.
|
|
13
|
+
field(:sdl, String, null: true, hash_key: :sdl)
|
|
13
14
|
end
|
|
14
15
|
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'graphql'
|
|
4
4
|
require 'apollo-federation/service'
|
|
5
|
+
require 'apollo-federation/next_execution_support'
|
|
5
6
|
|
|
6
7
|
module ApolloFederation
|
|
7
8
|
module ServiceField
|
|
@@ -13,13 +14,19 @@ module ApolloFederation
|
|
|
13
14
|
extend GraphQL::Schema::Member::HasFields
|
|
14
15
|
|
|
15
16
|
def define_service_field
|
|
16
|
-
|
|
17
|
+
# resolve_static so Next dispatches to the class method below, not root_value.
|
|
18
|
+
service_field_options = ApolloFederation::RESOLVE_STATIC_SUPPORTED ? { resolve_static: true } : {}
|
|
19
|
+
field(:_service, Service, null: false, **service_field_options)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def _service(context)
|
|
23
|
+
schema_class = context.schema.is_a?(GraphQL::Schema) ? context.schema.class : context.schema
|
|
24
|
+
{ sdl: schema_class.federation_sdl(context: context.to_h) }
|
|
17
25
|
end
|
|
18
26
|
end
|
|
19
27
|
|
|
20
28
|
def _service
|
|
21
|
-
|
|
22
|
-
{ sdl: schema_class.federation_sdl(context: context.to_h) }
|
|
29
|
+
self.class._service(context)
|
|
23
30
|
end
|
|
24
31
|
end
|
|
25
32
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: apollo-federation
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.10.
|
|
4
|
+
version: 3.10.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Noa Elad
|
|
8
8
|
- Rylan Collins
|
|
9
|
-
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: graphql
|
|
@@ -233,6 +232,7 @@ files:
|
|
|
233
232
|
- lib/apollo-federation/has_directives.rb
|
|
234
233
|
- lib/apollo-federation/input_object.rb
|
|
235
234
|
- lib/apollo-federation/interface.rb
|
|
235
|
+
- lib/apollo-federation/next_execution_support.rb
|
|
236
236
|
- lib/apollo-federation/object.rb
|
|
237
237
|
- lib/apollo-federation/scalar.rb
|
|
238
238
|
- lib/apollo-federation/schema.rb
|
|
@@ -254,7 +254,6 @@ metadata:
|
|
|
254
254
|
changelog_uri: https://github.com/Gusto/apollo-federation-ruby/releases
|
|
255
255
|
source_code_uri: https://github.com/Gusto/apollo-federation-ruby
|
|
256
256
|
bug_tracker_uri: https://github.com/Gusto/apollo-federation-ruby/issues
|
|
257
|
-
post_install_message:
|
|
258
257
|
rdoc_options: []
|
|
259
258
|
require_paths:
|
|
260
259
|
- lib
|
|
@@ -269,8 +268,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
269
268
|
- !ruby/object:Gem::Version
|
|
270
269
|
version: '0'
|
|
271
270
|
requirements: []
|
|
272
|
-
rubygems_version: 3.
|
|
273
|
-
signing_key:
|
|
271
|
+
rubygems_version: 3.6.9
|
|
274
272
|
specification_version: 4
|
|
275
273
|
summary: A Ruby implementation of Apollo Federation
|
|
276
274
|
test_files: []
|