Skip to content

Commit 01398f6

Browse files
[Fusion] Added SourceSchemaPreprocessor (#7975)
1 parent 1492d4d commit 01398f6

File tree

6 files changed

+465
-0
lines changed

6 files changed

+465
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using HotChocolate.Skimmed;
2+
using ArgumentNames = HotChocolate.Fusion.WellKnownArgumentNames;
3+
using DirectiveNames = HotChocolate.Fusion.WellKnownDirectiveNames;
4+
5+
namespace HotChocolate.Fusion.Extensions;
6+
7+
internal static class ComplexTypeDefinitionExtensions
8+
{
9+
public static void ApplyKeyDirective(this ComplexTypeDefinition type, string[] fields)
10+
{
11+
var fieldsArgument = new ArgumentAssignment(ArgumentNames.Fields, string.Join(" ", fields));
12+
var keyDirective = new Directive(new DirectiveDefinition(DirectiveNames.Key), fieldsArgument);
13+
14+
type.Directives.Add(keyDirective);
15+
}
16+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using HotChocolate.Skimmed;
2+
using DirectiveNames = HotChocolate.Fusion.WellKnownDirectiveNames;
3+
4+
namespace HotChocolate.Fusion.Extensions;
5+
6+
public static class ObjectFieldDefinitionExtensions
7+
{
8+
public static void ApplyLookupDirective(this OutputFieldDefinition outputField)
9+
{
10+
outputField.Directives.Add(new Directive(new DirectiveDefinition(DirectiveNames.Lookup)));
11+
}
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using HotChocolate.Skimmed;
2+
using DirectiveNames = HotChocolate.Fusion.WellKnownDirectiveNames;
3+
4+
namespace HotChocolate.Fusion.Extensions;
5+
6+
internal static class ObjectTypeDefinitionExtensions
7+
{
8+
public static void ApplyShareableDirective(this ObjectTypeDefinition type)
9+
{
10+
type.Directives.Add(new Directive(new DirectiveDefinition(DirectiveNames.Shareable)));
11+
}
12+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace HotChocolate.Fusion.Options;
2+
3+
internal sealed class SourceSchemaPreprocessorOptions
4+
{
5+
public bool ApplyShareableToAllTypes { get; set; } = true;
6+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using HotChocolate.Fusion.Extensions;
2+
using HotChocolate.Fusion.Options;
3+
using HotChocolate.Skimmed;
4+
using HotChocolate.Types;
5+
6+
namespace HotChocolate.Fusion;
7+
8+
/// <summary>
9+
/// Applies @lookup, @key, and optionally @shareable to a source schema to make it equivalent to a Fusion v1 source schema.
10+
/// </summary>
11+
internal sealed class SourceSchemaPreprocessor(
12+
SchemaDefinition schema,
13+
SourceSchemaPreprocessorOptions? options = null)
14+
{
15+
public SchemaDefinition Process()
16+
{
17+
var context = new SourceSchemaPreprocessorContext(schema, options ?? new());
18+
19+
ApplyLookups(context);
20+
21+
if (context.Options.ApplyShareableToAllTypes)
22+
{
23+
ApplyShareableToAllTypes(context);
24+
}
25+
26+
return schema;
27+
}
28+
29+
private static void ApplyLookups(SourceSchemaPreprocessorContext context)
30+
{
31+
if (context.Schema.QueryType is not { } queryType)
32+
{
33+
return;
34+
}
35+
36+
foreach (var queryField in queryType.Fields)
37+
{
38+
if (queryField.HasLookupDirective()
39+
|| queryField.Type.IsListType()
40+
|| queryField.Type.Kind == TypeKind.NonNull
41+
|| queryField.Arguments.Count != 1)
42+
{
43+
continue;
44+
}
45+
46+
var keyArgument = queryField.Arguments.First();
47+
var @is = keyArgument.GetIsFieldSelectionMap();
48+
49+
var queryFieldType = queryField.Type.NamedType();
50+
var keyOutputFieldName = @is ?? keyArgument.Name;
51+
52+
if (!context.Schema.Types.TryGetType(queryFieldType.Name, out var resultType))
53+
{
54+
continue;
55+
}
56+
57+
if (resultType is ObjectTypeDefinition resultObjectType)
58+
{
59+
if (resultObjectType.Fields.TryGetField(keyOutputFieldName, out var keyField))
60+
{
61+
queryField.ApplyLookupDirective();
62+
63+
resultObjectType.ApplyKeyDirective([keyField.Name]);
64+
}
65+
}
66+
else if (resultType is InterfaceTypeDefinition resultInterfaceType)
67+
{
68+
if (resultInterfaceType.Fields.TryGetField(keyOutputFieldName, out var keyField))
69+
{
70+
queryField.ApplyLookupDirective();
71+
72+
resultInterfaceType.ApplyKeyDirective([keyField.Name]);
73+
74+
foreach (var objectType in context.Schema.Types.OfType<ObjectTypeDefinition>())
75+
{
76+
if (objectType.Implements.ContainsName(resultInterfaceType.Name))
77+
{
78+
objectType.ApplyKeyDirective([keyField.Name]);
79+
}
80+
}
81+
}
82+
}
83+
}
84+
}
85+
86+
private static void ApplyShareableToAllTypes(SourceSchemaPreprocessorContext context)
87+
{
88+
foreach (var objectType in context.Schema.Types.OfType<ObjectTypeDefinition>())
89+
{
90+
objectType.ApplyShareableDirective();
91+
}
92+
}
93+
}
94+
95+
internal sealed class SourceSchemaPreprocessorContext(
96+
SchemaDefinition schema,
97+
SourceSchemaPreprocessorOptions options)
98+
{
99+
public SchemaDefinition Schema => schema;
100+
101+
public SourceSchemaPreprocessorOptions Options => options;
102+
}

0 commit comments

Comments
 (0)