Skip to content

Commit

Permalink
Take to account when the same variable is used multiple times with di…
Browse files Browse the repository at this point in the history
…fferent nullability.
  • Loading branch information
byme8 committed Jul 2, 2023
1 parent 13da466 commit 21377ad
Show file tree
Hide file tree
Showing 16 changed files with 172 additions and 29 deletions.
12 changes: 11 additions & 1 deletion src/TestApp/TestStandardLibrary/Generated/GraphQL.g.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// 2266bdc1fc63b8c7e265cf2cfc0db3ba
// a393364977163dc19ab51f098f47eb75
// This file generated for ZeroQL.
// <auto-generated/>
#pragma warning disable 8618
Expand Down Expand Up @@ -339,6 +339,16 @@ public class Mutation : global::ZeroQL.Internal.IMutation
return __AddLimit is null ? throw new NullReferenceException("AddLimit is null but it should not be null. Schema can be outdated.") : selector(__AddLimit);
}

[JsonPropertyName("addLimitNullable")]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public LimitZeroQL __AddLimitNullable { get; set; }

[ZeroQL.GraphQLName("addLimitNullable")]
public T? AddLimitNullable<T>([ZeroQL.GraphQLType("LimitInput")] LimitInputZeroQL? limit = default !, Func<LimitZeroQL, T> selector = default !)
{
return __AddLimitNullable is null ? default : selector(__AddLimitNullable);
}

[JsonPropertyName("addLimit2")]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public Limit2ZeroQL __AddLimit2 { get; set; }
Expand Down
12 changes: 11 additions & 1 deletion src/TestApp/ZeroQL.TestApp/Generated/GraphQL.g.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// 4d263fad3d06404790c84b2b9fdbad61
// aa62e722c7d89055764be10fff77a242
// This file generated for ZeroQL.
// <auto-generated/>
#pragma warning disable 8618
Expand Down Expand Up @@ -339,6 +339,16 @@ public class Mutation : global::ZeroQL.Internal.IMutation
return __AddLimit is null ? throw new NullReferenceException("AddLimit is null but it should not be null. Schema can be outdated.") : selector(__AddLimit);
}

[JsonPropertyName("addLimitNullable")]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public LimitZeroQL __AddLimitNullable { get; set; }

[ZeroQL.GraphQLName("addLimitNullable")]
public T? AddLimitNullable<T>([ZeroQL.GraphQLType("LimitInput")] LimitInputZeroQL? limit = default !, Func<LimitZeroQL, T> selector = default !)
{
return __AddLimitNullable is null ? default : selector(__AddLimitNullable);
}

[JsonPropertyName("addLimit2")]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public Limit2ZeroQL __AddLimit2 { get; set; }
Expand Down
1 change: 1 addition & 0 deletions src/TestApp/ZeroQL.TestApp/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ type Mutation {
addUsersInfoWithEmails(input: AddUsersInput!): Int!
addUserKindPascal(userKindPascal: UserKindPascal!): Int!
addLimit(limit: LimitInput!): Limit!
addLimitNullable(limit: LimitInput): Limit
addLimit2(limit: Limit2Input!): Limit2!
addLimit2Nullable(limit: Limit2Input): Limit2
addLimit3(limit: Limit3Input): Limit3
Expand Down
11 changes: 11 additions & 0 deletions src/ZeroQL.SourceGenerators/Extensions/LinqExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Collections.Generic;

// ReSharper disable once CheckNamespace
namespace System.Linq;

public static class LinqExtensions

{
public static TValue? GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key)
=> dictionary.TryGetValue(key, out var value) ? value : default;
}
38 changes: 22 additions & 16 deletions src/ZeroQL.SourceGenerators/Resolver/GraphQLQueryResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ public static Result<GraphQLQueryResolverResult> Resolve(SemanticModel semanticM

var inputs = GetQueryInputs(lambda);
var variables = GetVariablesFromLambda(semanticModel, lambda, cancellationToken);
var availableCSharpVariables = inputs.VariablesName is null
var predefinedVariables = inputs.VariablesName is null
? new Dictionary<string, GraphQLQueryVariable>()
: variables.ToDictionary(o => $"{inputs.VariablesName}.{o.Name}");

var context = new GraphQLResolveContext(
inputs.QueryName,
lambda,
availableCSharpVariables,
predefinedVariables,
new Dictionary<string, GraphQLQueryVariable>(),
semanticModel,
cancellationToken);

Expand All @@ -48,10 +49,10 @@ public static Result<GraphQLQueryResolverResult> Resolve(SemanticModel semanticM
}

var stringBuilder = new StringBuilder();
if (context.AvailableVariables.Any())
if (context.Variables.Any())
{
var variablesBody = context.AvailableVariables
.Select(o => $"{o.Value.GraphQLValue}: {o.Value.GraphQLType}")
var variablesBody = context.Variables
.Select(o => $"{o.GraphQLValue}: {o.GraphQLType}")
.Join()
.Wrap("(", ") ");

Expand All @@ -65,7 +66,7 @@ public static Result<GraphQLQueryResolverResult> Resolve(SemanticModel semanticM
return new GraphQLQueryResolverResult
{
Query = stringBuilder.ToString(),
Variables = availableCSharpVariables
Variables = context.Variables.ToDictionary(o => o.Name)
};
}

Expand All @@ -82,6 +83,7 @@ public static Result<GraphQLQueryResolverResult> Resolve(SemanticModel semanticM
inputs.QueryName,
method,
availableVariables,
new Dictionary<string, GraphQLQueryVariable>(),
semanticModel,
cancellationToken);

Expand Down Expand Up @@ -139,6 +141,7 @@ public static Result<string> ResolveFragmentTemplate(
queryName,
methodDeclaration,
availableVariables,
new Dictionary<string, GraphQLQueryVariable>(),
semanticModel,
cancellationToken);

Expand Down Expand Up @@ -363,7 +366,7 @@ private static Result<string> HandleArgumentAsVariable(GraphQLResolveContext con
}

var value = argument.Expression.ToString();
if (context.AvailableVariables.TryGetValue(value, out var variable))
if (context.PredefinedVariables.TryGetValue(value, out var variable))
{
return variable.GraphQLValue;
}
Expand All @@ -373,7 +376,7 @@ private static Result<string> HandleArgumentAsVariable(GraphQLResolveContext con
{
return Failed(argument);
}

var parameter = GetParameterSymbol(methodSymbol, argument);
if (parameter is null)
{
Expand Down Expand Up @@ -429,17 +432,19 @@ private static Result<string> HandleArgumentAsVariable(GraphQLResolveContext con
case ILocalSymbol localSymbol:
{
var graphQLType = parameter.ToGraphQLType();
var graphQLVariable = GraphQLQueryVariable.Variable(localSymbol.Name, localSymbol.Type, graphQLType);
context.AvailableVariables.Add(graphQLVariable.Name, graphQLVariable);
var graphQLVariable =
GraphQLQueryVariable.Variable(localSymbol.Name, localSymbol.Type, graphQLType);
context.AddVariable(graphQLVariable);

return graphQLVariable.GraphQLValue;
}

case IParameterSymbol parameterSymbol:
{
var graphQLType = parameter.ToGraphQLType();
var graphQLVariable = GraphQLQueryVariable.Variable(parameterSymbol.Name, parameterSymbol.Type, graphQLType);
context.AvailableVariables.Add(graphQLVariable.Name, graphQLVariable);
var graphQLVariable =
GraphQLQueryVariable.Variable(parameterSymbol.Name, parameterSymbol.Type, graphQLType);
context.AddVariable(graphQLVariable);

return graphQLVariable.GraphQLValue;
}
Expand Down Expand Up @@ -468,10 +473,11 @@ private static Result<string> HandlerSimpleLambda(GraphQLResolveContext context,

return ResolveQuery(childContext.WithParent(simpleLambda), simpleLambda.Body);
}

private static IParameterSymbol? GetParameterSymbol(IMethodSymbol methodSymbol, ArgumentSyntax argumentSyntax)
{
var parameter = methodSymbol.Parameters.FirstOrDefault(o => o.Name == argumentSyntax.NameColon?.Name.Identifier.Text);
var parameter =
methodSymbol.Parameters.FirstOrDefault(o => o.Name == argumentSyntax.NameColon?.Name.Identifier.Text);
if (parameter is not null)
{
return parameter;
Expand All @@ -481,7 +487,7 @@ private static Result<string> HandlerSimpleLambda(GraphQLResolveContext context,
{
return null;
}

var argumentIndex = argumentList.Arguments.IndexOf(argumentSyntax);
if (argumentIndex < 0 || argumentIndex >= methodSymbol.Parameters.Length)
{
Expand Down Expand Up @@ -757,7 +763,7 @@ private static Result<string> HandleFragment(
context = context.WithVariableName(name) with
{
SemanticModel = newSemanticModel,
AvailableVariables = variables.ToDictionary(o => o.Key, o => GraphQLQueryVariable.Constant(o.Value.Value!))
PredefinedVariables = variables.ToDictionary(o => o.Key, o => GraphQLQueryVariable.Constant(o.Value.Value!))
};

return HandleMethod(context, invocation, methodDeclaration);
Expand Down
24 changes: 23 additions & 1 deletion src/ZeroQL.SourceGenerators/Resolver/GraphQLResolveContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand All @@ -8,7 +9,8 @@ namespace ZeroQL.SourceGenerators.Resolver;
public record struct GraphQLResolveContext(
string QueryVariableName,
CSharpSyntaxNode Parent,
Dictionary<string, GraphQLQueryVariable> AvailableVariables,
Dictionary<string, GraphQLQueryVariable> PredefinedVariables,
Dictionary<string, GraphQLQueryVariable> DiscoveredVariables,
SemanticModel SemanticModel,
CancellationToken CancellationToken)
{
Expand Down Expand Up @@ -70,6 +72,9 @@ public SemanticModel SemanticModel
}
}

public GraphQLQueryVariable[] Variables
=> PredefinedVariables.Values.Concat(DiscoveredVariables.Values).ToArray();

public GraphQLResolveContext WithParent(CSharpSyntaxNode parent)
{
return this with { Parent = parent };
Expand All @@ -79,4 +84,21 @@ public GraphQLResolveContext WithVariableName(string name)
{
return this with { QueryVariableName = name };
}

public void AddVariable(GraphQLQueryVariable variable)
{
var existingVariable = DiscoveredVariables.GetValueOrDefault(variable.Name);
if (existingVariable is not null)
{
if (existingVariable.GraphQLType != variable.GraphQLType &&
variable.GraphQLType!.EndsWith("!"))
{
DiscoveredVariables[variable.Name] = variable;
}
}
else
{
DiscoveredVariables.Add(variable.Name, variable);
}
}
}
19 changes: 11 additions & 8 deletions src/ZeroQL.SourceGenerators/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,19 @@ public static string ToGraphQLType(this ISymbol symbol, bool verifyNullability =
var typeSymbolName = ExtractTypeFromAttribute(symbol);
if (typeSymbolName is not null)
{
var nullable = verifyNullability ? ((ITypeSymbol)symbol).Nullable() : string.Empty;
var nullable = verifyNullability ? ((ITypeSymbol)symbol).GraphQLNullable() : string.Empty;
return $"{typeSymbolName}{nullable}";
}

return ToGraphQLTypeInternal(symbol);

static string ToGraphQLTypeInternal(ISymbol localSymbol) =>
localSymbol switch
{
IArrayTypeSymbol arrayTypeSymbol =>
$"[{ToGraphQLTypeInternal(arrayTypeSymbol.ElementType)}]{arrayTypeSymbol.Nullable()}",
$"[{ToGraphQLTypeInternal(arrayTypeSymbol.ElementType)}]{arrayTypeSymbol.GraphQLNullable()}",
INamedTypeSymbol { Name: "Nullable" } namedType => ToGraphQLTypeInternal(namedType.TypeArguments[0]),
ITypeSymbol typeSymbol => MapGraphQLType(localSymbol) + typeSymbol.Nullable(),
ITypeSymbol typeSymbol => MapGraphQLType(localSymbol) + typeSymbol.GraphQLNullable(),
_ => MapGraphQLType(localSymbol) + "!"
};
}
Expand All @@ -157,13 +157,16 @@ private static string MapGraphQLType(ISymbol typeSymbol)
return typeSymbol.Name;
}

public static string Nullable(this ITypeSymbol typeSymbol)
public static string GraphQLNullable(this ITypeSymbol typeSymbol)
=> typeSymbol.CanBeNull() ? "" : "!";

public static bool CanBeNull(this ITypeSymbol typeSymbol)
{
return typeSymbol.NullableAnnotation switch
{
NullableAnnotation.None => "!",
NullableAnnotation.NotAnnotated => "!",
NullableAnnotation.Annotated => "",
NullableAnnotation.None => false,
NullableAnnotation.NotAnnotated => false,
NullableAnnotation.Annotated => true,
_ => throw new ArgumentOutOfRangeException()
};
}
Expand Down
5 changes: 5 additions & 0 deletions src/ZeroQL.TestServer/Query/UserGraphQLMutations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ public Limit_1 AddLimit(Limit_1 limit)
return limit;
}

public Limit_1? AddLimitNullable(Limit_1? limit)
{
return limit;
}

public Limit_2 AddLimit2(Limit_2 limit)
{
return limit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,16 @@ namespace GraphQLClient
return __AddLimit is null ? throw new NullReferenceException("AddLimit is null but it should not be null. Schema can be outdated.") : selector(__AddLimit);
}

[JsonPropertyName("addLimitNullable")]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public LimitZeroQL __AddLimitNullable { get; set; }

[ZeroQL.GraphQLName("addLimitNullable")]
public T? AddLimitNullable<T>([ZeroQL.GraphQLType("LimitInput")] LimitInputZeroQL? limit = default !, Func<LimitZeroQL, T> selector = default !)
{
return __AddLimitNullable is null ? default : selector(__AddLimitNullable);
}

[JsonPropertyName("addLimit2")]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public Limit2ZeroQL __AddLimit2 { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
int AddUsersInfoWithEmails([ZeroQL.GraphQLType("AddUsersInput!")] AddUsersInput input = default !),
int AddUserKindPascal([ZeroQL.GraphQLType("UserKindPascal!")] UserKindPascal userKindPascal = default !),
T AddLimit<T>([ZeroQL.GraphQLType("LimitInput!")] LimitInputZeroQL limit = default !, Func<LimitZeroQL, T> selector = default !),
T? AddLimitNullable<T>([ZeroQL.GraphQLType("LimitInput")] LimitInputZeroQL? limit = default !, Func<LimitZeroQL, T> selector = default !),
T AddLimit2<T>([ZeroQL.GraphQLType("Limit2Input!")] Limit2Input limit = default !, Func<Limit2ZeroQL, T> selector = default !),
T? AddLimit2Nullable<T>([ZeroQL.GraphQLType("Limit2Input")] Limit2Input? limit = default !, Func<Limit2ZeroQL, T> selector = default !),
T? AddLimit3<T>([ZeroQL.GraphQLType("Limit3Input")] Limit3InputZeroQL? limit = default !, Func<Limit3, T> selector = default !),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,16 @@ namespace GraphQLClient
return __AddLimit is null ? throw new NullReferenceException("AddLimit is null but it should not be null. Schema can be outdated.") : selector(__AddLimit);
}

[JsonPropertyName("addLimitNullable")]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public LimitZeroQL __AddLimitNullable { get; set; }

[ZeroQL.GraphQLName("addLimitNullable")]
public T? AddLimitNullable<T>([ZeroQL.GraphQLType("LimitInput")] LimitInputZeroQL? limit = default !, Func<LimitZeroQL, T> selector = default !)
{
return __AddLimitNullable is null ? default : selector(__AddLimitNullable);
}

[JsonPropertyName("addLimit2")]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public Limit2ZeroQL __AddLimit2 { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type Mutation {
addUsersInfoWithEmails(input: AddUsersInput!): Int!
addUserKindPascal(userKindPascal: UserKindPascal!): Int!
addLimit(limit: LimitInput!): Limit!
addLimitNullable(limit: LimitInput): Limit
addLimit2(limit: Limit2Input!): Limit2!
addLimit2Nullable(limit: Limit2Input): Limit2
addLimit3(limit: Limit3Input): Limit3
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
Query: mutation ($users: [UserInfoInput!]!) { addUsersInfo(users: $users)},
Data: 84
}
5 changes: 3 additions & 2 deletions src/ZeroQL.Tests/SourceGeneration/FileUploadTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,9 @@ public async Task UploadFileAsDeepNestedAnonymousTypeWithClosureSyntax()
(TestProject.PlaceToReplace, usersVariable),
(TestProject.FullMeQuery, csharpQuery));

var result = (GraphQLResult<int>)await project.Execute();
result.Data.Should().Be(84);
var result = await project.Execute();

await Verify(result);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
response: {
Query: mutation ($limit: LimitInput!) { addLimitNullable(limit: $limit) { limit } addLimit(limit: $limit) { limit } },
Data: {}
},
response2: {
Query: mutation ($limit: LimitInput!) { addLimit(limit: $limit) { limit } addLimitNullable(limit: $limit) { limit } },
Data: {}
}
}
Loading

0 comments on commit 21377ad

Please sign in to comment.