Skip to content

Commit 823dd2e

Browse files
Some cleanup
1 parent 97bdeee commit 823dd2e

12 files changed

+255
-95
lines changed

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Clients/SourceSchemaError.cs

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/OperationExecutionNode.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -387,32 +387,32 @@ private static void AddErrors(
387387
ImmutableArray<VariableValues> variables,
388388
ImmutableArray<string> responseNames)
389389
{
390-
var bufferLength = Math.Max(variables.Length, 1);
391-
var buffer = ArrayPool<SourceSchemaError>.Shared.Rent(bufferLength);
392-
393-
try
394-
{
395390
var error = ErrorBuilder.FromException(exception).Build();
396391

397392
if (variables.Length == 0)
398393
{
399-
buffer[0] = new SourceSchemaError(error, Path.Root);
394+
context.AddErrors(error, responseNames.AsSpan(), Path.Root);
400395
}
401396
else
402397
{
403-
for (var i = 0; i < variables.Length; i++)
398+
var bufferLength = Math.Max(variables.Length, 1);
399+
var buffer = ArrayPool<Path>.Shared.Rent(bufferLength);
400+
401+
try
404402
{
405-
buffer[i] = new SourceSchemaError(error, variables[i].Path);
403+
for (var i = 0; i < variables.Length; i++)
404+
{
405+
buffer[i] = variables[i].Path;
406+
}
407+
408+
context.AddErrors(error, responseNames.AsSpan(), buffer.AsSpan(0, bufferLength));
409+
}
410+
finally
411+
{
412+
buffer.AsSpan(0, bufferLength).Clear();
413+
ArrayPool<Path>.Shared.Return(buffer);
406414
}
407415
}
408-
409-
context.AddErrors(buffer.AsSpan(0, bufferLength), responseNames.AsSpan());
410-
}
411-
finally
412-
{
413-
buffer.AsSpan(0, bufferLength).Clear();
414-
ArrayPool<SourceSchemaError>.Shared.Return(buffer);
415-
}
416416
}
417417

418418
private sealed class SubscriptionEnumerable : IAsyncEnumerable<EventMessageResult>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ internal void AddPartialResults(SelectionPath sourcePath, ReadOnlySpan<SourceSch
105105
internal void AddPartialResults(ObjectResult result, ReadOnlySpan<Selection> selections)
106106
=> _resultStore.AddPartialResults(result, selections);
107107

108-
internal void AddErrors(ReadOnlySpan<SourceSchemaError> errors, ReadOnlySpan<string> responseNames)
109-
=> _resultStore.AddErrors(errors, responseNames);
108+
internal void AddErrors(IError error, ReadOnlySpan<string> responseNames, params ReadOnlySpan<Path> paths)
109+
=> _resultStore.AddErrors(error, responseNames, paths);
110110

111111
internal PooledArrayWriter CreateRentedBuffer()
112112
=> _resultStore.CreateRentedBuffer();

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Results/FetchResultStore.cs

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -119,66 +119,64 @@ public bool AddPartialResults(
119119
}
120120
}
121121

122-
public bool AddErrors(ReadOnlySpan<SourceSchemaError> errors, ReadOnlySpan<string> responseNames)
122+
public void AddPartialResults(ObjectResult result, ReadOnlySpan<Selection> selections)
123123
{
124+
ObjectDisposedException.ThrowIf(_disposed, this);
125+
ArgumentNullException.ThrowIfNull(result);
126+
127+
if (selections.Length == 0)
128+
{
129+
throw new ArgumentException(
130+
"The selections span must contain at least one selection.",
131+
nameof(selections));
132+
}
133+
124134
_lock.EnterWriteLock();
125135

126136
try
127137
{
128-
ref var error = ref MemoryMarshal.GetReference(errors);
129-
ref var end = ref Unsafe.Add(ref error, errors.Length);
130-
131-
while (Unsafe.IsAddressLessThan(ref error, ref end))
138+
foreach (var selection in selections)
132139
{
133-
if (_root.IsInvalidated)
134-
{
135-
return false;
136-
}
137-
138-
var result = error.Path.IsRoot ? _root : GetStartObjectResult(error.Path);
139-
140-
if (result.IsInvalidated)
140+
if (!selection.IsIncluded(_includeFlags))
141141
{
142142
continue;
143143
}
144144

145-
_valueCompletion.BuildResult(result, responseNames, error);
146-
147-
error = ref Unsafe.Add(ref error, 1)!;
145+
result.MoveFieldTo(selection.ResponseName, _root);
148146
}
149147
}
150148
finally
151149
{
152150
_lock.ExitWriteLock();
153151
}
154-
155-
return true;
156152
}
157153

158-
public void AddPartialResults(ObjectResult result, ReadOnlySpan<Selection> selections)
154+
public void AddErrors(IError error, ReadOnlySpan<string> responseNames, params ReadOnlySpan<Path> paths)
159155
{
160-
ObjectDisposedException.ThrowIf(_disposed, this);
161-
ArgumentNullException.ThrowIfNull(result);
162-
163-
if (selections.Length == 0)
164-
{
165-
throw new ArgumentException(
166-
"The selections span must contain at least one selection.",
167-
nameof(selections));
168-
}
169-
170156
_lock.EnterWriteLock();
171157

172158
try
173159
{
174-
foreach (var selection in selections)
160+
ref var path = ref MemoryMarshal.GetReference(paths);
161+
ref var end = ref Unsafe.Add(ref path, paths.Length);
162+
163+
while (Unsafe.IsAddressLessThan(ref path, ref end))
175164
{
176-
if (!selection.IsIncluded(_includeFlags))
165+
if (_root.IsInvalidated)
166+
{
167+
return;
168+
}
169+
170+
var result = path.IsRoot ? _root : GetStartObjectResult(path);
171+
172+
if (result.IsInvalidated)
177173
{
178174
continue;
179175
}
180176

181-
result.MoveFieldTo(selection.ResponseName, _root);
177+
_valueCompletion.BuildResult(result, responseNames, error, path);
178+
179+
path = ref Unsafe.Add(ref path, 1)!;
182180
}
183181
}
184182
finally
@@ -203,21 +201,22 @@ private bool SaveSafe(
203201

204202
while (Unsafe.IsAddressLessThan(ref result, ref end))
205203
{
206-
if (result.Path.IsRoot)
204+
if (_root.IsInvalidated)
207205
{
208-
var selectionSet = _operation.RootSelectionSet;
209-
if (!_valueCompletion.BuildResult(selectionSet, data, errorTrie, _root))
210-
{
211-
return false;
212-
}
206+
return false;
213207
}
214-
else
208+
209+
var objectResult = result.Path.IsRoot ? _root : GetStartObjectResult(result.Path);
210+
var selectionSet = result.Path.IsRoot ? _operation.RootSelectionSet : objectResult.SelectionSet;
211+
212+
if (objectResult.IsInvalidated)
215213
{
216-
var startResult = GetStartObjectResult(result.Path);
217-
if (!_valueCompletion.BuildResult(startResult.SelectionSet, data, errorTrie, startResult))
218-
{
219-
return false;
220-
}
214+
continue;
215+
}
216+
217+
if (!_valueCompletion.BuildResult(selectionSet, data, errorTrie, objectResult))
218+
{
219+
return false;
221220
}
222221

223222
result = ref Unsafe.Add(ref result, 1)!;

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Results/ValueCompletion.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ public bool BuildResult(
5959
.Build();
6060

6161
_errors.Add(errorWithPath);
62+
63+
if (_errorHandling is ErrorHandling.Propagate)
64+
{
65+
PropagateNullValues(objectResult);
66+
}
6267
}
6368

6469
return false;
@@ -94,7 +99,8 @@ public bool BuildResult(
9499
public void BuildResult(
95100
ObjectResult objectResult,
96101
ReadOnlySpan<string> responseNames,
97-
SourceSchemaError sourceSchemaError)
102+
IError error,
103+
Path path)
98104
{
99105
foreach (var responseName in responseNames)
100106
{
@@ -105,12 +111,12 @@ public void BuildResult(
105111
continue;
106112
}
107113

108-
var error = ErrorBuilder.FromError(sourceSchemaError.Error)
109-
.SetPath(sourceSchemaError.Path.Append(responseName))
114+
var errorWithPath = ErrorBuilder.FromError(error)
115+
.SetPath(path.Append(responseName))
110116
.AddLocation(fieldResult.Selection.SyntaxNodes[0].Node)
111117
.Build();
112118

113-
_errors.Add(error);
119+
_errors.Add(errorWithPath);
114120

115121
if (_errorHandling is ErrorHandling.Propagate && fieldResult.Selection.Type.IsNonNullType())
116122
{

src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/SubgraphErrorTests.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,82 @@ public async Task Error_On_Lookup_Field()
299299
response.MatchSnapshot();
300300
}
301301

302+
[Fact]
303+
public async Task Error_On_Lookup_Field_In_List()
304+
{
305+
// arrange
306+
using var server1 = CreateSourceSchema(
307+
"A",
308+
b => b.AddQueryType<SourceSchema1.Query>());
309+
310+
using var server2 = CreateSourceSchema(
311+
"B",
312+
b => b.AddQueryType<SourceSchema7.Query>());
313+
314+
// act
315+
using var gateway = await CreateCompositeSchemaAsync(
316+
[
317+
("A", server1),
318+
("B", server2),
319+
]);
320+
321+
// assert
322+
using var client = GraphQLHttpClient.Create(gateway.CreateClient());
323+
324+
using var result = await client.PostAsync(
325+
"""
326+
{
327+
topProducts {
328+
price
329+
name
330+
}
331+
}
332+
""",
333+
new Uri("http://localhost:5000/graphql"));
334+
335+
// act
336+
using var response = await result.ReadAsResultAsync();
337+
response.MatchSnapshot();
338+
}
339+
340+
[Fact]
341+
public async Task Error_On_Lookup_Field_In_List_Leaf_NonNull()
342+
{
343+
// arrange
344+
using var server1 = CreateSourceSchema(
345+
"A",
346+
b => b.AddQueryType<SourceSchema1.Query>());
347+
348+
using var server2 = CreateSourceSchema(
349+
"B",
350+
b => b.AddQueryType<SourceSchema3.Query>());
351+
352+
// act
353+
using var gateway = await CreateCompositeSchemaAsync(
354+
[
355+
("A", server1),
356+
("B", server2),
357+
]);
358+
359+
// assert
360+
using var client = GraphQLHttpClient.Create(gateway.CreateClient());
361+
362+
using var result = await client.PostAsync(
363+
"""
364+
{
365+
topProducts {
366+
price
367+
name
368+
}
369+
}
370+
""",
371+
new Uri("http://localhost:5000/graphql"));
372+
373+
// act
374+
using var response = await result.ReadAsResultAsync();
375+
response.MatchSnapshot();
376+
}
377+
302378
[Fact]
303379
public async Task No_Data_And_Error_With_Path_For_Lookup()
304380
{
@@ -686,4 +762,20 @@ public string GetName(IResolverContext context)
686762
}
687763
}
688764
}
765+
766+
public static class SourceSchema7
767+
{
768+
public class Query
769+
{
770+
[Lookup]
771+
public Product? GetProductById(int id, IResolverContext context)
772+
=> throw new GraphQLException(ErrorBuilder.New().SetMessage("Could not resolve Product")
773+
.SetPath(context.Path).Build());
774+
}
775+
776+
public record Product(int Id)
777+
{
778+
public string? GetName() => "Product " + Id;
779+
}
780+
}
689781
}

src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SubgraphErrorTests.Error_On_Lookup_Field.snap

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
{
2-
"data": {
3-
"topProduct": {
4-
"price": 13.99,
5-
"name": null
6-
}
7-
},
82
"errors": [
93
{
104
"message": "Could not resolve Product",

0 commit comments

Comments
 (0)