Skip to content

Commit

Permalink
Merge pull request #34 from Linq2GraphQL/add-support-for-nullable
Browse files Browse the repository at this point in the history
Add support for nullable
  • Loading branch information
joadan authored Sep 4, 2024
2 parents 11d776d + 601567f commit 5b9c97f
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 72 deletions.
117 changes: 64 additions & 53 deletions docs/Linq2GraphQL.Docs/Components/GenerateClient.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,67 @@

<Dimmer Active=isLoading>

<ItemSelect Items="demoOptions" @bind-SelectedValue="options" SelectedTextExpression="e=>e.ClientName">
<ListTemplate>
@context.ClientName
</ListTemplate>
</ItemSelect>

<Card class="mt-3">
<CardBody>
<DataGrid>
<DataGridItem Title="Name">
<InputText class="form-control" @bind-Value="options.ClientName" />
</DataGridItem>
<DataGridItem Title="Namespace">
<InputText class="form-control" @bind-Value="options.Namespace" />
</DataGridItem>
<DataGridItem Title="Include subscriptions">
<Checkbox Switch @bind-Value="options.IncludeSubscriptions" />
</DataGridItem>
</DataGrid>

<div class="mt-3" />
<Tabs>
<Tab Title="Url">
<DataGrid>
<DataGridItem Title="Url">
<InputText class="form-control" @bind-Value="options.Url" />
</DataGridItem>
<DataGridItem Title="Token">
<InputText class="form-control" @bind-Value="options.Token" />
</DataGridItem>
</DataGrid>


<Button class="mt-3" BackgroundColor="TablerColor.Primary" OnClick="GenerateClientAsync">Generate</Button>

</Tab>

<Tab Title="Schema">

<div class="mb-2">Run this <Icon class="icon" IconType="Icons.Copy" OnClick="CopyIntrospection" /> query and paste the result below.</div>

<InputTextArea class="form-control" @bind-Value="options.Schema" rows="20" />

<Button class="mt-3" BackgroundColor="TablerColor.Primary" OnClick="GenerateClientJson">Generate</Button>
</Tab>

</Tabs>


</CardBody>
</Card>

</Dimmer>
<ItemSelect Items="demoOptions" @bind-SelectedValue="options" SelectedTextExpression="e=>e.ClientName">
<ListTemplate>
@context.ClientName
</ListTemplate>
</ItemSelect>

<Card class="mt-3">
<CardBody>
<DataGrid>
<DataGridItem Title="Name">
<InputText class="form-control" @bind-Value="options.ClientName" />
</DataGridItem>
<DataGridItem Title="Namespace">
<InputText class="form-control" @bind-Value="options.Namespace" />
</DataGridItem>

<DataGridItem Title="Enum Strategy">
<ItemSelect Items="EnumHelper.GetList<EnumGeneratorStrategy>()" @bind-SelectedValue="options.EnumGeneratorStrategy" />
</DataGridItem>

<DataGridItem Title="Include subscriptions">
<Checkbox Switch @bind-Value="options.IncludeSubscriptions" />
</DataGridItem>

<DataGridItem Title="Nullable client">
<Checkbox Switch @bind-Value="options.Nullable" />
</DataGridItem>


</DataGrid>

<div class="mt-3" />
<Tabs>
<Tab Title="Url">
<DataGrid>
<DataGridItem Title="Url">
<InputText class="form-control" @bind-Value="options.Url" />
</DataGridItem>
<DataGridItem Title="Token">
<InputText class="form-control" @bind-Value="options.Token" />
</DataGridItem>
</DataGrid>


<Button class="mt-3" BackgroundColor="TablerColor.Primary" OnClick="GenerateClientAsync">Generate</Button>

</Tab>

<Tab Title="Schema">

<div class="mb-2">Run this <Icon class="icon" IconType="Icons.Copy" OnClick="CopyIntrospection" /> query and paste the result below.</div>

<InputTextArea class="form-control" @bind-Value="options.Schema" rows="20" />

<Button class="mt-3" BackgroundColor="TablerColor.Primary" OnClick="GenerateClientJson">Generate</Button>
</Tab>

</Tabs>


</CardBody>
</Card>

</Dimmer>
8 changes: 5 additions & 3 deletions docs/Linq2GraphQL.Docs/Components/GenerateClient.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ private async Task GenerateClientJson()
try
{
isLoading = true;
var generator = new Generator.ClientGenerator(options.Namespace, options.ClientName, options.IncludeSubscriptions, EnumGeneratorStrategy.FailIfMissing);
var generator = new Generator.ClientGenerator(options.Namespace, options.ClientName, options.IncludeSubscriptions, EnumGeneratorStrategy.FailIfMissing, options.Nullable);
var entries = generator.Generate(options.Schema);
await SaveEntriesAsync(entries);
}
Expand All @@ -107,7 +107,7 @@ private async Task GenerateClientAsync()
try
{
isLoading = true;
var generator = new ClientGenerator(options.Namespace, options.ClientName, options.IncludeSubscriptions, EnumGeneratorStrategy.FailIfMissing);
var generator = new ClientGenerator(options.Namespace, options.ClientName, options.IncludeSubscriptions, options.EnumGeneratorStrategy, options.Nullable);
var entries = await generator.GenerateAsync(new Uri(options.Url), options.Token);
await SaveEntriesAsync(entries);
}
Expand All @@ -128,10 +128,12 @@ public class GenerateOptions
public string Namespace { get; set; }
public string ClientName { get; set; }
public bool IncludeSubscriptions { get; set; }

public bool Nullable { get; set; }
public string Url { get; set; }
public string Token { get; set; }

public EnumGeneratorStrategy EnumGeneratorStrategy { get; set; }

public string Schema { get; set; }
}
}
7 changes: 6 additions & 1 deletion src/Linq2GraphQL.Generator/ClientGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ public class ClientGenerator
private readonly string clientName;
private readonly bool includeSubscriptions;
private readonly EnumGeneratorStrategy enumGeneratorStrategy;
private readonly bool nullable;
private readonly List<FileEntry> entries = new();

public ClientGenerator(string namespaceName, string clientName, bool includeSubscriptions,
EnumGeneratorStrategy enumGeneratorStrategy)
EnumGeneratorStrategy enumGeneratorStrategy, bool nullable)
{
this.namespaceName = namespaceName;
this.clientName = clientName;
this.includeSubscriptions = includeSubscriptions;
this.enumGeneratorStrategy = enumGeneratorStrategy;
this.nullable = nullable;
}

private void AddFile(string directory, string fileName, string content)
Expand Down Expand Up @@ -58,6 +60,9 @@ public async Task<List<FileEntry>> GenerateAsync(Uri uri, string authToken = nul
public List<FileEntry> Generate(string schemaJson)
{
entries.Clear();

GeneratorSettings.Current = new GeneratorSettings { Nullable = this.nullable };

var rootSchema = JsonSerializer.Deserialize<RootSchema>(schemaJson,
new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });

Expand Down
17 changes: 17 additions & 0 deletions src/Linq2GraphQL.Generator/GeneratorSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Linq2GraphQL.Generator
{
public class GeneratorSettings
{
public static GeneratorSettings Current { get; set; }

public bool Nullable { get; set; }
}


}
16 changes: 13 additions & 3 deletions src/Linq2GraphQL.Generator/GraphQLSchema/RootSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,15 +261,25 @@ public class TypeInfo
public bool IsNoneNull { get; set; }
public bool IsList { get; set; }

private bool csharpNullQuestion =>
!IsNoneNull && (Kind == TypeKind.Enum || (CSharpType != null && CSharpTypeName != "string"));

private bool CSharpNullQuestion()
{
if (GeneratorSettings.Current.Nullable)
{
return !IsNoneNull;
}
else
{
return !IsNoneNull && (Kind == TypeKind.Enum || (CSharpType != null && CSharpTypeName != "string"));
}

}

public string CSharpTypeNameFull
{
get
{
var result = CSharpTypeName + (csharpNullQuestion ? "?" : "");
var result = CSharpTypeName + (CSharpNullQuestion() ? "?" : "");

if (IsList)
{
Expand Down
12 changes: 8 additions & 4 deletions src/Linq2GraphQL.Generator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ private static async Task Main(string[] args)
var includeSubscriptions = new Option<bool>(new[] { "--subscriptions", "-s" }, "Include subscriptions");
var enumStrategy = new Option<string>(new[] { "--enum-strategy", "-es" }, "Enum strategy");

var nullable = new Option<bool>(new[] { "--nullable", "-nu" }, "Nullable client");

var rootCommand = new RootCommand("Generate GraphQL client")
{
uriArgument,
Expand All @@ -29,7 +31,8 @@ private static async Task Main(string[] args)
clientName,
authToken,
includeSubscriptions,
enumStrategy
enumStrategy,
nullable
};

rootCommand.SetHandler(async context =>
Expand All @@ -42,9 +45,10 @@ private static async Task Main(string[] args)
var authTokenValue = result.GetValueForOption(authToken);
var includeSubscriptionsValue = result.GetValueForOption(includeSubscriptions);
var enumStrategyValue = result.GetValueForOption(enumStrategy);
var nullableValue = result.GetValueForOption(nullable);
await GenerateClientAsync(uriValue, outputFolderValue, namespaceValue, clientNameValue,
includeSubscriptionsValue, authTokenValue, enumStrategyValue);
includeSubscriptionsValue, authTokenValue, enumStrategyValue, nullableValue);
}
);

Expand All @@ -54,13 +58,13 @@ await GenerateClientAsync(uriValue, outputFolderValue, namespaceValue, clientNam
}

private static async Task GenerateClientAsync(Uri uri, string outputFolder, string namespaceName, string name,
bool includeSubscriptions, string authToken, string enumStrategy)
bool includeSubscriptions, string authToken, string enumStrategy, bool nullable)
{
var enumStrat = enumStrategy != null && enumStrategy.Equals("AddUnknownOption", StringComparison.InvariantCultureIgnoreCase)
? EnumGeneratorStrategy.AddUnknownOption
: EnumGeneratorStrategy.FailIfMissing;

var generator = new ClientGenerator(namespaceName, name, includeSubscriptions, enumStrat);
var generator = new ClientGenerator(namespaceName, name, includeSubscriptions, enumStrat, nullable);
var entries = await generator.GenerateAsync(uri, authToken);

var outputPath = Path.GetFullPath(outputFolder, Environment.CurrentDirectory);
Expand Down
2 changes: 1 addition & 1 deletion src/Linq2GraphQL.Generator/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"profiles": {
"Linq2GraphQL.Generator": {
"commandName": "Project",
"commandLineArgs": "https://localhost:7184/graphql/ -c=\"SampleClient\" -n=\"Linq2GraphQL.TestClient\" -o=\"C:\\Code\\Linq2GraphQL\\test\\Linq2GraphQL.TestClient\\Generated\" -s=true -es=\"AddUnknownOption\""
"commandLineArgs": "https://localhost:50741/graphql/ -c=\"SampleNullableClient\" -n=\"Linq2GraphQL.TestClientNullable\" -o=\"C:\\temp\\Linq2GraphQL\\Linq2GraphQL.TestClientNullable\\Generated\" -s=true -nu=true"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ public GraphQuery<List<Customer>> CustomerList()
return new GraphQuery<List<Customer>>(client, "customerList", OperationType.Query, arguments);
}

public GraphQuery<Customer> CustomerNullable()
public GraphQuery<Customer?> CustomerNullable()
{
var arguments = new List<ArgumentValue>
{
};

return new GraphQuery<Customer>(client, "customerNullable", OperationType.Query, arguments);
return new GraphQuery<Customer?>(client, "customerNullable", OperationType.Query, arguments);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Linq2GraphQL.Client;

namespace Linq2GraphQL.TestClientNullable;

//public static class IF
//{
//}


Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ public partial class Customer : GraphQLTypeBase
public List<Order> Orders { get; set; }

Check warning on line 21 in test/Linq2GraphQL.TestClientNullable/Generated/Types/Customer.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Orders' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

[JsonPropertyName("address")]
public Address Address { get; set; }
public Address? Address { get; set; }

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,15 @@ public partial class Order : GraphQLTypeBase
public Customer Customer { get; set; }

Check warning on line 45 in test/Linq2GraphQL.TestClientNullable/Generated/Types/Order.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Customer' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

[JsonPropertyName("address")]
public Address Address { get; set; }
public Address? Address { get; set; }

[JsonPropertyName("orderDate")]
public DateTimeOffset OrderDate { get; set; }

[JsonPropertyName("lines")]
public List<OrderLine> Lines { get; set; }

Check warning on line 54 in test/Linq2GraphQL.TestClientNullable/Generated/Types/Order.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Lines' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

[JsonPropertyName("entryTime")]
public TimeSpan? EntryTime { get; set; }

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ public partial class OrderLine : GraphQLTypeBase
public Order Order { get; set; }

Check warning on line 15 in test/Linq2GraphQL.TestClientNullable/Generated/Types/OrderLine.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Order' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

[JsonPropertyName("item")]
public Item Item { get; set; }
public Item? Item { get; set; }

[JsonPropertyName("price")]
public decimal Price { get; set; }

[JsonPropertyName("quantity")]
public float Quantity { get; set; }
public double Quantity { get; set; }

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
Expand Down

0 comments on commit 5b9c97f

Please sign in to comment.