Skip to content

Commit 07fc376

Browse files
authored
[Fusion] Fixed basic lookup requirements (#8427)
1 parent 2c56bb4 commit 07fc376

40 files changed

+1068
-232
lines changed

src/CookieCrumble/src/CookieCrumble/Extensions/WriterExtensions.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,7 @@ public static void AppendLine(this IBufferWriter<byte> snapshot, bool appendWhen
3535
public static void AppendSeparator(this IBufferWriter<byte> snapshot)
3636
{
3737
const byte hyphen = (byte)'-';
38-
var span = snapshot.GetSpan(15);
39-
40-
for (var i = 0; i < 15; i++)
41-
{
42-
span[i] = hyphen;
43-
}
44-
38+
snapshot.GetSpan(15).Fill(hyphen);
4539
snapshot.Advance(15);
4640
}
4741
}

src/GreenDonut/src/GreenDonut/BatchDataLoader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ private static void CopyResults(
5353
{
5454
if (resultMap.TryGetValue(keys[i], out var value))
5555
{
56-
results[i] = value;
56+
results[i] = value!;
5757
}
5858
else
5959
{

src/GreenDonut/src/GreenDonut/CacheDataLoader.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ protected internal sealed override async ValueTask FetchAsync(
2727
{
2828
try
2929
{
30-
var value = await LoadSingleAsync(keys[i], cancellationToken).ConfigureAwait(false);
31-
results.Span[i] = value;
30+
var result = await LoadSingleAsync(keys[i], cancellationToken).ConfigureAwait(false);
31+
results.Span[i] = result;
3232
}
3333
catch (Exception ex)
3434
{
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
namespace HotChocolate.Types;
2+
3+
/// <summary>
4+
/// <para>
5+
/// The @internal directive is used in combination with lookup fields and allows you
6+
/// to declare internal types and fields. Internal types and fields do not appear in
7+
/// the final client-facing composite schema and do not participate in the standard
8+
/// schema-merging process. This allows a source schema to define lookup fields for
9+
/// resolving entities that should not be accessible through the client-facing
10+
/// composite schema.
11+
/// </para>
12+
/// <para>
13+
/// <see href="https://graphql.github.io/composite-schemas-spec/draft/#sec--internal"/>
14+
/// </para>
15+
/// <code>
16+
/// type User @internal {
17+
/// id: ID!
18+
/// name: String!
19+
/// }
20+
///
21+
/// directive @internal on OBJECT | FIELD_DEFINITION
22+
/// </code>
23+
/// </summary>
24+
[DirectiveType(
25+
DirectiveNames.Internal.Name,
26+
DirectiveLocation.Object |
27+
DirectiveLocation.FieldDefinition,
28+
IsRepeatable = false)]
29+
public sealed class Internal
30+
{
31+
private Internal()
32+
{
33+
}
34+
35+
/// <summary>
36+
/// The singleton instance of the <see cref="Internal"/> directive.
37+
/// </summary>
38+
public static Internal Instance { get; } = new();
39+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System.Reflection;
2+
using HotChocolate.Types.Descriptors;
3+
4+
namespace HotChocolate.Types;
5+
6+
/// <summary>
7+
/// <para>
8+
/// The @internal directive is used in combination with lookup fields and allows you
9+
/// to declare internal types and fields. Internal types and fields do not appear in
10+
/// the final client-facing composite schema and do not participate in the standard
11+
/// schema-merging process. This allows a source schema to define lookup fields for
12+
/// resolving entities that should not be accessible through the client-facing
13+
/// composite schema.
14+
/// </para>
15+
/// <para>
16+
/// <see href="https://graphql.github.io/composite-schemas-spec/draft/#sec--internal"/>
17+
/// </para>
18+
/// <code>
19+
/// type User @internal {
20+
/// id: ID!
21+
/// name: String!
22+
/// }
23+
///
24+
/// directive @internal on OBJECT | FIELD_DEFINITION
25+
/// </code>
26+
/// </summary>
27+
[AttributeUsage(
28+
AttributeTargets.Class |
29+
AttributeTargets.Property |
30+
AttributeTargets.Method,
31+
AllowMultiple = false)]
32+
public sealed class InternalAttribute : DescriptorAttribute
33+
{
34+
protected internal override void TryConfigure(
35+
IDescriptorContext context,
36+
IDescriptor descriptor,
37+
ICustomAttributeProvider element)
38+
{
39+
switch (descriptor)
40+
{
41+
case IObjectTypeDescriptor desc:
42+
desc.Internal();
43+
break;
44+
45+
case IObjectFieldDescriptor desc:
46+
desc.Internal();
47+
break;
48+
49+
default:
50+
throw new SchemaException(
51+
SchemaErrorBuilder.New()
52+
.SetMessage("Internal directive is only supported on object types and field definitions.")
53+
.SetExtension("member", element)
54+
.SetExtension("descriptor", descriptor)
55+
.Build());
56+
}
57+
}
58+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
namespace HotChocolate.Types;
2+
3+
/// <summary>
4+
/// Provides extension methods to configure the <see cref="HotChocolate.Types.Internal"/> directive with the fluent API.
5+
/// </summary>
6+
public static class InternalDirectiveExtensions
7+
{
8+
/// <summary>
9+
/// <para>
10+
/// The @internal directive is used in combination with lookup fields and allows you
11+
/// to declare internal types and fields. Internal types and fields do not appear in
12+
/// the final client-facing composite schema and do not participate in the standard
13+
/// schema-merging process. This allows a source schema to define lookup fields for
14+
/// resolving entities that should not be accessible through the client-facing
15+
/// composite schema.
16+
/// </para>
17+
/// <para>
18+
/// <see href="https://graphql.github.io/composite-schemas-spec/draft/#sec--internal"/>
19+
/// </para>
20+
/// <code>
21+
/// type User @internal {
22+
/// id: ID!
23+
/// name: String!
24+
/// }
25+
///
26+
/// directive @internal on OBJECT | FIELD_DEFINITION
27+
/// </code>
28+
/// </summary>
29+
public static IObjectTypeDescriptor Internal(this IObjectTypeDescriptor descriptor)
30+
{
31+
ArgumentNullException.ThrowIfNull(descriptor);
32+
return descriptor.Directive(Types.Internal.Instance);
33+
}
34+
35+
/// <summary>
36+
/// <para>
37+
/// The @internal directive is used in combination with lookup fields and allows you
38+
/// to declare internal types and fields. Internal types and fields do not appear in
39+
/// the final client-facing composite schema and do not participate in the standard
40+
/// schema-merging process. This allows a source schema to define lookup fields for
41+
/// resolving entities that should not be accessible through the client-facing
42+
/// composite schema.
43+
/// </para>
44+
/// <para>
45+
/// <see href="https://graphql.github.io/composite-schemas-spec/draft/#sec--internal"/>
46+
/// </para>
47+
/// <code>
48+
/// type User @internal {
49+
/// id: ID!
50+
/// name: String!
51+
/// }
52+
///
53+
/// directive @internal on OBJECT | FIELD_DEFINITION
54+
/// </code>
55+
/// </summary>
56+
public static IObjectFieldDescriptor Internal(this IObjectFieldDescriptor descriptor)
57+
{
58+
ArgumentNullException.ThrowIfNull(descriptor);
59+
return descriptor.Directive(Types.Internal.Instance);
60+
}
61+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
namespace HotChocolate.Types;
2+
3+
/// <summary>
4+
/// <para>
5+
/// The @lookup directive is used within a source schema to specify output fields
6+
/// that can be used by the distributed GraphQL executor to resolve an entity by
7+
/// a stable key.
8+
/// </para>
9+
/// <para>
10+
/// <see href="https://graphql.github.io/composite-schemas-spec/draft/#sec--lookup"/>
11+
/// </para>
12+
/// <code>
13+
/// type Query {
14+
/// productById(id: ID!): Product @lookup
15+
/// }
16+
///
17+
/// directive @lookup on FIELD_DEFINITION
18+
/// </code>
19+
/// </summary>
20+
[DirectiveType(
21+
DirectiveNames.Lookup.Name,
22+
DirectiveLocation.FieldDefinition,
23+
IsRepeatable = false)]
24+
public sealed class Lookup
25+
{
26+
private Lookup()
27+
{
28+
}
29+
30+
/// <summary>
31+
/// The singleton instance of the <see cref="Lookup"/> directive.
32+
/// </summary>
33+
public static Lookup Instance { get; } = new();
34+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System.Reflection;
2+
using HotChocolate.Types.Descriptors;
3+
4+
namespace HotChocolate.Types;
5+
6+
/// <summary>
7+
/// <para>
8+
/// The @lookup directive is used within a source schema to specify output fields
9+
/// that can be used by the distributed GraphQL executor to resolve an entity by
10+
/// a stable key.
11+
/// </para>
12+
/// <para>
13+
/// <see href="https://graphql.github.io/composite-schemas-spec/draft/#sec--lookup"/>
14+
/// </para>
15+
/// <code>
16+
/// type Query {
17+
/// productById(id: ID!): Product @lookup
18+
/// }
19+
///
20+
/// directive @lookup on FIELD_DEFINITION
21+
/// </code>
22+
/// </summary>
23+
[AttributeUsage(
24+
AttributeTargets.Property |
25+
AttributeTargets.Method,
26+
AllowMultiple = false)]
27+
public sealed class LookupAttribute : DescriptorAttribute
28+
{
29+
protected internal override void TryConfigure(
30+
IDescriptorContext context,
31+
IDescriptor descriptor,
32+
ICustomAttributeProvider element)
33+
{
34+
switch (descriptor)
35+
{
36+
case IObjectFieldDescriptor desc:
37+
desc.Lookup();
38+
break;
39+
40+
default:
41+
throw new SchemaException(
42+
SchemaErrorBuilder.New()
43+
.SetMessage("Lookup directive is only supported on field definitions of objects types.")
44+
.SetExtension("member", element)
45+
.SetExtension("descriptor", descriptor)
46+
.Build());
47+
}
48+
}
49+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
namespace HotChocolate.Types;
2+
3+
/// <summary>
4+
/// Provides extension methods to configure the <see cref="Lookup"/> directive with the fluent API.
5+
/// </summary>
6+
public static class LookupDirectiveExtensions
7+
{
8+
/// <summary>
9+
/// <para>
10+
/// The @lookup directive is used within a source schema to specify output fields
11+
/// that can be used by the distributed GraphQL executor to resolve an entity by
12+
/// a stable key.
13+
/// </para>
14+
/// <para>
15+
/// <see href="https://graphql.github.io/composite-schemas-spec/draft/#sec--lookup"/>
16+
/// </para>
17+
/// <code>
18+
/// type Query {
19+
/// productById(id: ID!): Product @lookup
20+
/// }
21+
///
22+
/// directive @lookup on FIELD_DEFINITION
23+
/// </code>
24+
/// </summary>
25+
public static IObjectFieldDescriptor Lookup(this IObjectFieldDescriptor descriptor)
26+
{
27+
ArgumentNullException.ThrowIfNull(descriptor);
28+
return descriptor.Directive(Types.Lookup.Instance);
29+
}
30+
}

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/FusionRequestExecutorManager.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ internal sealed class FusionRequestExecutorManager
4141
SingleReader = true,
4242
SingleWriter = false
4343
});
44-
private ImmutableArray<ObserverSession> _observers = ImmutableArray<ObserverSession>.Empty;
44+
private ImmutableArray<ObserverSession> _observers = [];
4545

4646
private bool _disposed;
4747

@@ -429,14 +429,16 @@ public async ValueTask DisposeAsync()
429429
await registration.DisposeAsync().ConfigureAwait(false);
430430
}
431431

432-
while(_executorEvents.Reader.TryRead(out _)) { }
432+
while (_executorEvents.Reader.TryRead(out _))
433+
{
434+
}
433435

434436
foreach (var session in _observers)
435437
{
436438
session.OnCompleted();
437439
}
438440

439-
_observers = ImmutableArray<ObserverSession>.Empty;
441+
_observers = [];
440442
}
441443

442444
private sealed class RequestExecutorAccessor

0 commit comments

Comments
 (0)