Skip to content

Commit 831eba2

Browse files
authored
[Fusion] Added internal argument to @fusion__lookup directive (#8620)
1 parent f00c4ca commit 831eba2

18 files changed

+144
-64
lines changed

src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Definitions/FusionLookupMutableDirectiveDefinition.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
using HotChocolate.Language;
12
using HotChocolate.Types;
23
using HotChocolate.Types.Mutable;
34
using static HotChocolate.Fusion.Properties.CompositionResources;
45
using static HotChocolate.Fusion.WellKnownDirectiveNames;
56
using ArgumentNames = HotChocolate.Fusion.WellKnownArgumentNames;
7+
using DirectiveLocation = HotChocolate.Types.DirectiveLocation;
68

79
namespace HotChocolate.Fusion.Definitions;
810

@@ -17,7 +19,8 @@ public FusionLookupMutableDirectiveDefinition(
1719
MutableScalarTypeDefinition fieldSelectionSetType,
1820
MutableScalarTypeDefinition fieldDefinitionType,
1921
MutableScalarTypeDefinition fieldSelectionMapType,
20-
MutableScalarTypeDefinition fieldSelectionPathType)
22+
MutableScalarTypeDefinition fieldSelectionPathType,
23+
MutableScalarTypeDefinition booleanType)
2124
: base(FusionLookup)
2225
{
2326
Description = FusionLookupMutableDirectiveDefinition_Description;
@@ -60,6 +63,12 @@ public FusionLookupMutableDirectiveDefinition(
6063
Description = FusionLookupMutableDirectiveDefinition_Argument_Path_Description
6164
});
6265

66+
Arguments.Add(new MutableInputFieldDefinition(ArgumentNames.Internal, new NonNullType(booleanType))
67+
{
68+
DefaultValue = new BooleanValueNode(false),
69+
Description = FusionLookupMutableDirectiveDefinition_Argument_Internal_Description
70+
});
71+
6372
IsRepeatable = true;
6473

6574
Locations =

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

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
using HotChocolate.Language;
22
using HotChocolate.Types;
33
using HotChocolate.Types.Mutable;
4-
using static HotChocolate.Fusion.WellKnownArgumentNames;
5-
using static HotChocolate.Fusion.WellKnownDirectiveNames;
4+
using ArgumentNames = HotChocolate.Fusion.WellKnownArgumentNames;
5+
using DirectiveNames = HotChocolate.Fusion.WellKnownDirectiveNames;
66

77
namespace HotChocolate.Fusion.Extensions;
88

99
internal static class MutableObjectTypeDefinitionExtensions
1010
{
1111
public static void ApplyShareableDirective(this MutableObjectTypeDefinition type)
1212
{
13-
type.Directives.Add(new Directive(new MutableDirectiveDefinition(Shareable)));
13+
type.Directives.Add(new Directive(new MutableDirectiveDefinition(DirectiveNames.Shareable)));
1414
}
1515

1616
public static bool ExistsInSchema(this MutableObjectTypeDefinition type, string schemaName)
1717
{
1818
return type.Directives.AsEnumerable().Any(
19-
d => d.Name == FusionType && (string)d.Arguments[Schema].Value! == schemaName);
19+
d =>
20+
d.Name == DirectiveNames.FusionType
21+
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName);
2022
}
2123

2224
public static IEnumerable<IDirective> GetFusionLookupDirectives(
@@ -29,8 +31,8 @@ public static IEnumerable<IDirective> GetFusionLookupDirectives(
2931
.AsEnumerable()
3032
.Where(
3133
d =>
32-
d.Name == FusionLookup
33-
&& (string)d.Arguments[Schema].Value! == schemaName)
34+
d.Name == DirectiveNames.FusionLookup
35+
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName)
3436
.ToList();
3537

3638
// To use an abstract lookup, the type must exist in the source schema.
@@ -45,8 +47,8 @@ public static IEnumerable<IDirective> GetFusionLookupDirectives(
4547
interfaceType.Directives
4648
.AsEnumerable()
4749
.Where(d =>
48-
d.Name == FusionLookup
49-
&& (string)d.Arguments[Schema].Value! == schemaName));
50+
d.Name == DirectiveNames.FusionLookup
51+
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName));
5052
}
5153

5254
// Union lookups.
@@ -56,8 +58,8 @@ public static IEnumerable<IDirective> GetFusionLookupDirectives(
5658
unionType.Directives
5759
.AsEnumerable()
5860
.Where(d =>
59-
d.Name == FusionLookup
60-
&& (string)d.Arguments[Schema].Value! == schemaName));
61+
d.Name == DirectiveNames.FusionLookup
62+
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName));
6163
}
6264
}
6365

@@ -70,16 +72,16 @@ public static IEnumerable<IDirective> GetFusionLookupDirectivesById(
7072
{
7173
var lookups = new List<IDirective>();
7274
var sourceSchemaNames = type.Directives.AsEnumerable()
73-
.Where(d => d.Name == FusionType)
74-
.Select(d => (string)d.Arguments[Schema].Value!);
75+
.Where(d => d.Name == DirectiveNames.FusionType)
76+
.Select(d => (string)d.Arguments[ArgumentNames.Schema].Value!);
7577
unionTypes = unionTypes.ToList();
7678

7779
foreach (var sourceSchemaName in sourceSchemaNames)
7880
{
7981
foreach (var lookupDirective in type.GetFusionLookupDirectives(sourceSchemaName, unionTypes))
8082
{
81-
if (lookupDirective.Arguments[Map] is ListValueNode { Items.Count: 1 } mapArg
82-
&& mapArg.Items[0].Value?.Equals(Id) == true)
83+
if (lookupDirective.Arguments[ArgumentNames.Map] is ListValueNode { Items.Count: 1 } mapArg
84+
&& mapArg.Items[0].Value?.Equals(ArgumentNames.Id) == true)
8385
{
8486
lookups.Add(lookupDirective);
8587
}
@@ -91,6 +93,6 @@ public static IEnumerable<IDirective> GetFusionLookupDirectivesById(
9193

9294
public static bool HasInternalDirective(this MutableObjectTypeDefinition type)
9395
{
94-
return type.Directives.ContainsName(Internal);
96+
return type.Directives.ContainsName(DirectiveNames.Internal);
9597
}
9698
}

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

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
using HotChocolate.Language;
22
using HotChocolate.Types.Mutable;
3-
using static HotChocolate.Fusion.WellKnownArgumentNames;
4-
using static HotChocolate.Fusion.WellKnownDirectiveNames;
53
using static HotChocolate.Language.Utf8GraphQLParser.Syntax;
4+
using ArgumentNames = HotChocolate.Fusion.WellKnownArgumentNames;
5+
using DirectiveNames = HotChocolate.Fusion.WellKnownDirectiveNames;
66

77
namespace HotChocolate.Fusion.Extensions;
88

99
internal static class MutableOutputFieldDefinitionExtensions
1010
{
1111
public static void ApplyLookupDirective(this MutableOutputFieldDefinition field)
1212
{
13-
field.Directives.Add(new Directive(new MutableDirectiveDefinition(Lookup)));
13+
field.Directives.Add(new Directive(new MutableDirectiveDefinition(DirectiveNames.Lookup)));
1414
}
1515

1616
public static bool ExistsInSchema(this MutableOutputFieldDefinition field, string schemaName)
1717
{
1818
return field.Directives.AsEnumerable().Any(
19-
d => d.Name == FusionField && (string)d.Arguments[Schema].Value! == schemaName);
19+
d =>
20+
d.Name == DirectiveNames.FusionField
21+
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName);
2022
}
2123

2224
public static string? GetFusionFieldProvides(
@@ -26,12 +28,10 @@ public static bool ExistsInSchema(this MutableOutputFieldDefinition field, strin
2628
var fusionFieldDirective =
2729
field.Directives.AsEnumerable().FirstOrDefault(
2830
d =>
29-
d.Name == FusionField
30-
&& (string)d.Arguments[Schema].Value! == schemaName);
31+
d.Name == DirectiveNames.FusionField
32+
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName);
3133

32-
if (fusionFieldDirective?.Arguments.TryGetValue(
33-
WellKnownArgumentNames.Provides,
34-
out var provides) == true)
34+
if (fusionFieldDirective?.Arguments.TryGetValue(ArgumentNames.Provides, out var provides) == true)
3535
{
3636
return (string?)provides.Value;
3737
}
@@ -48,38 +48,38 @@ public static bool ExistsInSchema(this MutableOutputFieldDefinition field, strin
4848
.AsEnumerable()
4949
.FirstOrDefault(
5050
d =>
51-
d.Name == FusionRequires
52-
&& (string)d.Arguments[Schema].Value! == schemaName);
51+
d.Name == DirectiveNames.FusionRequires
52+
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName);
5353

5454
if (fusionRequiresDirective is null)
5555
{
5656
return null;
5757
}
5858

59-
var requirements = (string)fusionRequiresDirective.Arguments[Requirements].Value!;
59+
var requirements = (string)fusionRequiresDirective.Arguments[ArgumentNames.Requirements].Value!;
6060

6161
return ParseSelectionSet($"{{ {requirements} }}");
6262
}
6363

6464
public static bool HasInternalDirective(this MutableOutputFieldDefinition type)
6565
{
66-
return type.Directives.ContainsName(Internal);
66+
return type.Directives.ContainsName(DirectiveNames.Internal);
6767
}
6868

6969
public static bool IsPartial(this MutableOutputFieldDefinition field, string schemaName)
7070
{
7171
var fusionFieldDirective =
7272
field.Directives.AsEnumerable().FirstOrDefault(
7373
d =>
74-
d.Name == FusionField
75-
&& (string)d.Arguments[Schema].Value! == schemaName);
74+
d.Name == DirectiveNames.FusionField
75+
&& (string)d.Arguments[ArgumentNames.Schema].Value! == schemaName);
7676

7777
if (fusionFieldDirective is null)
7878
{
7979
return false;
8080
}
8181

82-
if (fusionFieldDirective.Arguments.TryGetValue(Partial, out var partial))
82+
if (fusionFieldDirective.Arguments.TryGetValue(ArgumentNames.Partial, out var partial))
8383
{
8484
return (bool)partial.Value!;
8585
}

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
@@ -93,6 +93,9 @@
9393
<data name="FusionLookupMutableDirectiveDefinition_Argument_Field_Description" xml:space="preserve">
9494
<value>The GraphQL field definition in the source schema that can be used to look up the entity.</value>
9595
</data>
96+
<data name="FusionLookupMutableDirectiveDefinition_Argument_Internal_Description" xml:space="preserve">
97+
<value>Is the lookup meant as an entry point or just to provide more data.</value>
98+
</data>
9699
<data name="FusionLookupMutableDirectiveDefinition_Argument_Key_Description" xml:space="preserve">
97100
<value>A selection set on the annotated entity type that describes the stable key for the lookup.</value>
98101
</data>

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,14 +1036,17 @@ private void AddFusionLookupDirectives(
10361036
? NullValueNode.Default
10371037
: new StringValueNode(sourcePath);
10381038

1039+
var @internal = sourceField.HasInternalDirective();
1040+
10391041
type.Directives.Add(
10401042
new Directive(
10411043
_fusionDirectiveDefinitions[DirectiveNames.FusionLookup],
10421044
new ArgumentAssignment(ArgumentNames.Schema, schemaArgument),
10431045
new ArgumentAssignment(ArgumentNames.Key, keyArgument),
10441046
new ArgumentAssignment(ArgumentNames.Field, fieldArgument),
10451047
new ArgumentAssignment(ArgumentNames.Map, mapArgument),
1046-
new ArgumentAssignment(ArgumentNames.Path, pathArgument)));
1048+
new ArgumentAssignment(ArgumentNames.Path, pathArgument),
1049+
new ArgumentAssignment(ArgumentNames.Internal, @internal)));
10471050
}
10481051
}
10491052

@@ -1235,7 +1238,8 @@ private FrozenDictionary<string, MutableDirectiveDefinition> CreateFusionDirecti
12351238
fieldSelectionSetType,
12361239
fieldDefinitionType,
12371240
fieldSelectionMapType,
1238-
fieldSelectionPathType)
1241+
fieldSelectionPathType,
1242+
booleanType)
12391243
},
12401244
{
12411245
DirectiveNames.FusionRequires,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ internal static class WellKnownArgumentNames
77
public const string From = "from";
88
public const string Id = "id";
99
public const string Interface = "interface";
10+
public const string Internal = "internal";
1011
public const string Key = "key";
1112
public const string Map = "map";
1213
public const string Member = "member";

src/HotChocolate/Fusion-vnext/src/Fusion.Execution.Types/Directives/LookupDirective.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@ directive @fusion__lookup(
1010
field: fusion__FieldDefinition!
1111
map: [fusion__FieldSelectionMap!]!
1212
path: fusion__FieldSelectionPath
13+
internal: Boolean! = false
1314
) repeatable on OBJECT | INTERFACE | UNION
1415
*/
1516
internal sealed class LookupDirective(
1617
SchemaKey schemaKey,
1718
SelectionSetNode key,
1819
FieldDefinitionNode field,
1920
ImmutableArray<string> map,
20-
ImmutableArray<string> path)
21+
ImmutableArray<string> path,
22+
bool @internal = false)
2123
{
2224
public SchemaKey SchemaKey { get; } = schemaKey;
2325

@@ -28,4 +30,6 @@ internal sealed class LookupDirective(
2830
public ImmutableArray<string> Map { get; } = map;
2931

3032
public ImmutableArray<string> Path { get; } = path;
33+
34+
public bool Internal { get; } = @internal;
3135
}

src/HotChocolate/Fusion-vnext/src/Fusion.Execution.Types/Directives/LookupDirectiveParser.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public static LookupDirective Parse(DirectiveNode directive)
1616
FieldDefinitionNode? field = null;
1717
ImmutableArray<string>? map = null;
1818
ImmutableArray<string>? path = null;
19+
bool? @internal = null;
1920

2021
foreach (var argument in directive.Arguments)
2122
{
@@ -51,6 +52,10 @@ public static LookupDirective Parse(DirectiveNode directive)
5152
}
5253
break;
5354

55+
case "internal":
56+
@internal = ((BooleanValueNode)argument.Value).Value;
57+
break;
58+
5459
default:
5560
throw new DirectiveParserException(
5661
$"The argument `{argument.Name.Value}` is not supported on @lookup.");
@@ -81,7 +86,7 @@ public static LookupDirective Parse(DirectiveNode directive)
8186
"The `map` argument is required on the @lookup directive.");
8287
}
8388

84-
return new LookupDirective(new SchemaKey(schemaKey), key, field, map.Value, path ?? []);
89+
return new LookupDirective(new SchemaKey(schemaKey), key, field, map.Value, path ?? [], @internal ?? false);
8590
}
8691

8792
private static ImmutableArray<string> ParseMap(IValueNode value)

src/HotChocolate/Fusion-vnext/test/Fusion.CommandLine.Tests/__resources__/invalid-example-1-result/composite-schema.graphqls

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ type Query
1818
type User
1919
@fusion__type(schema: SCHEMA1)
2020
@fusion__type(schema: SCHEMA2)
21-
@fusion__lookup(schema: SCHEMA1, key: "id", field: "userById(id: ID!): User!", map: [ "id" ], path: null)
22-
@fusion__lookup(schema: SCHEMA2, key: "id", field: "userById(id: ID!): User!", map: [ "id" ], path: null) {
21+
@fusion__lookup(schema: SCHEMA1, key: "id", field: "userById(id: ID!): User!", map: [ "id" ], path: null, internal: false)
22+
@fusion__lookup(schema: SCHEMA2, key: "id", field: "userById(id: ID!): User!", map: [ "id" ], path: null, internal: false) {
2323
id: ID!
2424
@fusion__field(schema: SCHEMA1)
2525
@fusion__field(schema: SCHEMA2)
@@ -63,7 +63,7 @@ directive @fusion__inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT
6363
directive @fusion__inputField("The name of the source schema that originally provided this input field." schema: fusion__Schema! "The field type in the source schema if it differs in nullability or structure." sourceType: String) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
6464

6565
"The @fusion__lookup directive specifies how the distributed executor can resolve data for an entity type from a source schema by a stable key."
66-
directive @fusion__lookup("The GraphQL field definition in the source schema that can be used to look up the entity." field: fusion__FieldDefinition! "A selection set on the annotated entity type that describes the stable key for the lookup." key: fusion__FieldSelectionSet! "The map describes how the key values are resolved from the annotated entity type." map: [fusion__FieldSelectionMap!]! "The path to the lookup field relative to the Query type." path: fusion__FieldSelectionPath "The name of the source schema where the annotated entity type can be looked up from." schema: fusion__Schema!) repeatable on OBJECT | INTERFACE | UNION
66+
directive @fusion__lookup("The GraphQL field definition in the source schema that can be used to look up the entity." field: fusion__FieldDefinition! "Is the lookup meant as an entry point or just to provide more data." internal: Boolean! = false "A selection set on the annotated entity type that describes the stable key for the lookup." key: fusion__FieldSelectionSet! "The map describes how the key values are resolved from the annotated entity type." map: [fusion__FieldSelectionMap!]! "The path to the lookup field relative to the Query type." path: fusion__FieldSelectionPath "The name of the source schema where the annotated entity type can be looked up from." schema: fusion__Schema!) repeatable on OBJECT | INTERFACE | UNION
6767

6868
"The @fusion__requires directive specifies if a field has requirements on a source schema."
6969
directive @fusion__requires("The GraphQL field definition in the source schema that this field depends on." field: fusion__FieldDefinition! "The map describes how the argument values for the source schema are resolved from the arguments of the field exposed in the client-facing composite schema and from required data relative to the current type." map: [fusion__FieldSelectionMap]! "A selection set on the annotated field that describes its requirements." requirements: fusion__FieldSelectionSet! "The name of the source schema where this field has requirements to data on other source schemas." schema: fusion__Schema!) repeatable on FIELD_DEFINITION

0 commit comments

Comments
 (0)