graphql-stitching 1.3.0 → 1.4.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/README.md +57 -7
- data/docs/resolver.md +101 -0
- data/lib/graphql/stitching/client.rb +5 -1
- data/lib/graphql/stitching/composer/resolver_config.rb +17 -12
- data/lib/graphql/stitching/composer/validate_interfaces.rb +4 -4
- data/lib/graphql/stitching/composer/validate_resolvers.rb +23 -22
- data/lib/graphql/stitching/composer.rb +77 -83
- data/lib/graphql/stitching/executor/resolver_source.rb +25 -26
- data/lib/graphql/stitching/plan.rb +2 -3
- data/lib/graphql/stitching/planner.rb +11 -22
- data/lib/graphql/stitching/planner_step.rb +1 -1
- data/lib/graphql/stitching/resolver/arguments.rb +284 -0
- data/lib/graphql/stitching/resolver/keys.rb +206 -0
- data/lib/graphql/stitching/resolver.rb +44 -23
- data/lib/graphql/stitching/shaper.rb +3 -3
- data/lib/graphql/stitching/skip_include.rb +1 -1
- data/lib/graphql/stitching/supergraph/key_directive.rb +13 -0
- data/lib/graphql/stitching/supergraph/resolver_directive.rb +4 -5
- data/lib/graphql/stitching/supergraph/to_definition.rb +165 -0
- data/lib/graphql/stitching/supergraph.rb +13 -128
- data/lib/graphql/stitching/util.rb +28 -0
- data/lib/graphql/stitching/version.rb +1 -1
- data/lib/graphql/stitching.rb +2 -1
- metadata +7 -3
- data/lib/graphql/stitching/export_selection.rb +0 -42
@@ -0,0 +1,165 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "./key_directive"
|
3
|
+
require_relative "./resolver_directive"
|
4
|
+
require_relative "./source_directive"
|
5
|
+
|
6
|
+
module GraphQL::Stitching
|
7
|
+
class Supergraph
|
8
|
+
class << self
|
9
|
+
def validate_executable!(location, executable)
|
10
|
+
return true if executable.is_a?(Class) && executable <= GraphQL::Schema
|
11
|
+
return true if executable && executable.respond_to?(:call)
|
12
|
+
raise StitchingError, "Invalid executable provided for location `#{location}`."
|
13
|
+
end
|
14
|
+
|
15
|
+
def from_definition(schema, executables:)
|
16
|
+
schema = GraphQL::Schema.from_definition(schema) if schema.is_a?(String)
|
17
|
+
field_map = {}
|
18
|
+
resolver_map = {}
|
19
|
+
possible_locations = {}
|
20
|
+
introspection_types = schema.introspection_system.types.keys
|
21
|
+
|
22
|
+
schema.types.each do |type_name, type|
|
23
|
+
next if introspection_types.include?(type_name)
|
24
|
+
|
25
|
+
# Collect/build key definitions for each type
|
26
|
+
locations_by_key = type.directives.each_with_object({}) do |directive, memo|
|
27
|
+
next unless directive.graphql_name == KeyDirective.graphql_name
|
28
|
+
|
29
|
+
kwargs = directive.arguments.keyword_arguments
|
30
|
+
memo[kwargs[:key]] ||= []
|
31
|
+
memo[kwargs[:key]] << kwargs[:location]
|
32
|
+
end
|
33
|
+
|
34
|
+
key_definitions = locations_by_key.each_with_object({}) do |(key, locations), memo|
|
35
|
+
memo[key] = Resolver.parse_key(key, locations)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Collect/build resolver definitions for each type
|
39
|
+
type.directives.each do |directive|
|
40
|
+
next unless directive.graphql_name == ResolverDirective.graphql_name
|
41
|
+
|
42
|
+
kwargs = directive.arguments.keyword_arguments
|
43
|
+
resolver_map[type_name] ||= []
|
44
|
+
resolver_map[type_name] << Resolver.new(
|
45
|
+
location: kwargs[:location],
|
46
|
+
type_name: kwargs.fetch(:type_name, type_name),
|
47
|
+
field: kwargs[:field],
|
48
|
+
list: kwargs[:list] || false,
|
49
|
+
key: key_definitions[kwargs[:key]],
|
50
|
+
arguments: Resolver.parse_arguments_with_type_defs(kwargs[:arguments], kwargs[:argument_types]),
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
next unless type.kind.fields?
|
55
|
+
|
56
|
+
type.fields.each do |field_name, field|
|
57
|
+
# Collection locations for each field definition
|
58
|
+
field.directives.each do |d|
|
59
|
+
next unless d.graphql_name == SourceDirective.graphql_name
|
60
|
+
|
61
|
+
location = d.arguments.keyword_arguments[:location]
|
62
|
+
field_map[type_name] ||= {}
|
63
|
+
field_map[type_name][field_name] ||= []
|
64
|
+
field_map[type_name][field_name] << location
|
65
|
+
possible_locations[location] = true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
executables = possible_locations.keys.each_with_object({}) do |location, memo|
|
71
|
+
executable = executables[location] || executables[location.to_sym]
|
72
|
+
if validate_executable!(location, executable)
|
73
|
+
memo[location] = executable
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
new(
|
78
|
+
schema: schema,
|
79
|
+
fields: field_map,
|
80
|
+
resolvers: resolver_map,
|
81
|
+
executables: executables,
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_definition
|
87
|
+
if @schema.directives[KeyDirective.graphql_name].nil?
|
88
|
+
@schema.directive(KeyDirective)
|
89
|
+
end
|
90
|
+
if @schema.directives[ResolverDirective.graphql_name].nil?
|
91
|
+
@schema.directive(ResolverDirective)
|
92
|
+
end
|
93
|
+
if @schema.directives[SourceDirective.graphql_name].nil?
|
94
|
+
@schema.directive(SourceDirective)
|
95
|
+
end
|
96
|
+
|
97
|
+
@schema.types.each do |type_name, type|
|
98
|
+
if resolvers_for_type = @resolvers.dig(type_name)
|
99
|
+
# Apply key directives for each unique type/key/location
|
100
|
+
# (this allows keys to be composite selections and/or omitted from the supergraph schema)
|
101
|
+
keys_for_type = resolvers_for_type.each_with_object({}) do |resolver, memo|
|
102
|
+
memo[resolver.key.to_definition] ||= Set.new
|
103
|
+
memo[resolver.key.to_definition].merge(resolver.key.locations)
|
104
|
+
end
|
105
|
+
|
106
|
+
keys_for_type.each do |key, locations|
|
107
|
+
locations.each do |location|
|
108
|
+
params = { key: key, location: location }
|
109
|
+
|
110
|
+
unless has_directive?(type, KeyDirective.graphql_name, params)
|
111
|
+
type.directive(KeyDirective, **params)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Apply resolver directives for each unique query resolver
|
117
|
+
resolvers_for_type.each do |resolver|
|
118
|
+
params = {
|
119
|
+
location: resolver.location,
|
120
|
+
field: resolver.field,
|
121
|
+
list: resolver.list? || nil,
|
122
|
+
key: resolver.key.to_definition,
|
123
|
+
arguments: resolver.arguments.map(&:to_definition).join(", "),
|
124
|
+
argument_types: resolver.arguments.map(&:to_type_definition).join(", "),
|
125
|
+
type_name: (resolver.type_name if resolver.type_name != type_name),
|
126
|
+
}
|
127
|
+
|
128
|
+
unless has_directive?(type, ResolverDirective.graphql_name, params)
|
129
|
+
type.directive(ResolverDirective, **params.tap(&:compact!))
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
next unless type.kind.fields?
|
135
|
+
|
136
|
+
type.fields.each do |field_name, field|
|
137
|
+
locations_for_field = @locations_by_type_and_field.dig(type_name, field_name)
|
138
|
+
next if locations_for_field.nil?
|
139
|
+
|
140
|
+
# Apply source directives to annotate the possible locations of each field
|
141
|
+
locations_for_field.each do |location|
|
142
|
+
params = { location: location }
|
143
|
+
|
144
|
+
unless has_directive?(field, SourceDirective.graphql_name, params)
|
145
|
+
field.directive(SourceDirective, **params)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
@schema.to_definition
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def has_directive?(element, directive_name, params)
|
157
|
+
existing = element.directives.find do |d|
|
158
|
+
kwargs = d.arguments.keyword_arguments
|
159
|
+
d.graphql_name == directive_name && params.all? { |k, v| kwargs[k] == v }
|
160
|
+
end
|
161
|
+
|
162
|
+
!existing.nil?
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -1,78 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "./supergraph/
|
4
|
-
require_relative "./supergraph/source_directive"
|
3
|
+
require_relative "./supergraph/to_definition"
|
5
4
|
|
6
5
|
module GraphQL
|
7
6
|
module Stitching
|
8
7
|
class Supergraph
|
9
8
|
SUPERGRAPH_LOCATION = "__super"
|
10
9
|
|
11
|
-
class << self
|
12
|
-
def validate_executable!(location, executable)
|
13
|
-
return true if executable.is_a?(Class) && executable <= GraphQL::Schema
|
14
|
-
return true if executable && executable.respond_to?(:call)
|
15
|
-
raise StitchingError, "Invalid executable provided for location `#{location}`."
|
16
|
-
end
|
17
|
-
|
18
|
-
def from_definition(schema, executables:)
|
19
|
-
schema = GraphQL::Schema.from_definition(schema) if schema.is_a?(String)
|
20
|
-
field_map = {}
|
21
|
-
resolver_map = {}
|
22
|
-
possible_locations = {}
|
23
|
-
introspection_types = schema.introspection_system.types.keys
|
24
|
-
|
25
|
-
schema.types.each do |type_name, type|
|
26
|
-
next if introspection_types.include?(type_name)
|
27
|
-
|
28
|
-
type.directives.each do |directive|
|
29
|
-
next unless directive.graphql_name == ResolverDirective.graphql_name
|
30
|
-
|
31
|
-
kwargs = directive.arguments.keyword_arguments
|
32
|
-
resolver_map[type_name] ||= []
|
33
|
-
resolver_map[type_name] << Resolver.new(
|
34
|
-
type_name: kwargs.fetch(:type_name, type_name),
|
35
|
-
location: kwargs[:location],
|
36
|
-
key: kwargs[:key],
|
37
|
-
field: kwargs[:field],
|
38
|
-
list: kwargs[:list] || false,
|
39
|
-
arg: kwargs[:arg],
|
40
|
-
arg_type_name: kwargs[:arg_type_name],
|
41
|
-
representations: kwargs[:representations] || false,
|
42
|
-
)
|
43
|
-
end
|
44
|
-
|
45
|
-
next unless type.kind.fields?
|
46
|
-
|
47
|
-
type.fields.each do |field_name, field|
|
48
|
-
field.directives.each do |d|
|
49
|
-
next unless d.graphql_name == SourceDirective.graphql_name
|
50
|
-
|
51
|
-
location = d.arguments.keyword_arguments[:location]
|
52
|
-
field_map[type_name] ||= {}
|
53
|
-
field_map[type_name][field_name] ||= []
|
54
|
-
field_map[type_name][field_name] << location
|
55
|
-
possible_locations[location] = true
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
executables = possible_locations.keys.each_with_object({}) do |location, memo|
|
61
|
-
executable = executables[location] || executables[location.to_sym]
|
62
|
-
if validate_executable!(location, executable)
|
63
|
-
memo[location] = executable
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
new(
|
68
|
-
schema: schema,
|
69
|
-
fields: field_map,
|
70
|
-
resolvers: resolver_map,
|
71
|
-
executables: executables,
|
72
|
-
)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
10
|
# @return [GraphQL::Schema] the composed schema for the supergraph.
|
77
11
|
attr_reader :schema
|
78
12
|
|
@@ -86,6 +20,7 @@ module GraphQL
|
|
86
20
|
@schema.use(GraphQL::Schema::AlwaysVisible)
|
87
21
|
|
88
22
|
@resolvers = resolvers
|
23
|
+
@resolvers_by_version = nil
|
89
24
|
@fields_by_type_and_location = nil
|
90
25
|
@locations_by_type = nil
|
91
26
|
@memoized_introspection_types = nil
|
@@ -112,66 +47,17 @@ module GraphQL
|
|
112
47
|
end.freeze
|
113
48
|
end
|
114
49
|
|
115
|
-
def to_definition
|
116
|
-
if @schema.directives[ResolverDirective.graphql_name].nil?
|
117
|
-
@schema.directive(ResolverDirective)
|
118
|
-
end
|
119
|
-
if @schema.directives[SourceDirective.graphql_name].nil?
|
120
|
-
@schema.directive(SourceDirective)
|
121
|
-
end
|
122
|
-
|
123
|
-
@schema.types.each do |type_name, type|
|
124
|
-
if resolvers_for_type = @resolvers.dig(type_name)
|
125
|
-
resolvers_for_type.each do |resolver|
|
126
|
-
existing = type.directives.find do |d|
|
127
|
-
kwargs = d.arguments.keyword_arguments
|
128
|
-
d.graphql_name == ResolverDirective.graphql_name &&
|
129
|
-
kwargs[:location] == resolver.location &&
|
130
|
-
kwargs[:key] == resolver.key &&
|
131
|
-
kwargs[:field] == resolver.field &&
|
132
|
-
kwargs[:arg] == resolver.arg &&
|
133
|
-
kwargs.fetch(:list, false) == resolver.list &&
|
134
|
-
kwargs.fetch(:representations, false) == resolver.representations
|
135
|
-
end
|
136
|
-
|
137
|
-
type.directive(ResolverDirective, **{
|
138
|
-
type_name: (resolver.type_name if resolver.type_name != type_name),
|
139
|
-
location: resolver.location,
|
140
|
-
key: resolver.key,
|
141
|
-
field: resolver.field,
|
142
|
-
list: resolver.list || nil,
|
143
|
-
arg: resolver.arg,
|
144
|
-
arg_type_name: resolver.arg_type_name,
|
145
|
-
representations: resolver.representations || nil,
|
146
|
-
}.tap(&:compact!)) if existing.nil?
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
next unless type.kind.fields?
|
151
|
-
|
152
|
-
type.fields.each do |field_name, field|
|
153
|
-
locations_for_field = @locations_by_type_and_field.dig(type_name, field_name)
|
154
|
-
next if locations_for_field.nil?
|
155
|
-
|
156
|
-
locations_for_field.each do |location|
|
157
|
-
existing = field.directives.find do |d|
|
158
|
-
d.graphql_name == SourceDirective.graphql_name &&
|
159
|
-
d.arguments.keyword_arguments[:location] == location
|
160
|
-
end
|
161
|
-
|
162
|
-
field.directive(SourceDirective, location: location) if existing.nil?
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
@schema.to_definition
|
168
|
-
end
|
169
|
-
|
170
50
|
# @return [GraphQL::StaticValidation::Validator] static validator for the supergraph schema.
|
171
51
|
def static_validator
|
172
52
|
@static_validator ||= @schema.static_validator
|
173
53
|
end
|
174
54
|
|
55
|
+
def resolvers_by_version
|
56
|
+
@resolvers_by_version ||= resolvers.values.tap(&:flatten!).each_with_object({}) do |resolver, memo|
|
57
|
+
memo[resolver.version] = resolver
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
175
61
|
def fields
|
176
62
|
@locations_by_type_and_field.reject { |k, _v| memoized_introspection_types[k] }
|
177
63
|
end
|
@@ -245,24 +131,23 @@ module GraphQL
|
|
245
131
|
end
|
246
132
|
|
247
133
|
# collects all possible resolver keys for a given type
|
248
|
-
# ("Type") => ["id", ...]
|
134
|
+
# ("Type") => [Key("id"), ...]
|
249
135
|
def possible_keys_for_type(type_name)
|
250
136
|
@possible_keys_by_type[type_name] ||= begin
|
251
137
|
if type_name == @schema.query.graphql_name
|
252
138
|
GraphQL::Stitching::EMPTY_ARRAY
|
253
139
|
else
|
254
|
-
@resolvers[type_name].map(&:key).
|
140
|
+
@resolvers[type_name].map(&:key).uniq(&:to_definition)
|
255
141
|
end
|
256
142
|
end
|
257
143
|
end
|
258
144
|
|
259
145
|
# collects possible resolver keys for a given type and location
|
260
|
-
# ("Type", "location") => ["id", ...]
|
146
|
+
# ("Type", "location") => [Key("id"), ...]
|
261
147
|
def possible_keys_for_type_and_location(type_name, location)
|
262
148
|
possible_keys_by_type = @possible_keys_by_type_and_location[type_name] ||= {}
|
263
|
-
possible_keys_by_type[location] ||=
|
264
|
-
|
265
|
-
location_fields & possible_keys_for_type(type_name)
|
149
|
+
possible_keys_by_type[location] ||= possible_keys_for_type(type_name).select do |key|
|
150
|
+
key.locations.include?(location)
|
266
151
|
end
|
267
152
|
end
|
268
153
|
|
@@ -47,6 +47,34 @@ module GraphQL
|
|
47
47
|
structure
|
48
48
|
end
|
49
49
|
|
50
|
+
# builds a single-dimensional representation of a wrapped type structure from AST
|
51
|
+
def flatten_ast_type_structure(ast, structure: [])
|
52
|
+
null = true
|
53
|
+
|
54
|
+
while ast.is_a?(GraphQL::Language::Nodes::NonNullType)
|
55
|
+
ast = ast.of_type
|
56
|
+
null = false
|
57
|
+
end
|
58
|
+
|
59
|
+
if ast.is_a?(GraphQL::Language::Nodes::ListType)
|
60
|
+
structure << TypeStructure.new(
|
61
|
+
list: true,
|
62
|
+
null: null,
|
63
|
+
name: nil,
|
64
|
+
)
|
65
|
+
|
66
|
+
flatten_ast_type_structure(ast.of_type, structure: structure)
|
67
|
+
else
|
68
|
+
structure << TypeStructure.new(
|
69
|
+
list: false,
|
70
|
+
null: null,
|
71
|
+
name: ast.name,
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
structure
|
76
|
+
end
|
77
|
+
|
50
78
|
# expands interfaces and unions to an array of their memberships
|
51
79
|
# like `schema.possible_types`, but includes child interfaces
|
52
80
|
def expand_abstract_type(schema, parent_type)
|
data/lib/graphql/stitching.rb
CHANGED
@@ -8,6 +8,8 @@ module GraphQL
|
|
8
8
|
EMPTY_ARRAY = [].freeze
|
9
9
|
|
10
10
|
class StitchingError < StandardError; end
|
11
|
+
class CompositionError < StitchingError; end
|
12
|
+
class ValidationError < CompositionError; end
|
11
13
|
|
12
14
|
class << self
|
13
15
|
def stitch_directive
|
@@ -28,7 +30,6 @@ require_relative "stitching/resolver"
|
|
28
30
|
require_relative "stitching/client"
|
29
31
|
require_relative "stitching/composer"
|
30
32
|
require_relative "stitching/executor"
|
31
|
-
require_relative "stitching/export_selection"
|
32
33
|
require_relative "stitching/http_executable"
|
33
34
|
require_relative "stitching/plan"
|
34
35
|
require_relative "stitching/planner_step"
|
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.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg MacWilliam
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-07-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -89,6 +89,7 @@ files:
|
|
89
89
|
- docs/images/stitching.png
|
90
90
|
- docs/mechanics.md
|
91
91
|
- docs/request.md
|
92
|
+
- docs/resolver.md
|
92
93
|
- docs/supergraph.md
|
93
94
|
- examples/file_uploads/Gemfile
|
94
95
|
- examples/file_uploads/Procfile
|
@@ -119,18 +120,21 @@ files:
|
|
119
120
|
- lib/graphql/stitching/executor.rb
|
120
121
|
- lib/graphql/stitching/executor/resolver_source.rb
|
121
122
|
- lib/graphql/stitching/executor/root_source.rb
|
122
|
-
- lib/graphql/stitching/export_selection.rb
|
123
123
|
- lib/graphql/stitching/http_executable.rb
|
124
124
|
- lib/graphql/stitching/plan.rb
|
125
125
|
- lib/graphql/stitching/planner.rb
|
126
126
|
- lib/graphql/stitching/planner_step.rb
|
127
127
|
- lib/graphql/stitching/request.rb
|
128
128
|
- lib/graphql/stitching/resolver.rb
|
129
|
+
- lib/graphql/stitching/resolver/arguments.rb
|
130
|
+
- lib/graphql/stitching/resolver/keys.rb
|
129
131
|
- lib/graphql/stitching/shaper.rb
|
130
132
|
- lib/graphql/stitching/skip_include.rb
|
131
133
|
- lib/graphql/stitching/supergraph.rb
|
134
|
+
- lib/graphql/stitching/supergraph/key_directive.rb
|
132
135
|
- lib/graphql/stitching/supergraph/resolver_directive.rb
|
133
136
|
- lib/graphql/stitching/supergraph/source_directive.rb
|
137
|
+
- lib/graphql/stitching/supergraph/to_definition.rb
|
134
138
|
- lib/graphql/stitching/util.rb
|
135
139
|
- lib/graphql/stitching/version.rb
|
136
140
|
homepage: https://github.com/gmac/graphql-stitching-ruby
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module GraphQL
|
4
|
-
module Stitching
|
5
|
-
# Builds hidden selection fields added by stitiching code,
|
6
|
-
# used to request operational data about resolved objects.
|
7
|
-
class ExportSelection
|
8
|
-
EXPORT_PREFIX = "_export_"
|
9
|
-
|
10
|
-
class << self
|
11
|
-
@typename_node = nil
|
12
|
-
|
13
|
-
def key?(name)
|
14
|
-
return false unless name
|
15
|
-
|
16
|
-
name.start_with?(EXPORT_PREFIX)
|
17
|
-
end
|
18
|
-
|
19
|
-
def key(name)
|
20
|
-
"#{EXPORT_PREFIX}#{name}"
|
21
|
-
end
|
22
|
-
|
23
|
-
# The argument assigning Field.alias changed from
|
24
|
-
# a generic `alias` hash key to a structured `field_alias` kwarg.
|
25
|
-
# See https://github.com/rmosolgo/graphql-ruby/pull/4718
|
26
|
-
FIELD_ALIAS_KWARG = !GraphQL::Language::Nodes::Field.new(field_alias: "a").alias.nil?
|
27
|
-
|
28
|
-
def key_node(field_name)
|
29
|
-
if FIELD_ALIAS_KWARG
|
30
|
-
GraphQL::Language::Nodes::Field.new(field_alias: key(field_name), name: field_name)
|
31
|
-
else
|
32
|
-
GraphQL::Language::Nodes::Field.new(alias: key(field_name), name: field_name)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def typename_node
|
37
|
-
@typename_node ||= key_node("__typename")
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|