Skip to content

Commit 77b8d12

Browse files
authored
[Fusion] Added merging of implemented interfaces (#7999)
1 parent 0038250 commit 77b8d12

File tree

4 files changed

+199
-2
lines changed

4 files changed

+199
-2
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
using HotChocolate.Skimmed;
2+
3+
namespace HotChocolate.Fusion.Info;
4+
5+
internal record InterfaceInfo(InterfaceTypeDefinition InterfaceType, SchemaDefinition Schema);

src/HotChocolate/Fusion-vnext/src/Fusion.Composition/SourceSchemaMerger.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,12 +359,28 @@ private InterfaceTypeDefinition MergeInterfaceTypes(
359359

360360
interfaceType.Description = description;
361361

362+
// [InterfaceName: [{InterfaceType, Schema}, ...], ...].
363+
var interfaceGroupByName = typeGroup
364+
.SelectMany(
365+
i => ((InterfaceTypeDefinition)i.Type).Implements,
366+
(i, it) => new InterfaceInfo(it, i.Schema))
367+
.GroupBy(i => i.InterfaceType.Name)
368+
.Where(g => !g.Any(i => i.InterfaceType.HasInaccessibleDirective()))
369+
.ToArray();
370+
371+
foreach (var (interfaceName, _) in interfaceGroupByName)
372+
{
373+
interfaceType.Implements.Add(
374+
GetOrCreateType<InterfaceTypeDefinition>(mergedSchema, interfaceName));
375+
}
376+
362377
if (typeGroup.Any(i => i.Type.HasInaccessibleDirective()))
363378
{
364379
interfaceType.Directives.Add(new Directive(new InaccessibleDirectiveDefinition()));
365380
}
366381

367382
AddFusionTypeDirectives(interfaceType, typeGroup);
383+
AddFusionImplementsDirectives(interfaceType, [.. interfaceGroupByName.SelectMany(g => g)]);
368384

369385
// [FieldName: [{Field, Type, Schema}, ...], ...].
370386
var fieldGroupByName = typeGroup
@@ -418,12 +434,28 @@ private InterfaceTypeDefinition MergeInterfaceTypes(
418434

419435
objectType.Description = description;
420436

437+
// [InterfaceName: [{InterfaceType, Schema}, ...], ...].
438+
var interfaceGroupByName = typeGroup
439+
.SelectMany(
440+
i => ((ObjectTypeDefinition)i.Type).Implements,
441+
(i, it) => new InterfaceInfo(it, i.Schema))
442+
.GroupBy(i => i.InterfaceType.Name)
443+
.Where(g => !g.Any(i => i.InterfaceType.HasInaccessibleDirective()))
444+
.ToArray();
445+
446+
foreach (var (interfaceName, _) in interfaceGroupByName)
447+
{
448+
objectType.Implements.Add(
449+
GetOrCreateType<InterfaceTypeDefinition>(mergedSchema, interfaceName));
450+
}
451+
421452
if (typeGroup.Any(i => i.Type.HasInaccessibleDirective()))
422453
{
423454
objectType.Directives.Add(new Directive(new InaccessibleDirectiveDefinition()));
424455
}
425456

426457
AddFusionTypeDirectives(objectType, typeGroup);
458+
AddFusionImplementsDirectives(objectType, [.. interfaceGroupByName.SelectMany(g => g)]);
427459

428460
// [FieldName: [{Field, Type, Schema}, ...], ...].
429461
var fieldGroupByName = typeGroup
@@ -812,6 +844,22 @@ private void AddFusionFieldDirectives(
812844
}
813845
}
814846

847+
private void AddFusionImplementsDirectives(
848+
ComplexTypeDefinition complexType,
849+
ImmutableArray<InterfaceInfo> interfaceGroup)
850+
{
851+
foreach (var (sourceInterface, sourceSchema) in interfaceGroup)
852+
{
853+
complexType.Directives.Add(
854+
new Directive(
855+
_fusionDirectiveDefinitions[DirectiveNames.FusionImplements],
856+
new ArgumentAssignment(
857+
ArgumentNames.Schema,
858+
new EnumValueNode(_schemaConstantNames[sourceSchema])),
859+
new ArgumentAssignment(ArgumentNames.Interface, sourceInterface.Name)));
860+
}
861+
}
862+
815863
private void AddFusionInputFieldDirectives(
816864
InputFieldDefinition argument,
817865
ImmutableArray<FieldArgumentInfo> argumentGroup)

src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/SourceSchemaMerger.Interface.Tests.cs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,77 @@ interface Product
123123
}
124124
"""
125125
},
126+
// Implemented interfaces. I2 is inaccessible.
127+
{
128+
[
129+
"""
130+
# Schema A
131+
interface I1 {
132+
id: ID!
133+
}
134+
135+
interface I2 {
136+
id: ID!
137+
}
138+
139+
interface Product implements I1 & I2 {
140+
id: ID!
141+
}
142+
""",
143+
"""
144+
interface I1 {
145+
id: ID!
146+
}
147+
148+
interface I2 @inaccessible {
149+
id: ID!
150+
}
151+
152+
interface I3 {
153+
id: ID!
154+
}
155+
156+
interface Product implements I1 & I2 & I3 {
157+
id: ID!
158+
}
159+
"""
160+
],
161+
"""
162+
interface I1
163+
@fusion__type(schema: A)
164+
@fusion__type(schema: B) {
165+
id: ID!
166+
@fusion__field(schema: A)
167+
@fusion__field(schema: B)
168+
}
169+
170+
interface I2
171+
@inaccessible
172+
@fusion__type(schema: A)
173+
@fusion__type(schema: B) {
174+
id: ID!
175+
@fusion__field(schema: A)
176+
@fusion__field(schema: B)
177+
}
178+
179+
interface I3
180+
@fusion__type(schema: B) {
181+
id: ID!
182+
@fusion__field(schema: B)
183+
}
184+
185+
interface Product implements I1 & I3
186+
@fusion__type(schema: A)
187+
@fusion__type(schema: B)
188+
@fusion__implements(schema: A, interface: "I1")
189+
@fusion__implements(schema: B, interface: "I1")
190+
@fusion__implements(schema: B, interface: "I3") {
191+
id: ID!
192+
@fusion__field(schema: A)
193+
@fusion__field(schema: B)
194+
}
195+
"""
196+
},
126197
// @lookup
127198
{
128199
[
@@ -201,8 +272,9 @@ type Query
201272
@fusion__field(schema: A)
202273
}
203274
204-
type Cat
275+
type Cat implements Animal
205276
@fusion__type(schema: A)
277+
@fusion__implements(schema: A, interface: "Animal")
206278
@fusion__lookup(schema: A, key: "id", field: "catById(id: ID!): Cat", map: [ "id" ], path: "animalById") {
207279
catById(id: ID!
208280
@fusion__inputField(schema: A)): Cat
@@ -211,8 +283,9 @@ type Cat
211283
@fusion__field(schema: A)
212284
}
213285
214-
type Dog
286+
type Dog implements Animal
215287
@fusion__type(schema: A)
288+
@fusion__implements(schema: A, interface: "Animal")
216289
@fusion__lookup(schema: A, key: "id", field: "dogById(id: ID!): Dog", map: [ "id" ], path: "animalById") {
217290
dogById(id: ID!
218291
@fusion__inputField(schema: A)): Dog

src/HotChocolate/Fusion-vnext/test/Fusion.Composition.Tests/SourceSchemaMerger.Object.Tests.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,77 @@ type Product
155155
}
156156
"""
157157
},
158+
// Implemented interfaces. I2 is inaccessible.
159+
{
160+
[
161+
"""
162+
# Schema A
163+
interface I1 {
164+
id: ID!
165+
}
166+
167+
interface I2 {
168+
id: ID!
169+
}
170+
171+
type Product implements I1 & I2 {
172+
id: ID!
173+
}
174+
""",
175+
"""
176+
interface I1 {
177+
id: ID!
178+
}
179+
180+
interface I2 @inaccessible {
181+
id: ID!
182+
}
183+
184+
interface I3 {
185+
id: ID!
186+
}
187+
188+
type Product implements I1 & I2 & I3 {
189+
id: ID!
190+
}
191+
"""
192+
],
193+
"""
194+
type Product implements I1 & I3
195+
@fusion__type(schema: A)
196+
@fusion__type(schema: B)
197+
@fusion__implements(schema: A, interface: "I1")
198+
@fusion__implements(schema: B, interface: "I1")
199+
@fusion__implements(schema: B, interface: "I3") {
200+
id: ID!
201+
@fusion__field(schema: A)
202+
@fusion__field(schema: B)
203+
}
204+
205+
interface I1
206+
@fusion__type(schema: A)
207+
@fusion__type(schema: B) {
208+
id: ID!
209+
@fusion__field(schema: A)
210+
@fusion__field(schema: B)
211+
}
212+
213+
interface I2
214+
@inaccessible
215+
@fusion__type(schema: A)
216+
@fusion__type(schema: B) {
217+
id: ID!
218+
@fusion__field(schema: A)
219+
@fusion__field(schema: B)
220+
}
221+
222+
interface I3
223+
@fusion__type(schema: B) {
224+
id: ID!
225+
@fusion__field(schema: B)
226+
}
227+
"""
228+
},
158229
// @lookup
159230
{
160231
[

0 commit comments

Comments
 (0)