Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,12 @@ private static void InitializeRequests(FusionExecutionContext context, List<Exec
private void ProcessResult(
FusionExecutionContext context,
GraphQLResponse response,
BatchExecutionState[] batchExecutionState,
List<BatchExecutionState> batchExecutionState,
string subgraphName)
{
var result = UnwrapResult(response, Requires);
ref var batchState = ref MemoryMarshal.GetArrayDataReference(batchExecutionState);
ref var end = ref Unsafe.Add(ref batchState, batchExecutionState.Length);
ref var batchState = ref MemoryMarshal.GetReference(CollectionsMarshal.AsSpan(batchExecutionState));
ref var end = ref Unsafe.Add(ref batchState, batchExecutionState.Count);
var pathLength = Path.Length;
var first = true;

Expand Down Expand Up @@ -195,13 +195,13 @@ private void ProcessResult(
}

private static Dictionary<string, IValueNode> BuildVariables(
BatchExecutionState[] batchExecutionState,
List<BatchExecutionState> batchExecutionState,
string[] requires,
Dictionary<string, ITypeNode> argumentTypes)
{
var first = batchExecutionState[0];

if (batchExecutionState.Length == 1)
if (batchExecutionState.Count == 1)
{
return first.VariableValues;
}
Expand All @@ -210,8 +210,8 @@ private static Dictionary<string, IValueNode> BuildVariables(
var uniqueState = new List<BatchExecutionState>();
var processed = new HashSet<string>();

ref var batchState = ref MemoryMarshal.GetArrayDataReference(batchExecutionState);
ref var end = ref Unsafe.Add(ref batchState, batchExecutionState.Length);
ref var batchState = ref MemoryMarshal.GetReference(CollectionsMarshal.AsSpan(batchExecutionState));
ref var end = ref Unsafe.Add(ref batchState, batchExecutionState.Count);

while (Unsafe.IsAddressLessThan(ref batchState, ref end))
{
Expand Down Expand Up @@ -339,44 +339,38 @@ private static JsonElement LiftData(JsonElement data, string[] path)
return current;
}

private static BatchExecutionState[] CreateBatchBatchState(List<ExecutionState> executionState, string[] requires)
private static List<BatchExecutionState> CreateBatchBatchState(List<ExecutionState> executionState, string[] requires)
{
var batchExecutionState = new BatchExecutionState[executionState.Count];
var batchExecutionState = new List<BatchExecutionState>(executionState.Count);

ref var state = ref MemoryMarshal.GetReference(CollectionsMarshal.AsSpan(executionState));
ref var batchState = ref MemoryMarshal.GetArrayDataReference(batchExecutionState);
ref var end = ref Unsafe.Add(ref state, executionState.Count);

if (requires.Length == 1)
{
while (Unsafe.IsAddressLessThan(ref state, ref end))
{
var key = FormatKeyValue(state.VariableValues[requires[0]]);
batchState = new BatchExecutionState(key, state);
if (state.VariableValues.ContainsKey(requires[0]))
Comment thread
michaelstaib marked this conversation as resolved.
Resolved
{
var key = FormatKeyValue(state.VariableValues[requires[0]]);
var batchState = new BatchExecutionState(key, state);

batchExecutionState.Add(batchState);
}

state = ref Unsafe.Add(ref state, 1)!;
batchState = ref Unsafe.Add(ref batchState, 1)!;
}
}
else
{
var keyBuilder = new StringBuilder();

while (Unsafe.IsAddressLessThan(ref state, ref end))
{
ref var key = ref MemoryMarshal.GetArrayDataReference(requires);
ref var keyEnd = ref Unsafe.Add(ref key, requires.Length);

while (Unsafe.IsAddressLessThan(ref key, ref keyEnd))
{
keyBuilder.Append(FormatKeyValue(state.VariableValues[key]));
key = ref Unsafe.Add(ref key, 1)!;
}
var lastKey = requires[^1];
var batchState = new BatchExecutionState(lastKey, state);

batchState = new BatchExecutionState(key, state);
batchExecutionState.Add(batchState);

state = ref Unsafe.Add(ref state, 1)!;
batchState = ref Unsafe.Add(ref batchState, 1)!;
Comment thread
michaelstaib marked this conversation as resolved.
Resolved
}
}

Expand Down
177 changes: 133 additions & 44 deletions src/HotChocolate/Fusion/test/Core.Tests/DemoIntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,21 +134,21 @@ type Product implements Node {
using var subgraphs = new TestSubgraphCollection(output, [subgraphA, subgraphB]);
var executor = await subgraphs.GetExecutorAsync();
var request = Parse("""
query {
productsA {
id
name
price
reviewCount
}
productsB {
id
name
price
reviewCount
}
}
""");
query {
productsA {
id
name
price
reviewCount
}
productsB {
id
name
price
reviewCount
}
}
""");

// act
var result = await executor.ExecuteAsync(
Expand Down Expand Up @@ -260,10 +260,10 @@ public async Task Authors_And_Reviews_Query_GetUserReviews_Report_Cost()
// act
var fusionGraph = await new FusionGraphComposer(logFactory: _logFactory)
.ComposeAsync(
[
demoProject.Reviews2.ToConfiguration(Reviews2ExtensionWithCostSdl),
demoProject.Accounts.ToConfiguration(AccountsExtensionWithCostSdl)
]);
[
demoProject.Reviews2.ToConfiguration(Reviews2ExtensionWithCostSdl),
demoProject.Accounts.ToConfiguration(AccountsExtensionWithCostSdl)
]);

var executor = await new ServiceCollection()
.AddSingleton(demoProject.HttpClientFactory)
Expand Down Expand Up @@ -1656,11 +1656,7 @@ public async Task Forward_Nested_Variables_No_OpName()
.New()
.SetDocument(request)
.SetVariableValues(
new Dictionary<string, object?>
{
{ "id", "UHJvZHVjdDox" },
{ "first", 1 },
})
new Dictionary<string, object?> { { "id", "UHJvZHVjdDox" }, { "first", 1 }, })
.Build());

// assert
Expand Down Expand Up @@ -2028,10 +2024,7 @@ public async Task GetFirstPage_With_After_Null()

// act
var fusionGraph = await new FusionGraphComposer(logFactory: _logFactory).ComposeAsync(
new[]
{
demoProject.Appointment.ToConfiguration(),
},
new[] { demoProject.Appointment.ToConfiguration(), },
new FusionFeatureCollection(FusionFeatures.NodeField));

var executor = await new ServiceCollection()
Expand Down Expand Up @@ -2232,6 +2225,114 @@ type ResaleSurveyFeedback {
await snapshot.MatchMarkdownAsync();
}

[Fact]
public async Task BatchExecutionState_With_Multiple_Variable_Values_Some_Items_Null()
{
// arrange
var subgraphA = await TestSubgraph.CreateAsync(
"""
type Query {
node(id: ID!): Node
nodes(ids: [ID!]!): [Node]!
}

interface Node {
id: ID!
}

type User implements Node {
id: ID!
displayName: String!
}
""");
var subgraphB = await TestSubgraph.CreateAsync(
"""
type Query {
node(id: ID!): Node
nodes(ids: [ID!]!): [Node]! @null(atIndex: 1)
userBySlug(slug: String!): User
}

interface Node {
id: ID!
}

type User implements Node {
relativeUrl: String!
id: ID!
}
""");
var subgraphC = await TestSubgraph.CreateAsync(
"""
type Query {
node(id: ID!): Node
nodes(ids: [ID!]!): [Node]!
}

interface Node {
id: ID!
}

type User implements Node {
id: ID!
feedbacks: FeedbacksConnection
}

type FeedbacksConnection {
edges: [FeedbacksEdge!]
}

type FeedbacksEdge {
node: ResaleFeedback!
}

type ResaleFeedback implements Node {
feedback: ResaleSurveyFeedback
id: ID!
}

type ResaleSurveyFeedback {
buyer: User
}
""");

using var subgraphs = new TestSubgraphCollection(output, [subgraphA, subgraphB, subgraphC]);
var executor = await subgraphs.GetExecutorAsync();

var request = Parse(
"""
query {
userBySlug(slug: "me") {
feedbacks {
edges {
node {
feedback {
buyer {
relativeUrl
displayName
}
}
}
}
}
}
}

""");

// act
await using var result = await executor.ExecuteAsync(
OperationRequestBuilder
.New()
.SetDocument(request)
.Build());

// assert
var snapshot = new Snapshot();
CollectSnapshotData(snapshot, request, result);
await snapshot.MatchMarkdownAsync();
}

[Fact]
public async Task BatchExecutionState_With_Multiple_Variable_Values_And_Forwarded_Variable()
{
Expand Down Expand Up @@ -2401,10 +2502,7 @@ type Query {
}
}
""")
.SetVariableValues(new Dictionary<string, object?>
{
["productId"] = "UHJvZHVjdAppMzg2MzE4NTk="
})
.SetVariableValues(new Dictionary<string, object?> { ["productId"] = "UHJvZHVjdAppMzg2MzE4NTk=" })
.Build();

// act
Expand Down Expand Up @@ -2478,10 +2576,7 @@ type Query {
}
}
""")
.SetVariableValues(new Dictionary<string, object?>
{
["productId"] = "UHJvZHVjdAppMzg2MzE4NTk="
})
.SetVariableValues(new Dictionary<string, object?> { ["productId"] = "UHJvZHVjdAppMzg2MzE4NTk=" })
.Build();

// act
Expand Down Expand Up @@ -2559,10 +2654,7 @@ type Query {
}
}
""")
.SetVariableValues(new Dictionary<string, object?>
{
["productId"] = "UHJvZHVjdAppMzg2MzE4NTk="
})
.SetVariableValues(new Dictionary<string, object?> { ["productId"] = "UHJvZHVjdAppMzg2MzE4NTk=" })
.Build();

// act
Expand All @@ -2580,10 +2672,7 @@ public async Task Two_Arguments_Differing_Nullability_Does_Not_Duplicate_Forward

// act
var fusionGraph = await new FusionGraphComposer(logFactory: _logFactory).ComposeAsync(
new[]
{
demoProject.Accounts.ToConfiguration(AccountsExtensionSdl)
});
new[] { demoProject.Accounts.ToConfiguration(AccountsExtensionSdl) });

var executor = await new ServiceCollection()
.AddSingleton(demoProject.HttpClientFactory)
Expand Down
Loading