graphql-stitching 1.0.4 → 1.0.5

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: ccc67e1b52f1a0688d25958d1955580c7f88a8115dc6b6b6905f785da94089db
4
- data.tar.gz: 8e0925fb1ad0584bce11672be24868dc261cf680f8f88acdff87a7ca3819d9f8
3
+ metadata.gz: 2d90338dfde5c26515a55afdee7f5bd936a4563b2b8f83e1ffc1a4420c56a5cf
4
+ data.tar.gz: d728c5dfabb5e0250c38a6718ac7b535cfa7a183872dc60fa95a9b91b777a64a
5
5
  SHA512:
6
- metadata.gz: 9213dbd90d0fc0caf10a09b9ba68bfbfe072c3cce9d51c47623b0d5edabb9bfe1eac849fb3135bade04863c2ca9b62c42c2f67b469f1fc268f039fab15f17372
7
- data.tar.gz: c62c51fda4c9210ba71c9be894e7a31fe3346c0e4d49ac57632efa32b8db9809174b6d0fb048eddc1437584c57d7f2bd748e4fab3f1e1440c2d5c6f3647657dd
6
+ metadata.gz: cc5ff912f354e08b9f204028d5e6eed85a81bf283bd5dc13bb7ee9b69b83d0bb39ba83f9fbaac66be1363e86ce3f6bd1b3f7cc4466ef83998a751e3dbccf9013
7
+ data.tar.gz: 055e1c09f88e8f893a3ebb0aa3d7558156ec5c4a33b704cca69499efee4fd02e3a70e6efedeca1332f92392c7093ea8024ba9aefb159ce77b4f11510cd8d7a1c
data/docs/composer.md CHANGED
@@ -12,6 +12,7 @@ composer = GraphQL::Stitching::Composer.new(
12
12
  mutation_name: "Mutation",
13
13
  description_merger: ->(values_by_location, info) { values_by_location.values.join("\n") },
14
14
  deprecation_merger: ->(values_by_location, info) { values_by_location.values.first },
15
+ default_value_merger: ->(values_by_location, info) { values_by_location.values.first },
15
16
  directive_kwarg_merger: ->(values_by_location, info) { values_by_location.values.last },
16
17
  root_field_location_selector: ->(locations, info) { locations.last },
17
18
  )
@@ -27,6 +28,8 @@ Constructor arguments:
27
28
 
28
29
  - **`deprecation_merger:`** _optional_, a [value merger function](#value-merger-functions) for merging element deprecation strings from across locations.
29
30
 
31
+ - **`default_value_merger:`** _optional_, a [value merger function](#value-merger-functions) for merging argument default values from across locations.
32
+
30
33
  - **`directive_kwarg_merger:`** _optional_, a [value merger function](#value-merger-functions) for merging directive keyword arguments from across locations.
31
34
 
32
35
  - **`root_field_location_selector:`** _optional_, selects a default routing location for root fields with multiple locations. Use this to prioritize sending root fields to their primary data sources (only applies while routing the root operation scope). This handler receives an array of possible locations and an info object with field information, and should return the prioritized location. The last location is used by default.
data/docs/executor.md CHANGED
@@ -50,8 +50,8 @@ The raw result will contain many irregularities from the stitching process, howe
50
50
  "data" => {
51
51
  "product" => {
52
52
  "upc" => "1",
53
- "_STITCH_upc" => "1",
54
- "_STITCH_typename" => "Product",
53
+ "_export_upc" => "1",
54
+ "_export_typename" => "Product",
55
55
  "name" => "iPhone",
56
56
  "price" => nil,
57
57
  }
@@ -5,9 +5,13 @@ module GraphQL
5
5
  class Composer
6
6
  class ComposerError < StitchingError; end
7
7
  class ValidationError < ComposerError; end
8
+ class ReferenceType < GraphQL::Schema::Object
9
+ field(:f, String) do
10
+ argument(:a, String)
11
+ end
12
+ end
8
13
 
9
- attr_reader :query_name, :mutation_name, :candidate_types_by_name_and_location, :schema_directives
10
-
14
+ NO_DEFAULT_VALUE = ReferenceType.get_field("f").get_argument("a").default_value
11
15
  BASIC_VALUE_MERGER = ->(values_by_location, _info) { values_by_location.values.find { !_1.nil? } }
12
16
  BASIC_ROOT_FIELD_LOCATION_SELECTOR = ->(locations, _info) { locations.last }
13
17
 
@@ -16,6 +20,8 @@ module GraphQL
16
20
  "ValidateBoundaries",
17
21
  ].freeze
18
22
 
23
+ attr_reader :query_name, :mutation_name, :candidate_types_by_name_and_location, :schema_directives
24
+
19
25
  def initialize(
20
26
  query_name: "Query",
21
27
  mutation_name: "Mutation",
@@ -195,7 +201,7 @@ module GraphQL
195
201
  description(builder.merge_descriptions(directive_name, directives_by_location))
196
202
  repeatable(directives_by_location.values.any?(&:repeatable?))
197
203
  locations(*directives_by_location.values.flat_map(&:locations).uniq)
198
- builder.build_merged_arguments(directive_name, directives_by_location, self)
204
+ builder.build_merged_arguments(directive_name, directives_by_location, self, directive_name: directive_name)
199
205
  end
200
206
  end
201
207
 
@@ -343,7 +349,7 @@ module GraphQL
343
349
  end
344
350
  end
345
351
 
346
- def build_merged_arguments(type_name, members_by_location, owner, field_name: nil)
352
+ def build_merged_arguments(type_name, members_by_location, owner, field_name: nil, directive_name: nil)
347
353
  # "argument_name" => "location" => argument
348
354
  args_by_name_location = members_by_location.each_with_object({}) do |(location, member_candidate), memo|
349
355
  member_candidate.arguments.each do |argument_name, argument|
@@ -369,7 +375,7 @@ module GraphQL
369
375
 
370
376
  kwargs = {}
371
377
  default_values_by_location = arguments_by_location.each_with_object({}) do |(location, argument), memo|
372
- next if argument.default_value.class == Object # << pass on NOT_CONFIGURED (todo: improve this check)
378
+ next if argument.default_value == NO_DEFAULT_VALUE
373
379
  memo[location] = argument.default_value
374
380
  end
375
381
 
@@ -378,7 +384,8 @@ module GraphQL
378
384
  type_name: type_name,
379
385
  field_name: field_name,
380
386
  argument_name: argument_name,
381
- })
387
+ directive_name: directive_name,
388
+ }.tap(&:compact!))
382
389
  end
383
390
 
384
391
  type = merge_value_types(type_name, value_types, argument_name: argument_name, field_name: field_name)
@@ -430,7 +437,7 @@ module GraphQL
430
437
  enum_value: enum_value,
431
438
  directive_name: directive_name,
432
439
  kwarg_name: kwarg_name,
433
- }.compact!)
440
+ }.tap(&:compact!))
434
441
  end
435
442
 
436
443
  owner.directive(directive_class, **kwargs)
@@ -438,7 +445,7 @@ module GraphQL
438
445
  end
439
446
 
440
447
  def merge_value_types(type_name, type_candidates, field_name: nil, argument_name: nil)
441
- path = [type_name, field_name, argument_name].compact.join(".")
448
+ path = [type_name, field_name, argument_name].tap(&:compact!).join(".")
442
449
  alt_structures = type_candidates.map { Util.flatten_type_structure(_1) }
443
450
  basis_structure = alt_structures.shift
444
451
 
@@ -475,7 +482,7 @@ module GraphQL
475
482
  field_name: field_name,
476
483
  argument_name: argument_name,
477
484
  enum_value: enum_value,
478
- }.compact!)
485
+ }.tap(&:compact!))
479
486
  end
480
487
 
481
488
  def merge_deprecations(type_name, members_by_location, field_name: nil, argument_name: nil, enum_value: nil)
@@ -485,7 +492,7 @@ module GraphQL
485
492
  field_name: field_name,
486
493
  argument_name: argument_name,
487
494
  enum_value: enum_value,
488
- }.compact!)
495
+ }.tap(&:compact!))
489
496
  end
490
497
 
491
498
  def extract_boundaries(type_name, types_by_location)
@@ -16,7 +16,7 @@ module GraphQL
16
16
 
17
17
  if op.if_type
18
18
  # operations planned around unused fragment conditions should not trigger requests
19
- origin_set.select! { _1[SelectionHint.typename_node.alias] == op.if_type }
19
+ origin_set.select! { _1[ExportSelection.typename_node.alias] == op.if_type }
20
20
  end
21
21
 
22
22
  memo[op] = origin_set if origin_set.any?
@@ -94,9 +94,9 @@ module GraphQL
94
94
  end
95
95
 
96
96
  def build_key(key, origin_obj, federation: false)
97
- key_value = JSON.generate(origin_obj[SelectionHint.key(key)])
97
+ key_value = JSON.generate(origin_obj[ExportSelection.key(key)])
98
98
  if federation
99
- "{ __typename: \"#{origin_obj[SelectionHint.typename_node.alias]}\", #{key}: #{key_value} }"
99
+ "{ __typename: \"#{origin_obj[ExportSelection.typename_node.alias]}\", #{key}: #{key_value} }"
100
100
  else
101
101
  key_value
102
102
  end
@@ -4,18 +4,18 @@ module GraphQL
4
4
  module Stitching
5
5
  # Builds hidden selection fields added by stitiching code,
6
6
  # used to request operational data about resolved objects.
7
- class SelectionHint
8
- HINT_PREFIX = "_STITCH_"
7
+ class ExportSelection
8
+ EXPORT_PREFIX = "_export_"
9
9
 
10
10
  class << self
11
11
  def key?(name)
12
12
  return false unless name
13
13
 
14
- name.start_with?(HINT_PREFIX)
14
+ name.start_with?(EXPORT_PREFIX)
15
15
  end
16
16
 
17
17
  def key(name)
18
- "#{HINT_PREFIX}#{name}"
18
+ "#{EXPORT_PREFIX}#{name}"
19
19
  end
20
20
 
21
21
  def key_node(field_name)
@@ -42,7 +42,7 @@ module GraphQL
42
42
  # Adjoining selections not available here get split off into new entrypoints (C).
43
43
  # B.3) Collect all variable definitions used within the filtered selection.
44
44
  # These specify which request variables to pass along with each step.
45
- # B.4) Add a `__typename` hint to abstracts and types that implement fragments.
45
+ # B.4) Add a `__typename` export to abstracts and types that implement fragments.
46
46
  # This provides resolved type information used during execution.
47
47
  #
48
48
  # C) Delegate adjoining selections to new entrypoint locations.
@@ -199,7 +199,9 @@ module GraphQL
199
199
  input_selections.each do |node|
200
200
  case node
201
201
  when GraphQL::Language::Nodes::Field
202
- if node.name == TYPENAME
202
+ if node.alias&.start_with?(ExportSelection::EXPORT_PREFIX)
203
+ raise StitchingError, %(Alias "#{node.alias}" is not allowed because "#{ExportSelection::EXPORT_PREFIX}" is a reserved prefix.)
204
+ elsif node.name == TYPENAME
203
205
  locale_selections << node
204
206
  next
205
207
  end
@@ -257,10 +259,10 @@ module GraphQL
257
259
  end
258
260
  end
259
261
 
260
- # B.4) Add a `__typename` hint to abstracts and types that implement
262
+ # B.4) Add a `__typename` export to abstracts and types that implement
261
263
  # fragments so that resolved type information is available during execution.
262
264
  if requires_typename
263
- locale_selections << SelectionHint.typename_node
265
+ locale_selections << ExportSelection.typename_node
264
266
  end
265
267
 
266
268
  if remote_selections
@@ -274,18 +276,18 @@ module GraphQL
274
276
  routes.each_value do |route|
275
277
  route.reduce(locale_selections) do |parent_selections, boundary|
276
278
  # E.1) Add the key of each boundary query into the prior location's selection set.
277
- foreign_key = SelectionHint.key(boundary.key)
279
+ foreign_key = ExportSelection.key(boundary.key)
278
280
  has_key = false
279
281
  has_typename = false
280
282
 
281
283
  parent_selections.each do |node|
282
284
  next unless node.is_a?(GraphQL::Language::Nodes::Field)
283
285
  has_key ||= node.alias == foreign_key
284
- has_typename ||= node.alias == SelectionHint.typename_node.alias
286
+ has_typename ||= node.alias == ExportSelection.typename_node.alias
285
287
  end
286
288
 
287
- parent_selections << SelectionHint.key_node(boundary.key) unless has_key
288
- parent_selections << SelectionHint.typename_node unless has_typename
289
+ parent_selections << ExportSelection.key_node(boundary.key) unless has_key
290
+ parent_selections << ExportSelection.typename_node unless has_typename
289
291
 
290
292
  # E.2) Add a planner step for each new entrypoint location.
291
293
  add_step(
@@ -69,7 +69,7 @@ module GraphQL
69
69
 
70
70
  def prepare!
71
71
  operation.variables.each do |v|
72
- @variables[v.name] ||= v.default_value
72
+ @variables[v.name] = v.default_value if @variables[v.name].nil?
73
73
  end
74
74
 
75
75
  if @may_contain_runtime_directives
@@ -4,7 +4,7 @@
4
4
  module GraphQL
5
5
  module Stitching
6
6
  # Shapes the final results payload to the request selection and schema definition.
7
- # This eliminates unrequested selection hints and applies null bubbling.
7
+ # This eliminates unrequested export selections and applies null bubbling.
8
8
  class Shaper
9
9
  def initialize(supergraph:, request:)
10
10
  @supergraph = supergraph
@@ -21,8 +21,8 @@ module GraphQL
21
21
  def resolve_object_scope(raw_object, parent_type, selections, typename = nil)
22
22
  return nil if raw_object.nil?
23
23
 
24
- typename ||= raw_object[SelectionHint.typename_node.alias]
25
- raw_object.reject! { |key, _v| SelectionHint.key?(key) }
24
+ typename ||= raw_object[ExportSelection.typename_node.alias]
25
+ raw_object.reject! { |key, _v| ExportSelection.key?(key) }
26
26
 
27
27
  selections.each do |node|
28
28
  case node
@@ -35,7 +35,7 @@ module GraphQL
35
35
  end
36
36
 
37
37
  if filtered_selections.none?
38
- filtered_selections << SelectionHint.typename_node
38
+ filtered_selections << ExportSelection.typename_node
39
39
  end
40
40
 
41
41
  if changed
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GraphQL
4
4
  module Stitching
5
- VERSION = "1.0.4"
5
+ VERSION = "1.0.5"
6
6
  end
7
7
  end
@@ -28,12 +28,12 @@ require_relative "stitching/boundary"
28
28
  require_relative "stitching/client"
29
29
  require_relative "stitching/composer"
30
30
  require_relative "stitching/executor"
31
+ require_relative "stitching/export_selection"
31
32
  require_relative "stitching/http_executable"
32
33
  require_relative "stitching/plan"
33
34
  require_relative "stitching/planner_step"
34
35
  require_relative "stitching/planner"
35
36
  require_relative "stitching/request"
36
- require_relative "stitching/selection_hint"
37
37
  require_relative "stitching/shaper"
38
38
  require_relative "stitching/skip_include"
39
39
  require_relative "stitching/util"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-stitching
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
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-11-03 00:00:00.000000000 Z
11
+ date: 2023-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -106,12 +106,12 @@ files:
106
106
  - lib/graphql/stitching/executor.rb
107
107
  - lib/graphql/stitching/executor/boundary_source.rb
108
108
  - lib/graphql/stitching/executor/root_source.rb
109
+ - lib/graphql/stitching/export_selection.rb
109
110
  - lib/graphql/stitching/http_executable.rb
110
111
  - lib/graphql/stitching/plan.rb
111
112
  - lib/graphql/stitching/planner.rb
112
113
  - lib/graphql/stitching/planner_step.rb
113
114
  - lib/graphql/stitching/request.rb
114
- - lib/graphql/stitching/selection_hint.rb
115
115
  - lib/graphql/stitching/shaper.rb
116
116
  - lib/graphql/stitching/skip_include.rb
117
117
  - lib/graphql/stitching/supergraph.rb