Skip to content

Commit 1115d8a

Browse files
[Fusion] Added Global Object Identification composition support (#8467)
1 parent 914577c commit 1115d8a

19 files changed

+659
-29
lines changed

src/HotChocolate/Fusion-vnext/src/Fusion.CommandLine/Commands/ComposeCommand.cs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Text;
55
using System.Threading.Channels;
66
using HotChocolate.Fusion.Logging;
7+
using HotChocolate.Fusion.Options;
78
using static HotChocolate.Fusion.Properties.CommandLineResources;
89

910
namespace HotChocolate.Fusion.Commands;
@@ -48,6 +49,11 @@ public ComposeCommand() : base("compose")
4849
compositeSchemaFileOption.AddAlias("-c");
4950
compositeSchemaFileOption.LegalFilePathsOnly();
5051

52+
var enableGlobalObjectIdentificationOption = new Option<bool>("--enable-global-object-identification")
53+
{
54+
Description = ComposeCommand_EnableGlobalObjectIdentification_Description
55+
};
56+
5157
var watchModeOption = new Option<bool>("--watch")
5258
{
5359
Arity = ArgumentArity.ZeroOrOne
@@ -56,20 +62,24 @@ public ComposeCommand() : base("compose")
5662
AddOption(workingDirectoryOption);
5763
AddOption(sourceSchemaFileOption);
5864
AddOption(compositeSchemaFileOption);
65+
AddOption(enableGlobalObjectIdentificationOption);
5966
AddOption(watchModeOption);
6067

6168
this.SetHandler(async context =>
6269
{
6370
var workingDirectory = context.ParseResult.GetValueForOption(workingDirectoryOption)!;
6471
var sourceSchemaFiles = context.ParseResult.GetValueForOption(sourceSchemaFileOption)!;
6572
var compositeSchemaFile = context.ParseResult.GetValueForOption(compositeSchemaFileOption);
73+
var enableGlobalObjectIdentification =
74+
context.ParseResult.GetValueForOption(enableGlobalObjectIdentificationOption);
6675
var watchMode = context.ParseResult.GetValueForOption(watchModeOption);
6776

6877
context.ExitCode = await ExecuteAsync(
6978
context.Console,
7079
workingDirectory,
7180
sourceSchemaFiles,
7281
compositeSchemaFile,
82+
enableGlobalObjectIdentification,
7383
watchMode,
7484
context.GetCancellationToken());
7585
});
@@ -80,6 +90,7 @@ private static async Task<int> ExecuteAsync(
8090
string workingDirectory,
8191
List<string> sourceSchemaFiles,
8292
string? compositeSchemaFile,
93+
bool enableGlobalObjectIdentification,
8394
bool watchMode,
8495
CancellationToken cancellationToken)
8596
{
@@ -90,6 +101,7 @@ private static async Task<int> ExecuteAsync(
90101
workingDirectory,
91102
sourceSchemaFiles,
92103
compositeSchemaFile,
104+
enableGlobalObjectIdentification,
93105
cancellationToken);
94106
}
95107

@@ -98,6 +110,7 @@ private static async Task<int> ExecuteAsync(
98110
workingDirectory,
99111
sourceSchemaFiles,
100112
compositeSchemaFile,
113+
enableGlobalObjectIdentification,
101114
cancellationToken);
102115
}
103116

@@ -106,12 +119,19 @@ private static async Task<int> WatchComposeAsync(
106119
string workingDirectory,
107120
List<string> sourceSchemaFiles,
108121
string? compositeSchemaFile,
122+
bool enableGlobalObjectIdentification,
109123
CancellationToken cancellationToken)
110124
{
111125
console.Out.WriteLine("🔍 Starting watch mode...");
112126

113127
// Initial composition
114-
await ComposeAsync(console, workingDirectory, sourceSchemaFiles, compositeSchemaFile, cancellationToken);
128+
await ComposeAsync(
129+
console,
130+
workingDirectory,
131+
sourceSchemaFiles,
132+
compositeSchemaFile,
133+
enableGlobalObjectIdentification,
134+
cancellationToken);
115135

116136
ImmutableSortedSet<string> sourceSchemaFilePaths;
117137

@@ -144,6 +164,7 @@ private static async Task<int> WatchComposeAsync(
144164
workingDirectory,
145165
sourceSchemaFiles,
146166
compositeSchemaFile,
167+
enableGlobalObjectIdentification,
147168
cancellationToken);
148169

149170
// set up file watcher for source schema files
@@ -254,6 +275,7 @@ private static async Task ProcessCompositionRequestsAsync(
254275
string workingDirectory,
255276
List<string> sourceSchemaFiles,
256277
string? compositeSchemaFile,
278+
bool enableGlobalObjectIdentification,
257279
CancellationToken cancellationToken)
258280
{
259281
var lastComposition = DateTime.MinValue;
@@ -284,6 +306,7 @@ await ComposeAsync(
284306
workingDirectory,
285307
sourceSchemaFiles,
286308
compositeSchemaFile,
309+
enableGlobalObjectIdentification,
287310
cancellationToken);
288311
}
289312
catch (Exception ex) when (ex is not OperationCanceledException)
@@ -339,6 +362,7 @@ private static async Task<int> ComposeAsync(
339362
string workingDirectory,
340363
List<string> sourceSchemaFiles,
341364
string? compositeSchemaFile,
365+
bool enableGlobalObjectIdentification,
342366
CancellationToken cancellationToken)
343367
{
344368
IEnumerable<string> sourceSchemas;
@@ -356,8 +380,13 @@ private static async Task<int> ComposeAsync(
356380
return 1;
357381
}
358382

383+
var schemaComposerOptions = new SchemaComposerOptions
384+
{
385+
EnableGlobalObjectIdentification = enableGlobalObjectIdentification
386+
};
359387
var compositionLog = new CompositionLog();
360-
var schemaComposer = new SchemaComposer(sourceSchemas, compositionLog);
388+
var schemaComposer = new SchemaComposer(sourceSchemas, schemaComposerOptions, compositionLog);
389+
361390
var result = schemaComposer.Compose();
362391

363392
WriteCompositionLog(

src/HotChocolate/Fusion-vnext/src/Fusion.CommandLine/Properties/CommandLineResources.Designer.cs

Lines changed: 28 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/HotChocolate/Fusion-vnext/src/Fusion.CommandLine/Properties/CommandLineResources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
<data name="ComposeCommand_Description" xml:space="preserve">
3737
<value>Composes multiple source schemas into a single composite schema.</value>
3838
</data>
39+
<data name="ComposeCommand_EnableGlobalObjectIdentification_Description" xml:space="preserve">
40+
<value>Determines whether the 'Query.node' field shall be added.</value>
41+
</data>
3942
<data name="ComposeCommand_Error_NoSourceSchemaFilesFound" xml:space="preserve">
4043
<value>❌ No GraphQL schema files were found in the working directory.</value>
4144
</data>

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using HotChocolate.Language;
12
using HotChocolate.Types;
23
using HotChocolate.Types.Mutable;
34
using static HotChocolate.Fusion.WellKnownArgumentNames;
@@ -61,6 +62,31 @@ public static IEnumerable<IDirective> GetFusionLookupDirectives(
6162
return lookupDirectives;
6263
}
6364

65+
public static IEnumerable<IDirective> GetFusionLookupDirectivesById(
66+
this MutableObjectTypeDefinition type,
67+
IEnumerable<MutableUnionTypeDefinition> unionTypes)
68+
{
69+
var lookups = new List<IDirective>();
70+
var sourceSchemaNames = type.Directives.AsEnumerable()
71+
.Where(d => d.Name == FusionType)
72+
.Select(d => (string)d.Arguments[Schema].Value!);
73+
unionTypes = unionTypes.ToList();
74+
75+
foreach (var sourceSchemaName in sourceSchemaNames)
76+
{
77+
foreach (var lookupDirective in type.GetFusionLookupDirectives(sourceSchemaName, unionTypes))
78+
{
79+
if (lookupDirective.Arguments[Map] is ListValueNode { Items.Count: 1 } mapArg
80+
&& mapArg.Items[0].Value?.Equals(Id) == true)
81+
{
82+
lookups.Add(lookupDirective);
83+
}
84+
}
85+
}
86+
87+
return lookups;
88+
}
89+
6490
public static bool HasInternalDirective(this MutableObjectTypeDefinition type)
6591
{
6692
return type.Directives.ContainsName(Internal);
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+
public sealed class SchemaComposerOptions
4+
{
5+
public bool EnableGlobalObjectIdentification { get; init; }
6+
}

src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Options/SourceSchemaMergerOptions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ internal sealed class SourceSchemaMergerOptions
55
public bool RemoveUnreferencedTypes { get; init; } = true;
66

77
public bool AddFusionDefinitions { get; init; } = true;
8+
9+
public bool EnableGlobalObjectIdentification { get; init; }
810
}

src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Properties/CompositionResources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,9 @@
363363
<data name="SatisfiabilityValidator_CycleDetected" xml:space="preserve">
364364
<value>Cycle detected: {0} -&gt; {1}.</value>
365365
</data>
366+
<data name="SatisfiabilityValidator_NodeTypeHasNoLookupById" xml:space="preserve">
367+
<value>Type '{0}' implements the 'Node' interface, but does not have a lookup by ID.</value>
368+
</data>
366369
<data name="SatisfiabilityValidator_NoLookupsFoundForType" xml:space="preserve">
367370
<value>No lookups found for type '{0}' in schema '{1}'.</value>
368371
</data>

0 commit comments

Comments
 (0)