|
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 |
| 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 | + 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 | + end |
12 | 45 | end |
13 | 46 |
|
14 | | - module ClassMethods |
| 47 | + # TODO: Remove these once we drop support for graphql 1.9 |
| 48 | + module OneNineMethods |
| 49 | + include CommonMethods |
| 50 | + |
15 | 51 | def to_graphql |
16 | 52 | orig_defn = super |
| 53 | + @query_object = federation_query(query) |
17 | 54 |
|
18 | 55 | possible_entities = orig_defn.types.values.select do |type| |
19 | 56 | !type.introspection? && !type.default_scalar? && type.is_a?(GraphQL::ObjectType) && |
20 | 57 | type.metadata[:federation_directives]&.any? { |directive| directive[:name] == 'key' } |
21 | 58 | 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 |
| 59 | + @query_object.define_entities_field(possible_entities) |
33 | 60 |
|
34 | 61 | super |
35 | 62 | end |
| 63 | + end |
36 | 64 |
|
37 | | - def federation_query |
38 | | - if query.nil? |
39 | | - base = GraphQL::Schema::Object |
40 | | - elsif Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('1.10.0') |
41 | | - base = query |
| 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 |
42 | 71 | else |
43 | | - base = query.metadata[:type_class] |
44 | | - end |
| 72 | + if !@federation_query_object |
| 73 | + @federation_query_object = federation_query(@orig_query_object) |
| 74 | + @federation_query_object.define_entities_field(schema_entities) |
45 | 75 |
|
46 | | - Class.new(base) do |
47 | | - graphql_name 'Query' |
| 76 | + super(@federation_query_object) |
| 77 | + end |
48 | 78 |
|
49 | | - include EntitiesField |
50 | | - include ServiceField |
| 79 | + super |
51 | 80 | end |
52 | 81 | end |
53 | 82 |
|
54 | | - def federation_sdl(context: nil) |
55 | | - document_from_schema = FederatedDocumentFromSchemaDefinition.new(self, context: context) |
56 | | - GraphQL::Language::Printer.new.print(document_from_schema.document) |
| 83 | + private |
| 84 | + |
| 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) |
| 91 | + |
| 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 |
57 | 99 | end |
58 | 100 | end |
59 | 101 | end |
|
0 commit comments