Skip to content

Commit e6f96fe

Browse files
Some more changes
1 parent 39277e0 commit e6f96fe

File tree

9 files changed

+218
-120
lines changed

9 files changed

+218
-120
lines changed

src/HotChocolate/Core/src/Execution.Abstractions/Path.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,62 @@ public Path Append(int index)
6767
return new IndexerPathSegment(this, index);
6868
}
6969

70+
/// <summary>
71+
/// Appends another path to this path.
72+
/// </summary>
73+
/// <param name="path">
74+
/// The other path.
75+
/// </param>
76+
/// <returns>
77+
/// the combined path.
78+
/// </returns>
79+
public Path Append(Path path)
80+
{
81+
ArgumentNullException.ThrowIfNull(path);
82+
83+
if (path.IsRoot)
84+
{
85+
return this;
86+
}
87+
88+
var stack = new Stack<object>();
89+
var current = path;
90+
91+
while (!current.IsRoot)
92+
{
93+
switch (current)
94+
{
95+
case IndexerPathSegment indexer:
96+
stack.Push(indexer.Index);
97+
break;
98+
99+
case NamePathSegment name:
100+
stack.Push(name.Name);
101+
break;
102+
103+
default:
104+
throw new NotSupportedException("Unsupported path segment type.");
105+
}
106+
107+
current = current.Parent;
108+
}
109+
110+
var newPath = this;
111+
112+
while (stack.Count > 0)
113+
{
114+
var segment = stack.Pop();
115+
newPath = segment switch
116+
{
117+
string name => newPath.Append(name),
118+
int index => newPath.Append(index),
119+
_ => throw new NotSupportedException("Unsupported path segment type.")
120+
};
121+
}
122+
123+
return newPath;
124+
}
125+
70126
/// <summary>
71127
/// Generates a string that represents the current path.
72128
/// </summary>
Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,38 @@
1-
using System.Text.Json;
2-
31
namespace HotChocolate.Fusion.Execution.Clients;
42

53
public sealed class ErrorTrie : Dictionary<object, ErrorTrie>
64
{
7-
public JsonElement Error { get; set; }
5+
public IError? Error { get; set; }
86

9-
public JsonElement? GetFirstError()
7+
public (object[] Path, IError Error)? FindPathToFirstError()
108
{
9+
if (Error is not null)
10+
{
11+
return ([], Error);
12+
}
13+
14+
var stack = new Stack<(ErrorTrie Node, List<object> Path)>();
15+
16+
foreach (var kvp in this)
17+
{
18+
stack.Push((kvp.Value, [kvp.Key]));
19+
}
20+
21+
while (stack.Count > 0)
22+
{
23+
var (node, path) = stack.Pop();
24+
25+
if (node.Error is not null)
26+
{
27+
return ([..path], node.Error);
28+
}
29+
30+
foreach (var kvp in node)
31+
{
32+
stack.Push((kvp.Value, [..path, kvp.Key]));
33+
}
34+
}
35+
1136
return null;
1237
}
1338
}

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

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public sealed class SourceSchemaErrors
77
/// <summary>
88
/// Errors without a path.
99
/// </summary>
10-
public required List<JsonElement>? RootErrors { get; init; }
10+
public required List<IError>? RootErrors { get; init; }
1111

1212
public required ErrorTrie Trie { get; init; }
1313

@@ -18,47 +18,46 @@ public sealed class SourceSchemaErrors
1818
return null;
1919
}
2020

21-
List<JsonElement>? rootErrors = null;
21+
List<IError>? rootErrors = null;
2222
ErrorTrie root = new ErrorTrie();
2323

24-
foreach (var error in json.EnumerateArray())
24+
foreach (var jsonError in json.EnumerateArray())
2525
{
2626
var currentTrie = root;
2727

28-
if (!error.TryGetProperty("path", out var path) || path.ValueKind != JsonValueKind.Array)
28+
var error = CreateError(jsonError);
29+
30+
if (error is null)
31+
{
32+
continue;
33+
}
34+
35+
if (error.Path is null)
2936
{
3037
rootErrors ??= [];
3138
rootErrors.Add(error);
3239
continue;
3340
}
3441

35-
for (int i = 0, len = path.GetArrayLength(); i < len; ++i)
36-
{
37-
var pathSegment = path[i];
38-
object? pathSegmentValue = pathSegment.ValueKind switch
39-
{
40-
JsonValueKind.String => pathSegment.GetString(),
41-
JsonValueKind.Number => pathSegment.GetInt32(),
42-
_ => null
43-
};
42+
var pathSegments = error.Path.ToList();
43+
var lastPathIndex = pathSegments.Count - 1;
4444

45-
if (pathSegmentValue is null)
46-
{
47-
break;
48-
}
45+
for (var i = 0; i < pathSegments.Count; i++)
46+
{
47+
var pathSegment = pathSegments[i];
4948

50-
if (currentTrie.TryGetValue(pathSegmentValue, out var trieAtPath))
49+
if (currentTrie.TryGetValue(pathSegment, out var trieAtPath))
5150
{
5251
currentTrie = trieAtPath;
5352
}
5453
else
5554
{
5655
var newTrie = new ErrorTrie();
57-
currentTrie[pathSegmentValue] = newTrie;
56+
currentTrie[pathSegment] = newTrie;
5857
currentTrie = newTrie;
5958
}
6059

61-
if (i == len - 1)
60+
if (i == lastPathIndex)
6261
{
6362
currentTrie.Error = error;
6463
}
@@ -67,4 +66,60 @@ public sealed class SourceSchemaErrors
6766

6867
return new SourceSchemaErrors { RootErrors = rootErrors, Trie = root };
6968
}
69+
70+
private static IError? CreateError(JsonElement jsonError)
71+
{
72+
if (jsonError.ValueKind is not JsonValueKind.Object)
73+
{
74+
return null;
75+
}
76+
77+
if (jsonError.TryGetProperty("message", out var message)
78+
&& message.ValueKind is JsonValueKind.String)
79+
{
80+
var errorBuilder = ErrorBuilder.New()
81+
.SetMessage(message.GetString()!);
82+
83+
if (jsonError.TryGetProperty("path", out var path) && path.ValueKind == JsonValueKind.Array)
84+
{
85+
errorBuilder.SetPath(CreatePathFromJson(path));
86+
}
87+
88+
if (jsonError.TryGetProperty("code", out var code)
89+
&& code.ValueKind is JsonValueKind.String)
90+
{
91+
errorBuilder.SetCode(code.GetString());
92+
}
93+
94+
if (jsonError.TryGetProperty("extensions", out var extensions)
95+
&& extensions.ValueKind is JsonValueKind.Object)
96+
{
97+
foreach (var property in extensions.EnumerateObject())
98+
{
99+
errorBuilder.SetExtension(property.Name, property.Value);
100+
}
101+
}
102+
103+
return errorBuilder.Build();
104+
}
105+
106+
return null;
107+
}
108+
109+
private static Path CreatePathFromJson(JsonElement errorSubPath)
110+
{
111+
var path = Path.Root;
112+
113+
for (var i = 0; i < errorSubPath.GetArrayLength(); i++)
114+
{
115+
path = errorSubPath[i] switch
116+
{
117+
{ ValueKind: JsonValueKind.String } nameElement => path.Append(nameElement.GetString()!),
118+
{ ValueKind: JsonValueKind.Number } indexElement => path.Append(indexElement.GetInt32()),
119+
_ => throw new InvalidOperationException("The error path contains an unsupported element."),
120+
};
121+
}
122+
123+
return path;
124+
}
70125
}

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

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

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

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public bool AddPartialResults(
8080
nameof(results));
8181
}
8282

83-
var dataElements = ArrayPool<JsonElement?>.Shared.Rent(results.Length);
83+
var dataElements = ArrayPool<JsonElement>.Shared.Rent(results.Length);
8484
var errorTries = ArrayPool<ErrorTrie?>.Shared.Rent(results.Length);
8585
var dataElementsSpan = dataElements.AsSpan()[..results.Length];
8686
var errorTriesSpan = errorTries.AsSpan()[..results.Length];
@@ -99,7 +99,7 @@ public bool AddPartialResults(
9999

100100
if (result.Errors?.RootErrors is { } rootErrors)
101101
{
102-
RegisterErrors(_errors, rootErrors);
102+
_errors.AddRange(rootErrors);
103103
}
104104

105105
dataElement = GetDataElement(sourcePath, result.Data);
@@ -114,31 +114,11 @@ public bool AddPartialResults(
114114
}
115115
finally
116116
{
117-
ArrayPool<JsonElement?>.Shared.Return(dataElements);
117+
ArrayPool<JsonElement>.Shared.Return(dataElements);
118118
ArrayPool<ErrorTrie?>.Shared.Return(errorTries);
119119
}
120120
}
121121

122-
private static void RegisterErrors(List<IError> errors, List<JsonElement> jsonErrors)
123-
{
124-
var jsonErrorsSpan = CollectionsMarshal.AsSpan(jsonErrors);
125-
ref var jsonError = ref MemoryMarshal.GetReference(jsonErrorsSpan);
126-
ref var end = ref Unsafe.Add(ref jsonError, jsonErrorsSpan.Length);
127-
128-
while (Unsafe.IsAddressLessThan(ref jsonError, ref end))
129-
{
130-
var errorBuilder = ErrorUtils.CreateErrorBuilder(jsonError);
131-
132-
if (errorBuilder is not null)
133-
{
134-
var error = errorBuilder.Build();
135-
errors.Add(error);
136-
}
137-
138-
jsonError = ref Unsafe.Add(ref jsonError, 1)!;
139-
}
140-
}
141-
142122
public void AddPartialResults(ObjectResult result, ReadOnlySpan<Selection> selections)
143123
{
144124
ObjectDisposedException.ThrowIf(_disposed, this);
@@ -173,7 +153,7 @@ public void AddPartialResults(ObjectResult result, ReadOnlySpan<Selection> selec
173153

174154
private bool SaveSafe(
175155
ReadOnlySpan<SourceSchemaResult> results,
176-
ReadOnlySpan<JsonElement?> dataElements,
156+
ReadOnlySpan<JsonElement> dataElements,
177157
ReadOnlySpan<ErrorTrie?> errorTries)
178158
{
179159
_lock.EnterWriteLock();
@@ -410,7 +390,7 @@ public PooledArrayWriter CreateRentedBuffer()
410390
return buffer;
411391
}
412392

413-
private static JsonElement? GetDataElement(SelectionPath sourcePath, JsonElement data)
393+
private static JsonElement GetDataElement(SelectionPath sourcePath, JsonElement data)
414394
{
415395
if (sourcePath.IsRoot)
416396
{
@@ -424,7 +404,7 @@ public PooledArrayWriter CreateRentedBuffer()
424404
var segment = sourcePath.Segments[i];
425405
if (current.ValueKind != JsonValueKind.Object || !current.TryGetProperty(segment.Name, out current))
426406
{
427-
return null;
407+
return new JsonElement(); // TODO: Is this bad?
428408
}
429409
}
430410

0 commit comments

Comments
 (0)