Skip to content

Commit b5f7da0

Browse files
[Fusion] Only use non-internal lookups for node lookups (#8622)
1 parent 831eba2 commit b5f7da0

File tree

14 files changed

+394
-564
lines changed

14 files changed

+394
-564
lines changed

src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Extensions/DirectivesProviderExtensions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ internal static class DirectivesProviderExtensions
3131
return null;
3232
}
3333

34+
public static bool ExistsInSchema(this IDirectivesProvider type, string schemaName)
35+
{
36+
return type.Directives.AsEnumerable().Any(
37+
d =>
38+
d.Name == WellKnownDirectiveNames.FusionType
39+
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName);
40+
}
41+
3442
public static bool HasExternalDirective(this IDirectivesProvider type)
3543
{
3644
return type.Directives.ContainsName(WellKnownDirectiveNames.External);

src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Extensions/MutableObjectTypeDefinitionExtensions.cs

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using HotChocolate.Language;
2-
using HotChocolate.Types;
31
using HotChocolate.Types.Mutable;
42
using ArgumentNames = HotChocolate.Fusion.WellKnownArgumentNames;
53
using DirectiveNames = HotChocolate.Fusion.WellKnownDirectiveNames;
@@ -13,84 +11,6 @@ public static void ApplyShareableDirective(this MutableObjectTypeDefinition type
1311
type.Directives.Add(new Directive(new MutableDirectiveDefinition(DirectiveNames.Shareable)));
1412
}
1513

16-
public static bool ExistsInSchema(this MutableObjectTypeDefinition type, string schemaName)
17-
{
18-
return type.Directives.AsEnumerable().Any(
19-
d =>
20-
d.Name == DirectiveNames.FusionType
21-
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName);
22-
}
23-
24-
public static IEnumerable<IDirective> GetFusionLookupDirectives(
25-
this MutableObjectTypeDefinition type,
26-
string schemaName,
27-
IEnumerable<MutableUnionTypeDefinition> unionTypes)
28-
{
29-
var lookupDirectives =
30-
type.Directives
31-
.AsEnumerable()
32-
.Where(
33-
d =>
34-
d.Name == DirectiveNames.FusionLookup
35-
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName)
36-
.ToList();
37-
38-
// To use an abstract lookup, the type must exist in the source schema.
39-
// TODO: For abstract lookups we also need to validate that the type
40-
// is part of the abstract type's possible types in the specific source schema.
41-
if (type.ExistsInSchema(schemaName))
42-
{
43-
// Interface lookups.
44-
foreach (var interfaceType in type.Implements)
45-
{
46-
lookupDirectives.AddRange(
47-
interfaceType.Directives
48-
.AsEnumerable()
49-
.Where(d =>
50-
d.Name == DirectiveNames.FusionLookup
51-
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName));
52-
}
53-
54-
// Union lookups.
55-
foreach (var unionType in unionTypes)
56-
{
57-
lookupDirectives.AddRange(
58-
unionType.Directives
59-
.AsEnumerable()
60-
.Where(d =>
61-
d.Name == DirectiveNames.FusionLookup
62-
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName));
63-
}
64-
}
65-
66-
return lookupDirectives;
67-
}
68-
69-
public static IEnumerable<IDirective> GetFusionLookupDirectivesById(
70-
this MutableObjectTypeDefinition type,
71-
IEnumerable<MutableUnionTypeDefinition> unionTypes)
72-
{
73-
var lookups = new List<IDirective>();
74-
var sourceSchemaNames = type.Directives.AsEnumerable()
75-
.Where(d => d.Name == DirectiveNames.FusionType)
76-
.Select(d => (string)d.Arguments[ArgumentNames.Schema].Value!);
77-
unionTypes = unionTypes.ToList();
78-
79-
foreach (var sourceSchemaName in sourceSchemaNames)
80-
{
81-
foreach (var lookupDirective in type.GetFusionLookupDirectives(sourceSchemaName, unionTypes))
82-
{
83-
if (lookupDirective.Arguments[ArgumentNames.Map] is ListValueNode { Items.Count: 1 } mapArg
84-
&& mapArg.Items[0].Value?.Equals(ArgumentNames.Id) == true)
85-
{
86-
lookups.Add(lookupDirective);
87-
}
88-
}
89-
}
90-
91-
return lookups;
92-
}
93-
9414
public static bool HasInternalDirective(this MutableObjectTypeDefinition type)
9515
{
9616
return type.Directives.ContainsName(DirectiveNames.Internal);

src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Extensions/MutableSchemaDefinitionExtensions.cs

Lines changed: 120 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using System.Collections.Immutable;
2+
using System.Transactions;
3+
using HotChocolate.Language;
14
using HotChocolate.Types;
25
using HotChocolate.Types.Mutable;
36

@@ -25,10 +28,111 @@ public static bool IsRootOperationType(
2528
this MutableSchemaDefinition schema,
2629
MutableObjectTypeDefinition type)
2730
{
28-
return
29-
schema.QueryType == type
30-
|| schema.MutationType == type
31-
|| schema.SubscriptionType == type;
31+
return schema.QueryType == type || schema.MutationType == type || schema.SubscriptionType == type;
32+
}
33+
34+
public static List<IDirective> GetPossibleFusionLookupDirectives(
35+
this MutableSchemaDefinition schema,
36+
MutableComplexTypeDefinition type,
37+
string? schemaName = null)
38+
{
39+
if (!string.IsNullOrEmpty(schemaName) && !type.ExistsInSchema(schemaName))
40+
{
41+
return [];
42+
}
43+
44+
// Get the lookups directly on the requested type.
45+
var lookups = GetFusionLookupDirectives(type, schemaName);
46+
47+
// Get the lookups of interfaces this type implements.
48+
var implementsDirectives = type.Directives
49+
.AsEnumerable()
50+
.Where(d => d.Name == WellKnownDirectiveNames.FusionImplements)
51+
.ToImmutableArray();
52+
53+
foreach (var implementsDirective in implementsDirectives)
54+
{
55+
var implementedInSchemaName = (string)implementsDirective.Arguments[WellKnownArgumentNames.Schema].Value!;
56+
57+
if (!string.IsNullOrEmpty(schemaName) && implementedInSchemaName != schemaName)
58+
{
59+
continue;
60+
}
61+
62+
var interfaceName = (string)implementsDirective.Arguments[WellKnownArgumentNames.Interface].Value!;
63+
64+
if (!schema.Types.TryGetType<MutableInterfaceTypeDefinition>(interfaceName, out var interfaceType))
65+
{
66+
continue;
67+
}
68+
69+
var interfaceLookupsInSchema =
70+
GetFusionLookupDirectives(interfaceType, implementedInSchemaName);
71+
72+
lookups.AddRange(interfaceLookupsInSchema);
73+
}
74+
75+
// Get the lookups of unions this type is a member of,
76+
// if it's an object type.
77+
if (type.Kind == TypeKind.Object)
78+
{
79+
var unionTypes = schema.Types
80+
.OfType<MutableUnionTypeDefinition>()
81+
.Where(u => u.Types.Contains(type))
82+
.ToImmutableArray();
83+
84+
foreach (var unionType in unionTypes)
85+
{
86+
if (!string.IsNullOrEmpty(schemaName) && !unionType.ExistsInSchema(schemaName))
87+
{
88+
continue;
89+
}
90+
91+
var unionMemberDirectives = unionType.Directives
92+
.AsEnumerable()
93+
.Where(d => d.Name == WellKnownDirectiveNames.FusionUnionMember
94+
&& (string)d.Arguments[WellKnownArgumentNames.Member].Value! == type.Name)
95+
.ToImmutableArray();
96+
97+
foreach (var unionMemberDirective in unionMemberDirectives)
98+
{
99+
var memberInSchemaName =
100+
(string)unionMemberDirective.Arguments[WellKnownArgumentNames.Schema].Value!;
101+
102+
if (!string.IsNullOrEmpty(schemaName) && memberInSchemaName != schemaName)
103+
{
104+
continue;
105+
}
106+
107+
var unionLookups = GetFusionLookupDirectives(unionType, schemaName);
108+
109+
lookups.AddRange(unionLookups);
110+
}
111+
}
112+
}
113+
114+
return lookups;
115+
}
116+
117+
public static List<IDirective> GetPossibleFusionLookupDirectivesById(
118+
this MutableSchemaDefinition schema,
119+
MutableComplexTypeDefinition type,
120+
string? schemaName = null)
121+
{
122+
var lookups = GetPossibleFusionLookupDirectives(schema, type, schemaName);
123+
var lookupsById = new List<IDirective>();
124+
125+
foreach (var lookup in lookups)
126+
{
127+
if (lookup.Arguments[WellKnownArgumentNames.Map] is ListValueNode { Items.Count: 1 } mapArg
128+
&& mapArg.Items[0].Value?.Equals(WellKnownArgumentNames.Id) == true
129+
&& lookup.Arguments[WellKnownArgumentNames.Internal] is not BooleanValueNode { Value: true })
130+
{
131+
lookupsById.Add(lookup);
132+
}
133+
}
134+
135+
return lookupsById;
32136
}
33137

34138
public static void RemoveUnreferencedTypes(
@@ -55,9 +159,7 @@ public static void RemoveUnreferencedTypes(
55159

56160
while (backlog.TryPop(out var type))
57161
{
58-
if (!touchedTypes.Add(type)
59-
|| type.Kind == TypeKind.Scalar
60-
|| type.Kind == TypeKind.Enum)
162+
if (!touchedTypes.Add(type) || type.Kind == TypeKind.Scalar || type.Kind == TypeKind.Enum)
61163
{
62164
continue;
63165
}
@@ -98,6 +200,17 @@ public static void RemoveUnreferencedTypes(
98200
}
99201
}
100202

203+
private static List<IDirective> GetFusionLookupDirectives(
204+
IDirectivesProvider directivesProvider,
205+
string? schemaName)
206+
{
207+
return directivesProvider.Directives
208+
.Where(d => d.Name == WellKnownDirectiveNames.FusionLookup
209+
&& (string.IsNullOrEmpty(schemaName)
210+
|| (string)d.Arguments[WellKnownArgumentNames.Schema].Value! == schemaName))
211+
.ToList();
212+
}
213+
101214
private static void InspectComplexType(
102215
ISchemaDefinition schema,
103216
IComplexTypeDefinition complexType,

0 commit comments

Comments
 (0)