Skip to content

Commit 6df0802

Browse files
authored
Fixed issue with defer path when defers are nested. (#7605)
1 parent ddd2045 commit 6df0802

22 files changed

+194
-57
lines changed

src/HotChocolate/Core/src/Execution/Processing/DeferredExecutionTask.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,9 @@ public void Begin(OperationContextOwner operationContextOwner, uint resultId, ui
5959
Task.Factory.StartNew(
6060
() =>
6161
{
62-
ExecutionContext.Run(capturedContext, (state) =>
63-
ExecuteAsync(operationContextOwner, resultId, parentResultId, patchId),
62+
ExecutionContext.Run(
63+
capturedContext,
64+
_ => ExecuteAsync(operationContextOwner, resultId, parentResultId, patchId),
6465
null);
6566
},
6667
default,

src/HotChocolate/Core/src/Execution/Processing/PathHelper.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,19 @@ internal static class PathHelper
88
private const int _initialPathLength = 64;
99

1010
public static Path CreatePathFromContext(ObjectResult parent)
11-
=> parent.Parent is null ? Path.Root : CreatePath(parent);
11+
{
12+
if (parent.Parent is null)
13+
{
14+
if (parent.PatchPath is null)
15+
{
16+
return Path.Root;
17+
}
18+
19+
return parent.PatchPath;
20+
}
21+
22+
return CreatePath(parent);
23+
}
1224

1325
public static Path CreatePathFromContext(ISelection selection, ResultData parent, int index)
1426
=> parent switch
@@ -37,17 +49,19 @@ private static Path CreatePath(ResultData parent, object segmentValue)
3749
{
3850
var segments = ArrayPool<object>.Shared.Rent(_initialPathLength);
3951
segments[0] = segmentValue;
40-
var length = Build(segments, parent);
41-
var path = CreatePath(parent.PatchPath, segments, length);
52+
var current = parent;
53+
var length = Build(segments, ref current);
54+
var path = CreatePath(current.PatchPath, segments, length);
4255
ArrayPool<object>.Shared.Return(segments);
4356
return path;
4457
}
4558

4659
private static Path CreatePath(ResultData parent)
4760
{
4861
var segments = ArrayPool<object>.Shared.Rent(_initialPathLength);
49-
var length = Build(segments, parent, 0);
50-
var path = CreatePath(parent.PatchPath, segments, length);
62+
var current = parent;
63+
var length = Build(segments, ref current, 0);
64+
var path = CreatePath(current.PatchPath, segments, length);
5165
ArrayPool<object>.Shared.Return(segments);
5266
return path;
5367
}
@@ -73,7 +87,7 @@ private static Path CreatePath(Path? patchPath, object[] segments, int length)
7387
return path;
7488
}
7589

76-
private static int Build(object[] segments, ResultData parent, int start = 1)
90+
private static int Build(object[] segments, ref ResultData parent, int start = 1)
7791
{
7892
var segment = start;
7993
var current = parent;
@@ -117,6 +131,7 @@ private static int Build(object[] segments, ResultData parent, int start = 1)
117131
}
118132
}
119133

134+
parent = current;
120135
return segment;
121136
}
122137
}

src/HotChocolate/Core/test/Execution.Tests/DeferAndStreamTestSchema.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ public async Task<bool> Wait(int m, CancellationToken ct)
6464

6565
public async Task<Stateful> EnsureState()
6666
{
67-
await Task.Delay(150);
67+
var random = new Random();
68+
await Task.Delay(random.Next(500, 1000));
6869
return new Stateful();
6970
}
7071
}
@@ -92,7 +93,25 @@ public class Stateful
9293
{
9394
public async Task<string> GetState([GlobalState] string requestState)
9495
{
95-
await Task.Delay(250);
96+
var random = new Random();
97+
await Task.Delay(random.Next(1000, 5000));
98+
return requestState;
99+
}
100+
101+
public async Task<MoreState> GetMore()
102+
{
103+
var random = new Random();
104+
await Task.Delay(random.Next(1000, 5000));
105+
return new MoreState();
106+
}
107+
}
108+
109+
public class MoreState
110+
{
111+
public async Task<string> GetStuff([GlobalState] string requestState)
112+
{
113+
var random = new Random();
114+
await Task.Delay(random.Next(1000, 5000));
96115
return requestState;
97116
}
98117
}

src/HotChocolate/Core/test/Execution.Tests/DeferTests.cs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ ... @defer {
2222
}
2323
""");
2424

25-
Assert.IsType<ResponseStream>(result).MatchSnapshot();
25+
Assert.IsType<ResponseStream>(result).MatchMarkdownSnapshot();
2626
}
2727

2828
[Fact]
@@ -46,7 +46,7 @@ ... @defer {
4646
}
4747
""");
4848

49-
Assert.IsType<ResponseStream>(result).MatchSnapshot();
49+
Assert.IsType<ResponseStream>(result).MatchMarkdownSnapshot();
5050
}
5151

5252
[Fact]
@@ -65,7 +65,7 @@ ... @defer(label: ""abc"") {
6565
}
6666
}");
6767

68-
Assert.IsType<ResponseStream>(result).MatchSnapshot();
68+
Assert.IsType<ResponseStream>(result).MatchMarkdownSnapshot();
6969
}
7070

7171
[Fact]
@@ -86,7 +86,7 @@ ... @defer(if: false) {
8686
}
8787
""");
8888

89-
Assert.IsType<OperationResult>(result).MatchSnapshot();
89+
Assert.IsType<OperationResult>(result).MatchMarkdownSnapshot();
9090
}
9191

9292
[Fact]
@@ -112,7 +112,7 @@ ... @defer(if: $defer) {
112112
.SetVariableValues(new Dictionary<string, object?> { { "defer", false }, })
113113
.Build());
114114

115-
Assert.IsType<OperationResult>(result).MatchSnapshot();
115+
Assert.IsType<OperationResult>(result).MatchMarkdownSnapshot();
116116
}
117117

118118
[Fact]
@@ -135,7 +135,7 @@ fragment Foo on Query {
135135
}
136136
""");
137137

138-
Assert.IsType<ResponseStream>(result).MatchSnapshot();
138+
Assert.IsType<ResponseStream>(result).MatchMarkdownSnapshot();
139139
}
140140

141141
[Fact]
@@ -161,7 +161,7 @@ ... @defer {
161161
}
162162
""");
163163

164-
Assert.IsType<ResponseStream>(result).MatchSnapshot();
164+
Assert.IsType<ResponseStream>(result).MatchMarkdownSnapshot();
165165
}
166166

167167
[Fact]
@@ -184,7 +184,7 @@ fragment Foo on Query {
184184
}
185185
""");
186186

187-
Assert.IsType<ResponseStream>(result).MatchSnapshot();
187+
Assert.IsType<ResponseStream>(result).MatchMarkdownSnapshot();
188188
}
189189

190190
[Fact]
@@ -207,7 +207,7 @@ fragment Foo on Query {
207207
}
208208
""");
209209

210-
Assert.IsType<OperationResult>(result).MatchSnapshot();
210+
Assert.IsType<OperationResult>(result).MatchMarkdownSnapshot();
211211
}
212212

213213
[Fact]
@@ -235,7 +235,7 @@ fragment Foo on Query {
235235
.SetVariableValues(new Dictionary<string, object?> { { "defer", false }, })
236236
.Build());
237237

238-
Assert.IsType<OperationResult>(result).MatchSnapshot();
238+
Assert.IsType<OperationResult>(result).MatchMarkdownSnapshot();
239239
}
240240

241241
[Fact]
@@ -263,7 +263,39 @@ ... @defer {
263263
.SetGlobalState("requestState", "state 123")
264264
.Build());
265265

266-
Assert.IsType<ResponseStream>(result).MatchSnapshot();
266+
Assert.IsType<ResponseStream>(result).MatchMarkdownSnapshot();
267+
}
268+
269+
[Fact]
270+
public async Task Ensure_GlobalState_Is_Passed_To_DeferContext_Stacked_Defer_2()
271+
{
272+
// arrange
273+
var executor = await DeferAndStreamTestSchema.CreateAsync();
274+
275+
// act
276+
await using var response = await executor.ExecuteAsync(
277+
OperationRequestBuilder
278+
.New()
279+
.SetDocument(
280+
"""
281+
{
282+
... @defer {
283+
e: ensureState {
284+
... @defer {
285+
more {
286+
... @defer {
287+
stuff
288+
}
289+
}
290+
}
291+
}
292+
}
293+
}
294+
""")
295+
.SetGlobalState("requestState", "state 123")
296+
.Build());
297+
298+
Assert.IsType<ResponseStream>(response).MatchMarkdownSnapshot();
267299
}
268300

269301
[Fact]
@@ -289,6 +321,6 @@ ... @defer {
289321
.SetGlobalState("requestState", "state 123")
290322
.Build());
291323

292-
Assert.IsType<ResponseStream>(result).MatchSnapshot();
324+
Assert.IsType<ResponseStream>(result).MatchMarkdownSnapshot();
293325
}
294326
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
# Ensure_GlobalState_Is_Passed_To_DeferContext_Single_Defer
2+
3+
```text
14
{
25
"data": {
36
"ensureState": {
47
"state": "state 123"
58
}
69
}
710
}
11+
12+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Ensure_GlobalState_Is_Passed_To_DeferContext_Stacked_Defer
2+
3+
```text
4+
{
5+
"data": {
6+
"ensureState": {
7+
"state": "state 123"
8+
}
9+
}
10+
}
11+
12+
```

src/HotChocolate/Core/test/Execution.Tests/__snapshots__/DeferTests.Ensure_GlobalState_Is_Passed_To_DeferContext_Stacked_Defer.snap

Lines changed: 0 additions & 7 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Ensure_GlobalState_Is_Passed_To_DeferContext_Stacked_Defer_2
2+
3+
```text
4+
{
5+
"data": {
6+
"e": {
7+
"more": {
8+
"stuff": "state 123"
9+
}
10+
}
11+
}
12+
}
13+
14+
```
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
# FragmentSpread_Defer
2+
3+
```text
14
{
25
"data": {
36
"person": {
47
"id": "UGVyc29uOjE="
58
}
69
}
710
}
11+
12+
```
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
# FragmentSpread_Defer_If_Set_To_false
2+
3+
```json
14
{
25
"data": {
36
"person": {
47
"id": "UGVyc29uOjE="
58
}
69
}
710
}
11+
```

0 commit comments

Comments
 (0)