Skip to content

Commit

Permalink
Fixed StrawberryShake result has empty Extensions Issue (#5967)
Browse files Browse the repository at this point in the history
  • Loading branch information
anton-gogolev authored and michaelstaib committed May 4, 2023
1 parent dfb857d commit e895378
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 3 deletions.
18 changes: 18 additions & 0 deletions src/StrawberryShake/Client/src/Core/Json/JsonExtensionParser.cs
@@ -0,0 +1,18 @@
using System.Collections.Generic;
using System.Text.Json;

namespace StrawberryShake.Json;

internal static class JsonExtensionParser
{
public static IReadOnlyDictionary<string, object?>? ParseExtensions(JsonElement result)
{
if (result is { ValueKind: JsonValueKind.Object })
{
var extensions = JsonSerializationHelper.ReadValue(result);
return (IReadOnlyDictionary<string, object?>?)extensions;
}

return null;
}
}
11 changes: 10 additions & 1 deletion src/StrawberryShake/Client/src/Core/OperationResultBuilder.cs
Expand Up @@ -25,6 +25,7 @@ public abstract class OperationResultBuilder<TResultData>
TResultData? data = null;
IOperationResultDataInfo? dataInfo = null;
IReadOnlyList<IClientError>? errors = null;
IReadOnlyDictionary<string, object?>? extensions = null;

try
{
Expand All @@ -42,6 +43,14 @@ public abstract class OperationResultBuilder<TResultData>
{
errors = JsonErrorParser.ParseErrors(errorsProp);
}

if (body.RootElement.TryGetProperty(
ResultFields.Extensions,
out var extensionsProp) &&
extensionsProp.ValueKind is JsonValueKind.Object)
{
extensions = JsonExtensionParser.ParseExtensions(extensionsProp);
}
}
}
catch (Exception ex)
Expand Down Expand Up @@ -88,7 +97,7 @@ public abstract class OperationResultBuilder<TResultData>
dataInfo,
ResultDataFactory,
errors,
response.Extensions,
extensions,
response.ContextData);
}

Expand Down
1 change: 1 addition & 0 deletions src/StrawberryShake/Client/src/Core/ResultFields.cs
Expand Up @@ -7,4 +7,5 @@ public static class ResultFields
public const string Path = "path";
public const string Label = "label";
public const string HasNext = "hasNext";
public const string Extensions = "extensions";
}
@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Text.Json;

namespace StrawberryShake;

public class OperationResultBuilderTests
{
[Fact]
public void Build_With_Extensions()
{
// arrange
var factory = new DocumentDataFactory();
var builder = new DocumentOperationResultBuilder(factory);

// According to the current design, all implementations of IConnection operate
// on JsonDocuments which are deserialized straight from response streams and
// very few properties in the Response object are in fact ever initialized,
// including Response.Extensions. It is therefore safe to assume that, at
// least for now, OperationResultBuilder is the best place to actually parse
// and extract "extensions".
var body = JsonDocument.Parse(@"{""data"": { }, ""extensions"": { ""a"": 1, ""b"": { ""c"": ""Strawberry"" }, ""d"": 3.14 } }");
var response = new Response<JsonDocument>(body, null);

// act
var result = builder.Build(response);

// assert
Assert.NotEmpty(result.Extensions);
Assert.Equal(1L, result.Extensions["a"]);

var b = (IReadOnlyDictionary<string, object?>?)result.Extensions["b"];

Assert.NotNull(b);
Assert.Equal("Strawberry", b["c"]);

Assert.Equal(3.14, result.Extensions["d"]);
}

internal class Document
{
}

internal class DocumentDataInfo : IOperationResultDataInfo
{
public IReadOnlyCollection<EntityId> EntityIds { get; } = ArraySegment<EntityId>.Empty;

public ulong Version { get; } = 0;

public IOperationResultDataInfo WithVersion(ulong version)
{
throw new NotImplementedException();
}
}

internal class DocumentDataFactory : IOperationResultDataFactory<Document>
{
public Type ResultType { get => typeof(Document); }

public Document Create(IOperationResultDataInfo dataInfo, IEntityStoreSnapshot? snapshot = null)
{
return new Document();
}

object IOperationResultDataFactory.Create(IOperationResultDataInfo dataInfo, IEntityStoreSnapshot? snapshot)
{
return Create(dataInfo, snapshot);
}
}

internal class DocumentOperationResultBuilder : OperationResultBuilder<Document>
{
public DocumentOperationResultBuilder(IOperationResultDataFactory<Document> resultDataFactory)
{
ResultDataFactory = resultDataFactory;
}

protected override IOperationResultDataFactory<Document> ResultDataFactory { get; }

protected override IOperationResultDataInfo BuildData(JsonElement obj)
{
return new DocumentDataInfo();
}
}
}
Expand Up @@ -148,8 +148,7 @@ public static IReadOnlyList<IError> AssertError(params string[] fileNames)
documents.ToString().MatchSnapshot();
}

IReadOnlyList<Diagnostic> diagnostics =
CSharpCompiler.GetDiagnosticErrors(documents.ToString());
var diagnostics = CSharpCompiler.GetDiagnosticErrors(documents.ToString());

if (skipWarnings)
{
Expand Down

0 comments on commit e895378

Please sign in to comment.