graphql-stitching 0.2.2 → 0.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f67a4b892fba612e2e38552ae0a0f681ed0fdc136c04ecef4d2c01692eed9eb8
4
- data.tar.gz: 3db164c53dc67d64b7364ba5a17186e3eb612074993b21df5f9a8b059fca9f89
3
+ metadata.gz: a05f9ff15f40a886a20136cdaf5323cf37a59e7d98de27cc19cf7e600feb48e2
4
+ data.tar.gz: 7727f7394bb99abcb3c3a448f1ebf8b3bd5f9b7a2fd74e9bc741285f401a23cc
5
5
  SHA512:
6
- metadata.gz: 8d687747a19a25a69b1c998910265a183bdb22338fec5e9787412ca5c1cdfc5e0b838bb49ce4942ce41dec0e000e0ddc35bdf07368a7a772751ffc5342b7ee48
7
- data.tar.gz: f4419aa525964b37db62ce2343d11914ac56677825c8f1450c5187465b2f28e3a740acf6779309bdb0a5fbd41829054101aed4c9d0eb764882759c50bbf1b641
6
+ metadata.gz: f8993da51f8bd18ec1e590727a24bcba8690831e006a1a3fc861cfaa83b9794b94f90fb0e458919d7997d67606ae8ece4acfdd8a3a0d6fe669e7971b01232cf3
7
+ data.tar.gz: 1032ed3279a98d1bc52db321a49a0a47d78dfb00cf9a8c922d1e77217ac837f8695c146908767ec398620f42a816f92eefc339d1fde970fe543904a6a30976f5
data/README.md CHANGED
@@ -92,7 +92,7 @@ To facilitate this merging of types, stitching must know how to cross-reference
92
92
  directive @stitch(key: String!) repeatable on FIELD_DEFINITION
93
93
  ```
94
94
 
95
- This directive is applied to root queries where a merged type may be accessed in each location, and a `key` argument specifies a field needed from other locations to be used as a query argument.
95
+ This directive (or [static configuration](#sdl-based-schemas)) is applied to root queries where a merged type may be accessed in each location, and a `key` argument specifies a field needed from other locations to be used as a query argument.
96
96
 
97
97
  ```ruby
98
98
  products_schema = <<~GRAPHQL
@@ -219,7 +219,7 @@ type Query {
219
219
  }
220
220
  ```
221
221
 
222
- The `@stitch` directive is also repeatable (_requires graphql-ruby v2.0.15_), allowing a single query to associate with multiple keys:
222
+ The `@stitch` directive is also repeatable (_requires graphql-ruby >= v2.0.15_), allowing a single query to associate with multiple keys:
223
223
 
224
224
  ```graphql
225
225
  type Product {
@@ -251,6 +251,35 @@ class Query < GraphQL::Schema::Object
251
251
  end
252
252
  ```
253
253
 
254
+ The `@stitch` directive can be exported from a class-based schema to an SDL string by calling `schema.to_definition`.
255
+
256
+ #### SDL-based schemas
257
+
258
+ A clean SDL string may also have stitching directives applied via static configuration using the `GraphQL::Stitching` module to build the SDL into a schema:
259
+
260
+ ```ruby
261
+ sdl_string = <<~GRAPHQL
262
+ type Product {
263
+ id: ID!
264
+ upc: ID!
265
+ }
266
+ type Query {
267
+ productById(id: ID!): Product
268
+ productByUpc(upc: ID!): Product
269
+ }
270
+ GRAPHQL
271
+
272
+ decorated_schema = GraphQL::Stitching.schema_from_definition(sdl_string, stitch_directives: [
273
+ { type_name: "Query", field_name: "productById", key: "id" },
274
+ { type_name: "Query", field_name: "productByUpc", key: "upc" },
275
+ ])
276
+
277
+ supergraph = GraphQL::Stitching::Composer.new(schemas: {
278
+ "products" => decorated_schema,
279
+ # ...
280
+ })
281
+ ```
282
+
254
283
  #### Custom directive names
255
284
 
256
285
  The library is configured to use a `@stitch` directive by default. You may customize this by setting a new name during initialization:
data/docs/supergraph.md CHANGED
@@ -30,7 +30,7 @@ end
30
30
 
31
31
  ### Export and caching
32
32
 
33
- A Supergraph is designed to be composed, cached, and restored. Calling the `export` method will return an SDL (Schema Definition Language) print of the combined graph schema and a deletation mapping hash. These can be persisted in any raw format that suits your stack:
33
+ A Supergraph is designed to be composed, cached, and restored. Calling the `export` method will return an SDL (Schema Definition Language) print of the combined graph schema and a delegation mapping hash. These can be persisted in any raw format that suits your stack:
34
34
 
35
35
  ```ruby
36
36
  supergraph_sdl, delegation_map = supergraph.export
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  end
27
27
  spec.require_paths = ['lib']
28
28
 
29
- spec.add_runtime_dependency 'graphql', '~> 2.0.3'
29
+ spec.add_runtime_dependency 'graphql', '>= 1.13.9'
30
30
 
31
31
  spec.add_development_dependency 'bundler', '~> 2.0'
32
32
  spec.add_development_dependency 'rake', '~> 12.0'
@@ -67,7 +67,17 @@ module GraphQL
67
67
  end
68
68
 
69
69
  def validate_as_shared(ctx, type, subschema_types_by_location)
70
- expected_fields = type.fields.keys.sort
70
+ expected_fields = begin
71
+ type.fields.keys.sort
72
+ rescue StandardError => e
73
+ # bug with inherited interfaces in older versions of GraphQL
74
+ if type.interfaces.any? { _1.is_a?(GraphQL::Schema::LateBoundType) }
75
+ raise Composer::ComposerError, "Merged interface inheritance requires GraphQL >= v2.0.3"
76
+ else
77
+ raise e
78
+ end
79
+ end
80
+
71
81
  subschema_types_by_location.each do |location, subschema_type|
72
82
  if subschema_type.fields.keys.sort != expected_fields
73
83
  raise Composer::ValidationError, "Shared type `#{type.graphql_name}` must have consistent fields across locations,
@@ -96,7 +96,7 @@ module GraphQL
96
96
  end
97
97
  end
98
98
 
99
- # { "Type" => ["location1", "location2", ...] }
99
+ # "Type" => ["location1", "location2", ...]
100
100
  def locations_by_type
101
101
  @locations_by_type ||= @locations_by_type_and_field.each_with_object({}) do |(type_name, fields), memo|
102
102
  memo[type_name] = fields.values.flatten.uniq
@@ -104,7 +104,7 @@ module GraphQL
104
104
  end
105
105
 
106
106
  # collects all possible boundary keys for a given type
107
- # { "Type" => ["id", ...] }
107
+ # ("Type") => ["id", ...]
108
108
  def possible_keys_for_type(type_name)
109
109
  @possible_keys_by_type[type_name] ||= begin
110
110
  keys = @boundaries[type_name].map { _1["selection"] }
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GraphQL
4
4
  module Stitching
5
- VERSION = "0.2.2"
5
+ VERSION = "0.2.3"
6
6
  end
7
7
  end
@@ -19,6 +19,56 @@ module GraphQL
19
19
  def stitching_directive_names
20
20
  [stitch_directive]
21
21
  end
22
+
23
+ def schema_from_definition(sdl, stitch_directives:)
24
+ ast = GraphQL.parse(sdl)
25
+
26
+ if stitch_directives&.any?
27
+ directive_definition = ast.definitions.find do |d|
28
+ d.is_a?(GraphQL::Language::Nodes::DirectiveDefinition) && d.name == stitch_directive
29
+ end
30
+
31
+ if !directive_definition
32
+ directive_sdl = "directive @#{stitch_directive}(key: String!) repeatable on FIELD_DEFINITION"
33
+ directive_definition = GraphQL.parse(directive_sdl).definitions.first
34
+ ast.send(:merge!, { definitions: [directive_definition, *ast.definitions] })
35
+ end
36
+ end
37
+
38
+ stitch_directives.each do |config|
39
+ config[:type_name] ||= "Query"
40
+
41
+ type_node = ast.definitions.find do |d|
42
+ d.is_a?(GraphQL::Language::Nodes::ObjectTypeDefinition) && d.name == config[:type_name]
43
+ end
44
+
45
+ raise StitchingError, "invalid type name `#{config[:type_name]}`." unless type_node
46
+
47
+ field_node = type_node.fields.find do |f|
48
+ f.name == config[:field_name]
49
+ end
50
+
51
+ raise StitchingError, "invalid field name `#{config[:field_name]}`." unless field_node
52
+
53
+ field_node.send(:merge!, {
54
+ directives: [
55
+ *field_node.directives,
56
+ GraphQL::Language::Nodes::Directive.new(
57
+ arguments: [GraphQL::Language::Nodes::Argument.new(name: "key", value: config[:key])],
58
+ name: stitch_directive,
59
+ )
60
+ ]
61
+ })
62
+ end
63
+
64
+ if GraphQL::Schema::BuildFromDefinition.method(:from_document).parameters.first.last == :document
65
+ # GraphQL v1.13.x
66
+ GraphQL::Schema::BuildFromDefinition.from_document(ast, default_resolve: nil)
67
+ else
68
+ # GraphQL v2
69
+ GraphQL::Schema::BuildFromDefinition.from_document(GraphQL::Schema, ast, default_resolve: nil)
70
+ end
71
+ end
22
72
  end
23
73
  end
24
74
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-stitching
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg MacWilliam
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-21 00:00:00.000000000 Z
11
+ date: 2023-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 2.0.3
19
+ version: 1.13.9
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 2.0.3
26
+ version: 1.13.9
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement