apollo-federation 1.0.1 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5447e41edfbfe54ff9555f72f648b65d6b8bcfd424e869d39ec728b34e44ffac
4
- data.tar.gz: 3eff395ab5a52ebfd54b4668ce309354c45f0c4a7c6e90a509dd13f462e0cb3e
3
+ metadata.gz: a520e4e58f160aa1029b433dc2b35cb3026a7b78a976510632fcfa6c85535208
4
+ data.tar.gz: cc672c543e40bdc06d20635bf9ebd41b5832ec97868931c8759ae01bc5be6d80
5
5
  SHA512:
6
- metadata.gz: 51cd3316349b31c17e068e43dff5297598457eba6f56b12aedb303a3f792cec01a960e537dd757e10bba4ca477cf4da2cce3492c56ad50231b3459db8ee38d1d
7
- data.tar.gz: 8d24372e4ab0d6f916089b95a8be62ce166dbed95f6afd5c65bbc09d2d91b2bd063fcc13cdbf9d2403b3875741113f6c34e8e9105955736a5fb51a3b97d5d890
6
+ metadata.gz: 8f5ecaf9d65c0440b2a6ff9f7211a318ff8ef34daa48192615f7d9f33ee9b00362043249a221606b118cc1909c382fb150fd8a75ec92eedd50e816a61343a56f
7
+ data.tar.gz: b39f9288f6928f1998647b63495127c98180f0b4287dcd6528c0b25b9f66c26df617405ac30b484d768df3022f341b491058dde22b33d78f217ffffeb16936fb
@@ -1,3 +1,38 @@
1
+ ## [1.1.1](https://github.com/Gusto/apollo-federation-ruby/compare/v1.1.0...v1.1.1) (2020-05-29)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **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))
7
+
8
+ # [1.1.0](https://github.com/Gusto/apollo-federation-ruby/compare/v1.0.4...v1.1.0) (2020-05-27)
9
+
10
+
11
+ ### Features
12
+
13
+ * 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))
14
+
15
+ ## [1.0.4](https://github.com/Gusto/apollo-federation-ruby/compare/v1.0.3...v1.0.4) (2020-04-06)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * Fix spec to account for breaking change to graphql-ruby 1.10.0 ([#62](https://github.com/Gusto/apollo-federation-ruby/issues/62)) ([a631441](https://github.com/Gusto/apollo-federation-ruby/commit/a631441))
21
+
22
+ ## [1.0.3](https://github.com/Gusto/apollo-federation-ruby/compare/v1.0.2...v1.0.3) (2020-03-25)
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * Make the tracer work with the new interpreter runtime ([#59](https://github.com/Gusto/apollo-federation-ruby/issues/59)) ([de4caf0](https://github.com/Gusto/apollo-federation-ruby/commit/de4caf0))
28
+
29
+ ## [1.0.2](https://github.com/Gusto/apollo-federation-ruby/compare/v1.0.1...v1.0.2) (2020-02-19)
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * service field context ([#50](https://github.com/Gusto/apollo-federation-ruby/issues/50)) ([6dd1fe7](https://github.com/Gusto/apollo-federation-ruby/commit/6dd1fe7))
35
+
1
36
  ## [1.0.1](https://github.com/Gusto/apollo-federation-ruby/compare/v1.0.0...v1.0.1) (2020-01-29)
2
37
 
3
38
 
@@ -13,7 +13,14 @@ module ApolloFederation
13
13
  module ClassMethods
14
14
  extend GraphQL::Schema::Member::HasFields
15
15
 
16
- def define_entities_field(entity_type)
16
+ def define_entities_field(possible_entities)
17
+ # If there are any "entities", define the Entity union and and the Query._entities field
18
+ return if possible_entities.empty?
19
+
20
+ entity_type = Class.new(Entity) do
21
+ possible_types(*possible_entities)
22
+ end
23
+
17
24
  field(:_entities, [entity_type, null: true], null: false) do
18
25
  argument :representations, [Any], required: true
19
26
  extension(EntityTypeResolutionExtension)
@@ -32,8 +39,8 @@ module ApolloFederation
32
39
  ' but no object type of that name was found in the schema'
33
40
  end
34
41
 
35
- # TODO: Handle non-class types?
36
- type_class = type.metadata[:type_class]
42
+ # TODO: What if the type is an interface?
43
+ type_class = type.is_a?(GraphQL::ObjectType) ? type.metadata[:type_class] : type
37
44
  if type_class.respond_to?(:resolve_reference)
38
45
  result = type_class.resolve_reference(reference, context)
39
46
  else
@@ -2,17 +2,15 @@
2
2
 
3
3
  class EntityTypeResolutionExtension < GraphQL::Schema::FieldExtension
4
4
  def after_resolve(value:, context:, **_rest)
5
- synced_value =
6
- value.map do |type, result|
7
- [type, context.query.schema.sync_lazy(result)]
5
+ value.map do |type, result|
6
+ context.schema.after_lazy(result) do |resolved_value|
7
+ # TODO: This isn't 100% correct: if (for some reason) 2 different resolve_reference calls
8
+ # return the same object, it might not have the right type
9
+ # Right now, apollo-federation just adds a __typename property to the result,
10
+ # but I don't really like the idea of modifying the resolved object
11
+ context[resolved_value] = type
12
+ resolved_value
8
13
  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 }
14
+ end
17
15
  end
18
16
  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.metadata[:federation_directives])
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.metadata[:federation_directives])
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.metadata[:federation_directives])
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, directives)
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],
@@ -2,6 +2,8 @@
2
2
 
3
3
  module ApolloFederation
4
4
  module HasDirectives
5
+ attr_reader :federation_directives
6
+
5
7
  def add_directive(name:, arguments: nil)
6
8
  @federation_directives ||= []
7
9
  @federation_directives << { name: name, arguments: arguments }
@@ -8,48 +8,94 @@ require 'apollo-federation/federated_document_from_schema_definition.rb'
8
8
  module ApolloFederation
9
9
  module Schema
10
10
  def self.included(klass)
11
- klass.extend(ClassMethods)
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
12
16
  end
13
17
 
14
- module ClassMethods
15
- def to_graphql
16
- orig_defn = super
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
17
25
 
18
- if query.nil?
26
+ def federation_query(query_obj)
27
+ # Build the new query object with the '_service' field
28
+ if query_obj.nil?
19
29
  base = GraphQL::Schema::Object
30
+ elsif Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('1.10.0')
31
+ base = query_obj
20
32
  else
21
- base = query.metadata[:type_class]
33
+ base = query_obj.metadata[:type_class]
22
34
  end
23
35
 
24
- federation_query = Class.new(base) do
36
+ 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?
25
39
  graphql_name 'Query'
26
40
 
27
41
  include EntitiesField
28
42
  include ServiceField
29
43
  end
44
+ end
45
+ end
46
+
47
+ # TODO: Remove these once we drop support for graphql 1.9
48
+ module OneNineMethods
49
+ include CommonMethods
50
+
51
+ def to_graphql
52
+ orig_defn = super
53
+ @query_object = federation_query(query)
30
54
 
31
55
  possible_entities = orig_defn.types.values.select do |type|
32
56
  !type.introspection? && !type.default_scalar? && type.is_a?(GraphQL::ObjectType) &&
33
57
  type.metadata[:federation_directives]&.any? { |directive| directive[:name] == 'key' }
34
58
  end
59
+ @query_object.define_entities_field(possible_entities)
35
60
 
36
- if !possible_entities.empty?
37
- entity_type = Class.new(Entity) do
38
- possible_types(*possible_entities)
61
+ super
62
+ end
63
+ end
64
+
65
+ module OneTenMethods
66
+ include CommonMethods
67
+
68
+ def query(new_query_object = nil)
69
+ if new_query_object
70
+ @orig_query_object = new_query_object
71
+ else
72
+ if !@federation_query_object
73
+ @federation_query_object = federation_query(@orig_query_object)
74
+ @federation_query_object.define_entities_field(schema_entities)
75
+
76
+ super(@federation_query_object)
39
77
  end
40
- # TODO: Should/can we encapsulate all of this inside the module? What's the best/most Ruby
41
- # way to split this out?
42
- federation_query.define_entities_field(entity_type)
78
+
79
+ super
43
80
  end
81
+ end
44
82
 
45
- query(federation_query)
83
+ private
46
84
 
47
- super
48
- end
85
+ def schema_entities
86
+ # Create a temporary schema that inherits from this one to extract the types
87
+ types_schema = Class.new(self)
88
+ # Add the original query objects to the types. We have to use orphan_types here to avoid
89
+ # infinite recursion
90
+ types_schema.orphan_types(@orig_query_object)
49
91
 
50
- def federation_sdl(context: nil)
51
- document_from_schema = FederatedDocumentFromSchemaDefinition.new(self, context: context)
52
- GraphQL::Language::Printer.new.print(document_from_schema.document)
92
+ # Walk through all of the types and determine which ones are entities (any type with a
93
+ # "key" directive)
94
+ types_schema.types.values.select do |type|
95
+ # TODO: Interfaces can have a key...
96
+ !type.introspection? && type.include?(ApolloFederation::Object) &&
97
+ type.federation_directives&.any? { |directive| directive[:name] == 'key' }
98
+ end
53
99
  end
54
100
  end
55
101
  end
@@ -10,7 +10,8 @@ module ApolloFederation
10
10
  field(:_service, Service, null: false)
11
11
 
12
12
  def _service
13
- { sdl: context.schema.class.federation_sdl(context) }
13
+ schema_class = context.schema.is_a?(GraphQL::Schema) ? context.schema.class : context.schema
14
+ { sdl: schema_class.federation_sdl(context: context) }
14
15
  end
15
16
  end
16
17
  end
@@ -103,7 +103,7 @@ module ApolloFederation
103
103
  # because we don't have the error `location` here.
104
104
  # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
105
105
  def self.execute_field(data, &block)
106
- context = data.fetch(:context) || data.fetch(:query).context
106
+ context = data.fetch(:context, nil) || data.fetch(:query).context
107
107
  return block.call unless context && context[:tracing_enabled]
108
108
 
109
109
  start_time_nanos = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
@@ -116,16 +116,17 @@ module ApolloFederation
116
116
 
117
117
  end_time_nanos = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
118
118
 
119
- # interpreter runtime
119
+ # legacy runtime
120
120
  if data.include?(:context)
121
121
  path = context.path
122
122
  field_name = context.field.graphql_name
123
123
  field_type = context.field.type.to_s
124
124
  parent_type = context.parent_type.graphql_name
125
- else # legacy runtime
125
+ else # interpreter runtime
126
126
  path = data.fetch(:path)
127
- field_name = data.fetch(:field).graphql_name
128
- field_type = data.fetch(:field).type.unwrap.graphql_name
127
+ field = data.fetch(:field)
128
+ field_name = field.graphql_name
129
+ field_type = field.type.to_type_signature
129
130
  parent_type = data.fetch(:owner).graphql_name
130
131
  end
131
132
 
@@ -147,7 +148,7 @@ module ApolloFederation
147
148
  # Optional Step 3:
148
149
  # Overwrite the end times on the trace node if the resolver was lazy.
149
150
  def self.execute_field_lazy(data, &block)
150
- context = data.fetch(:context) || data.fetch(:query).context
151
+ context = data.fetch(:context, nil) || data.fetch(:query).context
151
152
  return block.call unless context && context[:tracing_enabled]
152
153
 
153
154
  begin
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ApolloFederation
4
- VERSION = '1.0.1'
4
+ VERSION = '1.1.1'
5
5
  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.0.1
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noa Elad
@@ -9,20 +9,20 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-01-29 00:00:00.000000000 Z
12
+ date: 2020-05-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: graphql
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: 1.9.8
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
27
  version: 1.9.8
28
28
  - !ruby/object:Gem::Dependency