apollo-federation 1.0.4 → 1.1.4.beta.1
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 +35 -0
- data/README.md +0 -8
- data/bin/rspec +29 -0
- data/lib/apollo-federation/entities_field.rb +18 -6
- data/lib/apollo-federation/federated_document_from_schema_definition.rb +12 -4
- data/lib/apollo-federation/has_directives.rb +2 -0
- data/lib/apollo-federation/schema.rb +72 -27
- data/lib/apollo-federation/service_field.rb +12 -3
- data/lib/apollo-federation/tracing.rb +4 -37
- data/lib/apollo-federation/tracing/tracer.rb +62 -14
- data/lib/apollo-federation/version.rb +1 -1
- metadata +47 -7
- data/bin/prepare.rb +0 -22
- data/bin/publish.rb +0 -6
- data/lib/apollo-federation/entity_type_resolution_extension.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: daf6d773f974fc148d5b0b512a26c9f93e0ab439326531a02bfed864d7fa6cb2
|
4
|
+
data.tar.gz: 3b1ff037218ae14fe2aee7557166bc1ab0fe9b91ba52f256d53e17bc63abea0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '083988b5151aed2b559b1f3eeb7760df2ada9fddacba4385c3fed34b5087a6daf1913b73e77eb2c600e1eccb6a4d29e593071f3ccf2a834f6abf88cb7fe100cf'
|
7
|
+
data.tar.gz: c6af4542c73ccf7fffcc06e58a0a8c73b71439dd2a78565611e582cabfe48ca60799df011ebcfde75ab6c811142636dcb30b5486a0bfb3eea3f642f191d2e728
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,38 @@
|
|
1
|
+
## [1.1.4-beta.1](https://github.com/Gusto/apollo-federation-ruby/compare/v1.1.3...v1.1.4-beta.1) (2020-09-21)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* **tracing:** properly handle parsing and validation errors ([#101](https://github.com/Gusto/apollo-federation-ruby/issues/101)) ([6cf8202](https://github.com/Gusto/apollo-federation-ruby/commit/6cf820281dd85bd358c6bf4c176b9a73a9280d54))
|
7
|
+
|
8
|
+
## [1.1.3](https://github.com/Gusto/apollo-federation-ruby/compare/v1.1.2...v1.1.3) (2020-07-16)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* **tracing:** Properly handle tracing fields that resolve an array of lazy values ([#87](https://github.com/Gusto/apollo-federation-ruby/issues/87)) ([a9eed77](https://github.com/Gusto/apollo-federation-ruby/commit/a9eed77bbe5859456f93be00fbcafa02142ad5ed))
|
14
|
+
|
15
|
+
## [1.1.2](https://github.com/Gusto/apollo-federation-ruby/compare/v1.1.1...v1.1.2) (2020-06-09)
|
16
|
+
|
17
|
+
|
18
|
+
### Bug Fixes
|
19
|
+
|
20
|
+
* Fix _service field type owner ([#70](https://github.com/Gusto/apollo-federation-ruby/issues/70)) ([364e54f](https://github.com/Gusto/apollo-federation-ruby/commit/364e54fbb333b7cd4fe30f04bf72733b0e18d3f4))
|
21
|
+
|
22
|
+
## [1.1.1](https://github.com/Gusto/apollo-federation-ruby/compare/v1.1.0...v1.1.1) (2020-05-29)
|
23
|
+
|
24
|
+
|
25
|
+
### Bug Fixes
|
26
|
+
|
27
|
+
* **lazy resolve:** Handle problem with sync resolve ([#58](https://github.com/Gusto/apollo-federation-ruby/issues/58)) ([e66c22b](https://github.com/Gusto/apollo-federation-ruby/commit/e66c22ba6fe51a7c282190ee77bd02dbfa514a66))
|
28
|
+
|
29
|
+
# [1.1.0](https://github.com/Gusto/apollo-federation-ruby/compare/v1.0.4...v1.1.0) (2020-05-27)
|
30
|
+
|
31
|
+
|
32
|
+
### Features
|
33
|
+
|
34
|
+
* Add support for interpreter runtime ([#65](https://github.com/Gusto/apollo-federation-ruby/issues/65)) ([1957da0](https://github.com/Gusto/apollo-federation-ruby/commit/1957da0))
|
35
|
+
|
1
36
|
## [1.0.4](https://github.com/Gusto/apollo-federation-ruby/compare/v1.0.3...v1.0.4) (2020-04-06)
|
2
37
|
|
3
38
|
|
data/README.md
CHANGED
@@ -175,14 +175,6 @@ To support [federated tracing](https://www.apollographql.com/docs/apollo-server/
|
|
175
175
|
# ...
|
176
176
|
end
|
177
177
|
```
|
178
|
-
3. Change your controller to attach the traces to the response:
|
179
|
-
```ruby
|
180
|
-
def execute
|
181
|
-
# ...
|
182
|
-
result = YourSchema.execute(query, ...)
|
183
|
-
render json: ApolloFederation::Tracing.attach_trace_to_result(result)
|
184
|
-
end
|
185
|
-
```
|
186
178
|
|
187
179
|
## Known Issues and Limitations
|
188
180
|
- Only works with class-based schemas, the legacy `.define` API will not be supported
|
data/bin/rspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'pathname'
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
13
|
+
Pathname.new(__FILE__).realpath,)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'rubygems'
|
27
|
+
require 'bundler/setup'
|
28
|
+
|
29
|
+
load Gem.bin_path('rspec-core', 'rspec')
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'graphql'
|
4
4
|
require 'apollo-federation/any'
|
5
|
-
require 'apollo-federation/entity_type_resolution_extension'
|
6
5
|
|
7
6
|
module ApolloFederation
|
8
7
|
module EntitiesField
|
@@ -13,10 +12,16 @@ module ApolloFederation
|
|
13
12
|
module ClassMethods
|
14
13
|
extend GraphQL::Schema::Member::HasFields
|
15
14
|
|
16
|
-
def define_entities_field(
|
15
|
+
def define_entities_field(possible_entities)
|
16
|
+
# If there are any "entities", define the Entity union and and the Query._entities field
|
17
|
+
return if possible_entities.empty?
|
18
|
+
|
19
|
+
entity_type = Class.new(Entity) do
|
20
|
+
possible_types(*possible_entities)
|
21
|
+
end
|
22
|
+
|
17
23
|
field(:_entities, [entity_type, null: true], null: false) do
|
18
24
|
argument :representations, [Any], required: true
|
19
|
-
extension(EntityTypeResolutionExtension)
|
20
25
|
end
|
21
26
|
end
|
22
27
|
end
|
@@ -32,15 +37,22 @@ module ApolloFederation
|
|
32
37
|
' but no object type of that name was found in the schema'
|
33
38
|
end
|
34
39
|
|
35
|
-
# TODO:
|
36
|
-
type_class = type.metadata[:type_class]
|
40
|
+
# TODO: What if the type is an interface?
|
41
|
+
type_class = type.is_a?(GraphQL::ObjectType) ? type.metadata[:type_class] : type
|
37
42
|
if type_class.respond_to?(:resolve_reference)
|
38
43
|
result = type_class.resolve_reference(reference, context)
|
39
44
|
else
|
40
45
|
result = reference
|
41
46
|
end
|
42
47
|
|
43
|
-
|
48
|
+
context.schema.after_lazy(result) do |resolved_value|
|
49
|
+
# TODO: This isn't 100% correct: if (for some reason) 2 different resolve_reference calls
|
50
|
+
# return the same object, it might not have the right type
|
51
|
+
# Right now, apollo-federation just adds a __typename property to the result,
|
52
|
+
# but I don't really like the idea of modifying the resolved object
|
53
|
+
context[resolved_value] = type
|
54
|
+
resolved_value
|
55
|
+
end
|
44
56
|
end
|
45
57
|
end
|
46
58
|
end
|
@@ -23,17 +23,17 @@ module ApolloFederation
|
|
23
23
|
end
|
24
24
|
federation_fields.each { |field| object_node = object_node.delete_child(field) }
|
25
25
|
end
|
26
|
-
merge_directives(object_node, object_type
|
26
|
+
merge_directives(object_node, object_type)
|
27
27
|
end
|
28
28
|
|
29
29
|
def build_interface_type_node(interface_type)
|
30
30
|
field_node = super
|
31
|
-
merge_directives(field_node, interface_type
|
31
|
+
merge_directives(field_node, interface_type)
|
32
32
|
end
|
33
33
|
|
34
34
|
def build_field_node(field_type)
|
35
35
|
field_node = super
|
36
|
-
merge_directives(field_node, field_type
|
36
|
+
merge_directives(field_node, field_type)
|
37
37
|
end
|
38
38
|
|
39
39
|
def build_type_definition_nodes(types)
|
@@ -53,7 +53,15 @@ module ApolloFederation
|
|
53
53
|
type == warden.root_type_for_operation('query')
|
54
54
|
end
|
55
55
|
|
56
|
-
def merge_directives(node,
|
56
|
+
def merge_directives(node, type)
|
57
|
+
if type.is_a?(ApolloFederation::HasDirectives)
|
58
|
+
directives = type.federation_directives
|
59
|
+
elsif type.is_a?(GraphQL::Define::InstanceDefinable)
|
60
|
+
directives = type.metadata[:federation_directives]
|
61
|
+
else
|
62
|
+
directives = []
|
63
|
+
end
|
64
|
+
|
57
65
|
(directives || []).each do |directive|
|
58
66
|
node = node.merge_directive(
|
59
67
|
name: directive[:name],
|
@@ -8,52 +8,97 @@ require 'apollo-federation/federated_document_from_schema_definition.rb'
|
|
8
8
|
module ApolloFederation
|
9
9
|
module Schema
|
10
10
|
def self.included(klass)
|
11
|
-
|
11
|
+
if Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('1.10.0')
|
12
|
+
klass.extend(OneTenMethods)
|
13
|
+
else
|
14
|
+
klass.extend(OneNineMethods)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module CommonMethods
|
19
|
+
def federation_sdl(context: nil)
|
20
|
+
document_from_schema = FederatedDocumentFromSchemaDefinition.new(self, context: context)
|
21
|
+
GraphQL::Language::Printer.new.print(document_from_schema.document)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def federation_query(query_obj)
|
27
|
+
# Build the new query object with the '_service' field
|
28
|
+
if query_obj.nil?
|
29
|
+
base = GraphQL::Schema::Object
|
30
|
+
elsif Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('1.10.0')
|
31
|
+
base = query_obj
|
32
|
+
else
|
33
|
+
base = query_obj.metadata[:type_class]
|
34
|
+
end
|
35
|
+
|
36
|
+
klass = Class.new(base) do
|
37
|
+
# TODO: Maybe the name should inherit from the original Query name
|
38
|
+
# Or MAYBE we should just modify the original class?
|
39
|
+
graphql_name 'Query'
|
40
|
+
|
41
|
+
include EntitiesField
|
42
|
+
include ServiceField
|
43
|
+
end
|
44
|
+
|
45
|
+
klass.define_service_field
|
46
|
+
klass
|
47
|
+
end
|
12
48
|
end
|
13
49
|
|
14
|
-
|
50
|
+
# TODO: Remove these once we drop support for graphql 1.9
|
51
|
+
module OneNineMethods
|
52
|
+
include CommonMethods
|
53
|
+
|
15
54
|
def to_graphql
|
16
55
|
orig_defn = super
|
56
|
+
@query_object = federation_query(query)
|
17
57
|
|
18
58
|
possible_entities = orig_defn.types.values.select do |type|
|
19
59
|
!type.introspection? && !type.default_scalar? && type.is_a?(GraphQL::ObjectType) &&
|
20
60
|
type.metadata[:federation_directives]&.any? { |directive| directive[:name] == 'key' }
|
21
61
|
end
|
22
|
-
|
23
|
-
@query_object = federation_query
|
24
|
-
|
25
|
-
if !possible_entities.empty?
|
26
|
-
entity_type = Class.new(Entity) do
|
27
|
-
possible_types(*possible_entities)
|
28
|
-
end
|
29
|
-
# TODO: Should/can we encapsulate all of this inside the module? What's the best/most Ruby
|
30
|
-
# way to split this out?
|
31
|
-
@query_object.define_entities_field(entity_type)
|
32
|
-
end
|
62
|
+
@query_object.define_entities_field(possible_entities)
|
33
63
|
|
34
64
|
super
|
35
65
|
end
|
66
|
+
end
|
36
67
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
68
|
+
module OneTenMethods
|
69
|
+
include CommonMethods
|
70
|
+
|
71
|
+
def query(new_query_object = nil)
|
72
|
+
if new_query_object
|
73
|
+
@orig_query_object = new_query_object
|
42
74
|
else
|
43
|
-
|
44
|
-
|
75
|
+
if !@federation_query_object
|
76
|
+
@federation_query_object = federation_query(@orig_query_object)
|
77
|
+
@federation_query_object.define_entities_field(schema_entities)
|
45
78
|
|
46
|
-
|
47
|
-
|
79
|
+
super(@federation_query_object)
|
80
|
+
end
|
48
81
|
|
49
|
-
|
50
|
-
include ServiceField
|
82
|
+
super
|
51
83
|
end
|
52
84
|
end
|
53
85
|
|
54
|
-
|
55
|
-
|
56
|
-
|
86
|
+
private
|
87
|
+
|
88
|
+
def schema_entities
|
89
|
+
# Create a temporary schema that inherits from this one to extract the types
|
90
|
+
types_schema = Class.new(self)
|
91
|
+
# Add the original query objects to the types. We have to use orphan_types here to avoid
|
92
|
+
# infinite recursion
|
93
|
+
types_schema.orphan_types(@orig_query_object)
|
94
|
+
|
95
|
+
# Walk through all of the types and determine which ones are entities (any type with a
|
96
|
+
# "key" directive)
|
97
|
+
types_schema.types.values.select do |type|
|
98
|
+
# TODO: Interfaces can have a key...
|
99
|
+
!type.introspection? && type.include?(ApolloFederation::Object) &&
|
100
|
+
type.federation_directives&.any? { |directive| directive[:name] == 'key' }
|
101
|
+
end
|
57
102
|
end
|
58
103
|
end
|
59
104
|
end
|
@@ -5,12 +5,21 @@ require 'apollo-federation/service'
|
|
5
5
|
|
6
6
|
module ApolloFederation
|
7
7
|
module ServiceField
|
8
|
-
|
8
|
+
def self.included(base)
|
9
|
+
base.extend(ClassMethods)
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
extend GraphQL::Schema::Member::HasFields
|
9
14
|
|
10
|
-
|
15
|
+
def define_service_field
|
16
|
+
field(:_service, Service, null: false)
|
17
|
+
end
|
18
|
+
end
|
11
19
|
|
12
20
|
def _service
|
13
|
-
|
21
|
+
schema_class = context.schema.is_a?(GraphQL::Schema) ? context.schema.class : context.schema
|
22
|
+
{ sdl: schema_class.federation_sdl(context: context) }
|
14
23
|
end
|
15
24
|
end
|
16
25
|
end
|
@@ -4,14 +4,6 @@ module ApolloFederation
|
|
4
4
|
module Tracing
|
5
5
|
KEY = :ftv1
|
6
6
|
DEBUG_KEY = "#{KEY}_debug".to_sym
|
7
|
-
class NotInstalledError < StandardError
|
8
|
-
MESSAGE = 'Apollo Federation Tracing not installed. \
|
9
|
-
Add `use ApolloFederation::Tracing` to your schema.'
|
10
|
-
|
11
|
-
def message
|
12
|
-
MESSAGE
|
13
|
-
end
|
14
|
-
end
|
15
7
|
|
16
8
|
module_function
|
17
9
|
|
@@ -23,35 +15,10 @@ Add `use ApolloFederation::Tracing` to your schema.'
|
|
23
15
|
headers && headers['apollo-federation-include-trace'] == KEY.to_s
|
24
16
|
end
|
25
17
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
raise NotInstalledError unless trace[:start_time]
|
31
|
-
|
32
|
-
result['errors']&.each do |error|
|
33
|
-
trace[:node_map].add_error(error)
|
34
|
-
end
|
35
|
-
|
36
|
-
proto = ApolloFederation::Tracing::Trace.new(
|
37
|
-
start_time: to_proto_timestamp(trace[:start_time]),
|
38
|
-
end_time: to_proto_timestamp(trace[:end_time]),
|
39
|
-
duration_ns: trace[:end_time_nanos] - trace[:start_time_nanos],
|
40
|
-
root: trace[:node_map].root,
|
41
|
-
)
|
42
|
-
|
43
|
-
result[:extensions] ||= {}
|
44
|
-
result[:extensions][KEY] = Base64.encode64(proto.class.encode(proto))
|
45
|
-
|
46
|
-
if result.context[:debug_tracing]
|
47
|
-
result[:extensions][DEBUG_KEY] = proto.to_h
|
48
|
-
end
|
49
|
-
|
50
|
-
result.to_h
|
51
|
-
end
|
52
|
-
|
53
|
-
def to_proto_timestamp(time)
|
54
|
-
Google::Protobuf::Timestamp.new(seconds: time.to_i, nanos: time.nsec)
|
18
|
+
# @deprecated There is no need to call this method. Traces are added to the result automatically
|
19
|
+
def attach_trace_to_result(_result)
|
20
|
+
warn '[DEPRECATION] `attach_trace_to_result` is deprecated. There is no need to call it, as '\
|
21
|
+
'traces are added to the result automatically'
|
55
22
|
end
|
56
23
|
end
|
57
24
|
end
|
@@ -35,15 +35,15 @@ module ApolloFederation
|
|
35
35
|
module Tracing
|
36
36
|
module Tracer
|
37
37
|
# store string constants to avoid creating new strings for each call to .trace
|
38
|
-
|
38
|
+
EXECUTE_MULTIPLEX = 'execute_multiplex'
|
39
39
|
EXECUTE_QUERY_LAZY = 'execute_query_lazy'
|
40
40
|
EXECUTE_FIELD = 'execute_field'
|
41
41
|
EXECUTE_FIELD_LAZY = 'execute_field_lazy'
|
42
42
|
|
43
43
|
def self.trace(key, data, &block)
|
44
44
|
case key
|
45
|
-
when
|
46
|
-
|
45
|
+
when EXECUTE_MULTIPLEX
|
46
|
+
execute_multiplex(data, &block)
|
47
47
|
when EXECUTE_QUERY_LAZY
|
48
48
|
execute_query_lazy(data, &block)
|
49
49
|
when EXECUTE_FIELD
|
@@ -55,19 +55,26 @@ module ApolloFederation
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
def self.execute_multiplex(data, &block)
|
59
|
+
# Step 1:
|
60
|
+
# Create a trace hash on each query's context and record start times.
|
61
|
+
data.fetch(:multiplex).queries.each { |query| start_trace(query) }
|
62
|
+
|
63
|
+
results = block.call
|
64
|
+
|
65
|
+
# Step 5
|
66
|
+
# Attach the trace to the 'extensions' key of each result
|
67
|
+
results.map { |result| attach_trace_to_result(result) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.start_trace(query)
|
71
|
+
return unless query.context && query.context[:tracing_enabled]
|
63
72
|
|
64
73
|
query.context.namespace(ApolloFederation::Tracing::KEY).merge!(
|
65
74
|
start_time: Time.now.utc,
|
66
75
|
start_time_nanos: Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond),
|
67
76
|
node_map: NodeMap.new,
|
68
77
|
)
|
69
|
-
|
70
|
-
block.call
|
71
78
|
end
|
72
79
|
|
73
80
|
# Step 4:
|
@@ -159,17 +166,27 @@ module ApolloFederation
|
|
159
166
|
|
160
167
|
end_time_nanos = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
|
161
168
|
|
162
|
-
#
|
169
|
+
# legacy runtime
|
163
170
|
if data.include?(:context)
|
164
|
-
context = data.fetch(:context)
|
165
171
|
path = context.path
|
166
|
-
|
167
|
-
|
172
|
+
field = context.field
|
173
|
+
else # interpreter runtime
|
168
174
|
path = data.fetch(:path)
|
175
|
+
field = data.fetch(:field)
|
169
176
|
end
|
170
177
|
|
171
178
|
trace = context.namespace(ApolloFederation::Tracing::KEY)
|
172
179
|
|
180
|
+
# When a field is resolved with an array of lazy values, the interpreter fires an
|
181
|
+
# `execute_field` for the resolution of the field and then a `execute_field_lazy` event for
|
182
|
+
# each lazy value in the array. Since the path here will contain an index (indicating which
|
183
|
+
# lazy value we're executing: e.g. ['arrayOfLazies', 0]), we won't have a node for the path.
|
184
|
+
# We only care about the end of the parent field (e.g. ['arrayOfLazies']), so we get the
|
185
|
+
# node for that path. What ends up happening is we update the end_time for the parent node
|
186
|
+
# for each of the lazy values. The last one that's executed becomes the final end time.
|
187
|
+
if field.type.list? && path.last.is_a?(Integer)
|
188
|
+
path = path[0...-1]
|
189
|
+
end
|
173
190
|
node = trace[:node_map].node_for_path(path)
|
174
191
|
node.end_time = end_time_nanos - trace[:start_time_nanos]
|
175
192
|
|
@@ -178,6 +195,37 @@ module ApolloFederation
|
|
178
195
|
result
|
179
196
|
end
|
180
197
|
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
198
|
+
|
199
|
+
def self.attach_trace_to_result(result)
|
200
|
+
return result unless result.context[:tracing_enabled]
|
201
|
+
|
202
|
+
trace = result.context.namespace(ApolloFederation::Tracing::KEY)
|
203
|
+
|
204
|
+
result['errors']&.each do |error|
|
205
|
+
trace[:node_map].add_error(error)
|
206
|
+
end
|
207
|
+
|
208
|
+
proto = ApolloFederation::Tracing::Trace.new(
|
209
|
+
start_time: to_proto_timestamp(trace[:start_time]),
|
210
|
+
end_time: to_proto_timestamp(trace[:end_time]),
|
211
|
+
duration_ns: trace[:end_time_nanos] - trace[:start_time_nanos],
|
212
|
+
root: trace[:node_map].root,
|
213
|
+
)
|
214
|
+
|
215
|
+
result[:extensions] ||= {}
|
216
|
+
result[:extensions][ApolloFederation::Tracing::KEY] =
|
217
|
+
Base64.encode64(proto.class.encode(proto))
|
218
|
+
|
219
|
+
if result.context[:debug_tracing]
|
220
|
+
result[:extensions][ApolloFederation::Tracing::DEBUG_KEY] = proto.to_h
|
221
|
+
end
|
222
|
+
|
223
|
+
result
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.to_proto_timestamp(time)
|
227
|
+
Google::Protobuf::Timestamp.new(seconds: time.to_i, nanos: time.nsec)
|
228
|
+
end
|
181
229
|
end
|
182
230
|
end
|
183
231
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apollo-federation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.4.beta.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noa Elad
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-09-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: graphql
|
@@ -53,6 +53,34 @@ dependencies:
|
|
53
53
|
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: appraisal
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: debase
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
56
84
|
- !ruby/object:Gem::Dependency
|
57
85
|
name: pry-byebug
|
58
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -137,6 +165,20 @@ dependencies:
|
|
137
165
|
- - ">="
|
138
166
|
- !ruby/object:Gem::Version
|
139
167
|
version: '0'
|
168
|
+
- !ruby/object:Gem::Dependency
|
169
|
+
name: ruby-debug-ide
|
170
|
+
requirement: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
type: :development
|
176
|
+
prerelease: false
|
177
|
+
version_requirements: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
140
182
|
description: A Ruby implementation of Apollo Federation
|
141
183
|
email:
|
142
184
|
- noa.elad@gusto.com
|
@@ -149,13 +191,11 @@ files:
|
|
149
191
|
- LICENSE
|
150
192
|
- README.md
|
151
193
|
- bin/generate-protos.sh
|
152
|
-
- bin/
|
153
|
-
- bin/publish.rb
|
194
|
+
- bin/rspec
|
154
195
|
- lib/apollo-federation.rb
|
155
196
|
- lib/apollo-federation/any.rb
|
156
197
|
- lib/apollo-federation/entities_field.rb
|
157
198
|
- lib/apollo-federation/entity.rb
|
158
|
-
- lib/apollo-federation/entity_type_resolution_extension.rb
|
159
199
|
- lib/apollo-federation/federated_document_from_schema_definition.rb
|
160
200
|
- lib/apollo-federation/field.rb
|
161
201
|
- lib/apollo-federation/has_directives.rb
|
@@ -190,9 +230,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
190
230
|
version: 2.2.0
|
191
231
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
192
232
|
requirements:
|
193
|
-
- - "
|
233
|
+
- - ">"
|
194
234
|
- !ruby/object:Gem::Version
|
195
|
-
version:
|
235
|
+
version: 1.3.1
|
196
236
|
requirements: []
|
197
237
|
rubygems_version: 3.0.3
|
198
238
|
signing_key:
|
data/bin/prepare.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
def set_version
|
4
|
-
new_version = ARGV[0]
|
5
|
-
|
6
|
-
contents = File.read('lib/apollo-federation/version.rb')
|
7
|
-
|
8
|
-
new_contents = contents.gsub(/VERSION = '[0-9.]*'/, "VERSION = '#{new_version}'")
|
9
|
-
File.write('lib/apollo-federation/version.rb', new_contents)
|
10
|
-
end
|
11
|
-
|
12
|
-
def bundle_install
|
13
|
-
system('bundle install')
|
14
|
-
end
|
15
|
-
|
16
|
-
def build_gem
|
17
|
-
system('gem build apollo-federation.gemspec')
|
18
|
-
end
|
19
|
-
|
20
|
-
set_version
|
21
|
-
bundle_install
|
22
|
-
build_gem
|
data/bin/publish.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class EntityTypeResolutionExtension < GraphQL::Schema::FieldExtension
|
4
|
-
def after_resolve(value:, context:, **_rest)
|
5
|
-
synced_value =
|
6
|
-
value.map do |type, result|
|
7
|
-
[type, context.query.schema.sync_lazy(result)]
|
8
|
-
end
|
9
|
-
|
10
|
-
# TODO: This isn't 100% correct: if (for some reason) 2 different resolve_reference calls
|
11
|
-
# return the same object, it might not have the right type
|
12
|
-
# Right now, apollo-federation just adds a __typename property to the result,
|
13
|
-
# but I don't really like the idea of modifying the resolved object
|
14
|
-
synced_value.each { |type, result| context[result] = type }
|
15
|
-
|
16
|
-
synced_value.map { |_, result| result }
|
17
|
-
end
|
18
|
-
end
|