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 @@ -69,7 +69,7 @@ private void CoerceVariableValuesInternal(

var hasValue = hasVariables && variableValues.TryGetProperty(variableName, out propertyValue);

if (!hasValue && variableDefinition.DefaultValue is { Kind: not SyntaxKind.NullValue } defaultValue)
if (!hasValue && variableDefinition.DefaultValue is { } defaultValue)
{
var runtimeValue = _inputParser.ParseLiteral(
defaultValue,
Expand All @@ -88,27 +88,15 @@ private void CoerceVariableValuesInternal(

// if we do not have any value we will not create an entry to the
// coerced variables.
if (!hasValue)
{
continue;
}

coercedValues[variableName] =
new VariableValue(
variableName,
variableType,
null,
NullValueNode.Default);
}
else
{
coercedValues[variableName] =
CoerceVariableValue(
variableDefinition,
variableType,
propertyValue,
context);
continue;
}

coercedValues[variableName] =
CoerceVariableValue(
variableDefinition,
variableType,
propertyValue,
context);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,42 @@ public async Task Pass_In_Sydney_To_NonNullArgument_With_DefaultValue_By_Variabl
result.ToJson().MatchSnapshot();
}

[Fact]
public async Task ExecuteAsync_Should_Pass_Null_When_Omitted_Variable_Has_Null_Default()
{
// arrange
var executor =
await new ServiceCollection()
.AddGraphQL()
.AddQueryType<Query>()
.BuildRequestExecutorAsync(
cancellationToken: TestContext.Current.CancellationToken);

var request =
OperationRequestBuilder
.New()
.SetDocument(
"""
query ($value: Int = null) {
echo(value: $value)
}
""")
.Build();

// act
var result = await executor.ExecuteAsync(request, TestContext.Current.CancellationToken);

// assert
result.MatchInlineSnapshot(
"""
{
"data": {
"echo": null
}
}
""");
}

[Fact]
public async Task ExecuteAsync_Should_Report_Path_Without_Locations_When_Inline_Input_Object_Literal_Has_Invalid_Leaf()
{
Expand Down Expand Up @@ -208,6 +244,9 @@ public async Task ExecuteAsync_Should_Report_Path_Without_Locations_When_Inline_

public class Query
{
public int? Echo(int? value = 5)
=> value;

public string SayHello(string name = "Michael")
=> $"Hello {name}.";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,38 @@ public void Coerce_Nullable_String_Variable_Where_Value_Is_Not_Provided()
Assert.Empty(coercedValues);
}

[Fact]
public void Coerce_Nullable_String_Variable_With_Null_Default_Where_Value_Is_Not_Provided()
{
// arrange
var schema = SchemaBuilder.New().AddStarWarsTypes().Create();

var variableDefinitions = new List<VariableDefinitionNode>
{
new VariableDefinitionNode(
null,
new VariableNode("abc"),
description: null,
new NamedTypeNode("String"),
NullValueNode.Default,
Array.Empty<DirectiveNode>())
};

var coercedValues = new Dictionary<string, VariableValue>();
var featureProvider = new MockFeatureProvider();
var helper = new VariableCoercionHelper(new());

// act
helper.CoerceVariableValues(
schema, variableDefinitions, default, coercedValues, featureProvider);

// assert
var entry = Assert.Single(coercedValues);
Assert.Equal("abc", entry.Key);
Assert.Null(entry.Value.RuntimeValue);
Assert.IsType<NullValueNode>(entry.Value.ValueLiteral);
}

[Fact]
public void Coerce_Nullable_String_Variable_With_Default_Where_Value_Is_Provided()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static bool TryCoerceVariableValues(

var hasValue = hasVariables && variableValues.TryGetProperty(variableName, out propertyValue);

if (!hasValue && variableDefinition.DefaultValue is { Kind: not SyntaxKind.NullValue } defaultValue)
if (!hasValue && variableDefinition.DefaultValue is { } defaultValue)
{
coercedVariableValues[variableName] = new VariableValue(variableName, variableType, defaultValue);
continue;
Expand All @@ -57,36 +57,25 @@ public static bool TryCoerceVariableValues(

// if we do not have any value, we will not create an entry to the
// coerced variables.
if (!hasValue)
{
continue;
}
continue;
}

coercedVariableValues[variableName] =
new VariableValue(
variableName,
variableType,
NullValueNode.Default);
if (TryCoerceVariableValue(
context,
variableDefinition,
variableType,
propertyValue,
ignoreAdditionalInputFields,
ref memory,
out var variableValue,
out error))
{
coercedVariableValues[variableName] = variableValue.Value;
}
else
{
if (TryCoerceVariableValue(
context,
variableDefinition,
variableType,
propertyValue,
ignoreAdditionalInputFields,
ref memory,
out var variableValue,
out error))
{
coercedVariableValues[variableName] = variableValue.Value;
}
else
{
coercedVariableValues = null;
return false;
}
coercedVariableValues = null;
return false;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,38 @@ query testQuery($pet: Pet!) {
await MatchSnapshotAsync(gateway, request, result);
}

[Fact]
public async Task Omitted_Variable_With_Null_Default_Overrides_Argument_Default()
{
// arrange
using var serverA = CreateSourceSchema(
"A",
r => r.AddQueryType<SourceSchema3.Query>());

using var gateway = await CreateCompositeSchemaAsync(
[
("A", serverA)
]);

// act
using var client = GraphQLHttpClient.Create(gateway.CreateClient());

var request = new OperationRequest(
"""
query testQuery($value: Int = null) {
field(arg: $value)
}
""");

using var result = await client.PostAsync(
request,
new Uri("http://localhost:5000/graphql"),
TestContext.Current.CancellationToken);

// assert
await MatchSnapshotAsync(gateway, request, result);
}

public static class SourceSchema1
{
public class Query
Expand All @@ -593,4 +625,12 @@ public class Query
public double GetField(double input) => input;
}
}

public static class SourceSchema3
{
public class Query
{
public int? GetField(int? arg = 5) => arg;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
title: Omitted_Variable_With_Null_Default_Overrides_Argument_Default
request:
document: |
query testQuery($value: Int = null) {
field(arg: $value)
}
response:
body: |
{
"data": {
"field": null
}
}
sourceSchemas:
- name: A
schema: |
schema {
query: Query
}

type Query {
field(arg: Int = 5): Int
}
interactions:
- request:
accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8
document: |
query testQuery_dcfd4e86_1($value: Int = null) {
field(arg: $value)
}
variables: |
{
"value": null
}
response:
results:
- |
{
"data": {
"field": null
}
}
operationPlan:
operation:
- document: |
query testQuery($value: Int = null) {
field(arg: $value)
}
name: testQuery
hash: eb301bff5742ca0de609d91b06ef2ad3
searchSpace: 1
expandedNodes: 1
nodes:
- id: 1
type: Operation
schema: A
operation: |
query testQuery_dcfd4e86_1($value: Int = null) {
field(arg: $value)
}
forwardedVariables:
- value
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,42 @@ public void Error_When_List_Element_Type_Does_Not_Match()
""");
}

[Fact]
public void TryCoerceVariableValues_Should_CoerceNullDefault_When_VariableIsOmitted()
{
// arrange
var schema = ComposeSchema(
"""
type Query {
field(arg: Int = 5): Int
}
""");
var variableDefinition = new VariableDefinitionNode(
null,
new VariableNode("value"),
description: null,
new NamedTypeNode("Int"),
NullValueNode.Default,
Array.Empty<DirectiveNode>());

// act
var success = VariableCoercionHelper.TryCoerceVariableValues(
new MockFeatureProvider(),
schema,
[variableDefinition],
default,
ignoreAdditionalInputFields: false,
out var coercedVariableValues,
out var error);

// assert
Assert.True(success, error?.Message);
Assert.NotNull(coercedVariableValues);
var entry = Assert.Single(coercedVariableValues);
Assert.Equal("value", entry.Key);
Assert.IsType<NullValueNode>(entry.Value.Value);
}

[Fact]
public void TryCoerceVariableValues_Should_PreserveNestedErrorPaths()
{
Expand Down
Loading