Skip to content

Commit 5b9c97f

Browse files
authored
Merge pull request #34 from Linq2GraphQL/add-support-for-nullable
Add support for nullable
2 parents 11d776d + 601567f commit 5b9c97f

13 files changed

Lines changed: 136 additions & 72 deletions

File tree

docs/Linq2GraphQL.Docs/Components/GenerateClient.razor

Lines changed: 64 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,56 +4,67 @@
44

55
<Dimmer Active=isLoading>
66

7-
<ItemSelect Items="demoOptions" @bind-SelectedValue="options" SelectedTextExpression="e=>e.ClientName">
8-
<ListTemplate>
9-
@context.ClientName
10-
</ListTemplate>
11-
</ItemSelect>
12-
13-
<Card class="mt-3">
14-
<CardBody>
15-
<DataGrid>
16-
<DataGridItem Title="Name">
17-
<InputText class="form-control" @bind-Value="options.ClientName" />
18-
</DataGridItem>
19-
<DataGridItem Title="Namespace">
20-
<InputText class="form-control" @bind-Value="options.Namespace" />
21-
</DataGridItem>
22-
<DataGridItem Title="Include subscriptions">
23-
<Checkbox Switch @bind-Value="options.IncludeSubscriptions" />
24-
</DataGridItem>
25-
</DataGrid>
26-
27-
<div class="mt-3" />
28-
<Tabs>
29-
<Tab Title="Url">
30-
<DataGrid>
31-
<DataGridItem Title="Url">
32-
<InputText class="form-control" @bind-Value="options.Url" />
33-
</DataGridItem>
34-
<DataGridItem Title="Token">
35-
<InputText class="form-control" @bind-Value="options.Token" />
36-
</DataGridItem>
37-
</DataGrid>
38-
39-
40-
<Button class="mt-3" BackgroundColor="TablerColor.Primary" OnClick="GenerateClientAsync">Generate</Button>
41-
42-
</Tab>
43-
44-
<Tab Title="Schema">
45-
46-
<div class="mb-2">Run this <Icon class="icon" IconType="Icons.Copy" OnClick="CopyIntrospection" /> query and paste the result below.</div>
47-
48-
<InputTextArea class="form-control" @bind-Value="options.Schema" rows="20" />
49-
50-
<Button class="mt-3" BackgroundColor="TablerColor.Primary" OnClick="GenerateClientJson">Generate</Button>
51-
</Tab>
52-
53-
</Tabs>
54-
55-
56-
</CardBody>
57-
</Card>
58-
59-
</Dimmer>
7+
<ItemSelect Items="demoOptions" @bind-SelectedValue="options" SelectedTextExpression="e=>e.ClientName">
8+
<ListTemplate>
9+
@context.ClientName
10+
</ListTemplate>
11+
</ItemSelect>
12+
13+
<Card class="mt-3">
14+
<CardBody>
15+
<DataGrid>
16+
<DataGridItem Title="Name">
17+
<InputText class="form-control" @bind-Value="options.ClientName" />
18+
</DataGridItem>
19+
<DataGridItem Title="Namespace">
20+
<InputText class="form-control" @bind-Value="options.Namespace" />
21+
</DataGridItem>
22+
23+
<DataGridItem Title="Enum Strategy">
24+
<ItemSelect Items="EnumHelper.GetList<EnumGeneratorStrategy>()" @bind-SelectedValue="options.EnumGeneratorStrategy" />
25+
</DataGridItem>
26+
27+
<DataGridItem Title="Include subscriptions">
28+
<Checkbox Switch @bind-Value="options.IncludeSubscriptions" />
29+
</DataGridItem>
30+
31+
<DataGridItem Title="Nullable client">
32+
<Checkbox Switch @bind-Value="options.Nullable" />
33+
</DataGridItem>
34+
35+
36+
</DataGrid>
37+
38+
<div class="mt-3" />
39+
<Tabs>
40+
<Tab Title="Url">
41+
<DataGrid>
42+
<DataGridItem Title="Url">
43+
<InputText class="form-control" @bind-Value="options.Url" />
44+
</DataGridItem>
45+
<DataGridItem Title="Token">
46+
<InputText class="form-control" @bind-Value="options.Token" />
47+
</DataGridItem>
48+
</DataGrid>
49+
50+
51+
<Button class="mt-3" BackgroundColor="TablerColor.Primary" OnClick="GenerateClientAsync">Generate</Button>
52+
53+
</Tab>
54+
55+
<Tab Title="Schema">
56+
57+
<div class="mb-2">Run this <Icon class="icon" IconType="Icons.Copy" OnClick="CopyIntrospection" /> query and paste the result below.</div>
58+
59+
<InputTextArea class="form-control" @bind-Value="options.Schema" rows="20" />
60+
61+
<Button class="mt-3" BackgroundColor="TablerColor.Primary" OnClick="GenerateClientJson">Generate</Button>
62+
</Tab>
63+
64+
</Tabs>
65+
66+
67+
</CardBody>
68+
</Card>
69+
70+
</Dimmer>

docs/Linq2GraphQL.Docs/Components/GenerateClient.razor.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ private async Task GenerateClientJson()
8686
try
8787
{
8888
isLoading = true;
89-
var generator = new Generator.ClientGenerator(options.Namespace, options.ClientName, options.IncludeSubscriptions, EnumGeneratorStrategy.FailIfMissing);
89+
var generator = new Generator.ClientGenerator(options.Namespace, options.ClientName, options.IncludeSubscriptions, EnumGeneratorStrategy.FailIfMissing, options.Nullable);
9090
var entries = generator.Generate(options.Schema);
9191
await SaveEntriesAsync(entries);
9292
}
@@ -107,7 +107,7 @@ private async Task GenerateClientAsync()
107107
try
108108
{
109109
isLoading = true;
110-
var generator = new ClientGenerator(options.Namespace, options.ClientName, options.IncludeSubscriptions, EnumGeneratorStrategy.FailIfMissing);
110+
var generator = new ClientGenerator(options.Namespace, options.ClientName, options.IncludeSubscriptions, options.EnumGeneratorStrategy, options.Nullable);
111111
var entries = await generator.GenerateAsync(new Uri(options.Url), options.Token);
112112
await SaveEntriesAsync(entries);
113113
}
@@ -128,10 +128,12 @@ public class GenerateOptions
128128
public string Namespace { get; set; }
129129
public string ClientName { get; set; }
130130
public bool IncludeSubscriptions { get; set; }
131-
131+
public bool Nullable { get; set; }
132132
public string Url { get; set; }
133133
public string Token { get; set; }
134134

135+
public EnumGeneratorStrategy EnumGeneratorStrategy { get; set; }
136+
135137
public string Schema { get; set; }
136138
}
137139
}

src/Linq2GraphQL.Generator/ClientGenerator.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@ public class ClientGenerator
1515
private readonly string clientName;
1616
private readonly bool includeSubscriptions;
1717
private readonly EnumGeneratorStrategy enumGeneratorStrategy;
18+
private readonly bool nullable;
1819
private readonly List<FileEntry> entries = new();
1920

2021
public ClientGenerator(string namespaceName, string clientName, bool includeSubscriptions,
21-
EnumGeneratorStrategy enumGeneratorStrategy)
22+
EnumGeneratorStrategy enumGeneratorStrategy, bool nullable)
2223
{
2324
this.namespaceName = namespaceName;
2425
this.clientName = clientName;
2526
this.includeSubscriptions = includeSubscriptions;
2627
this.enumGeneratorStrategy = enumGeneratorStrategy;
28+
this.nullable = nullable;
2729
}
2830

2931
private void AddFile(string directory, string fileName, string content)
@@ -58,6 +60,9 @@ public async Task<List<FileEntry>> GenerateAsync(Uri uri, string authToken = nul
5860
public List<FileEntry> Generate(string schemaJson)
5961
{
6062
entries.Clear();
63+
64+
GeneratorSettings.Current = new GeneratorSettings { Nullable = this.nullable };
65+
6166
var rootSchema = JsonSerializer.Deserialize<RootSchema>(schemaJson,
6267
new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
6368

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Linq2GraphQL.Generator
8+
{
9+
public class GeneratorSettings
10+
{
11+
public static GeneratorSettings Current { get; set; }
12+
13+
public bool Nullable { get; set; }
14+
}
15+
16+
17+
}

src/Linq2GraphQL.Generator/GraphQLSchema/RootSchema.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,15 +261,25 @@ public class TypeInfo
261261
public bool IsNoneNull { get; set; }
262262
public bool IsList { get; set; }
263263

264-
private bool csharpNullQuestion =>
265-
!IsNoneNull && (Kind == TypeKind.Enum || (CSharpType != null && CSharpTypeName != "string"));
264+
265+
private bool CSharpNullQuestion()
266+
{
267+
if (GeneratorSettings.Current.Nullable)
268+
{
269+
return !IsNoneNull;
270+
}
271+
else
272+
{
273+
return !IsNoneNull && (Kind == TypeKind.Enum || (CSharpType != null && CSharpTypeName != "string"));
274+
}
266275

276+
}
267277

268278
public string CSharpTypeNameFull
269279
{
270280
get
271281
{
272-
var result = CSharpTypeName + (csharpNullQuestion ? "?" : "");
282+
var result = CSharpTypeName + (CSharpNullQuestion() ? "?" : "");
273283

274284
if (IsList)
275285
{

src/Linq2GraphQL.Generator/Program.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ private static async Task Main(string[] args)
2121
var includeSubscriptions = new Option<bool>(new[] { "--subscriptions", "-s" }, "Include subscriptions");
2222
var enumStrategy = new Option<string>(new[] { "--enum-strategy", "-es" }, "Enum strategy");
2323

24+
var nullable = new Option<bool>(new[] { "--nullable", "-nu" }, "Nullable client");
25+
2426
var rootCommand = new RootCommand("Generate GraphQL client")
2527
{
2628
uriArgument,
@@ -29,7 +31,8 @@ private static async Task Main(string[] args)
2931
clientName,
3032
authToken,
3133
includeSubscriptions,
32-
enumStrategy
34+
enumStrategy,
35+
nullable
3336
};
3437

3538
rootCommand.SetHandler(async context =>
@@ -42,9 +45,10 @@ private static async Task Main(string[] args)
4245
var authTokenValue = result.GetValueForOption(authToken);
4346
var includeSubscriptionsValue = result.GetValueForOption(includeSubscriptions);
4447
var enumStrategyValue = result.GetValueForOption(enumStrategy);
48+
var nullableValue = result.GetValueForOption(nullable);
4549

4650
await GenerateClientAsync(uriValue, outputFolderValue, namespaceValue, clientNameValue,
47-
includeSubscriptionsValue, authTokenValue, enumStrategyValue);
51+
includeSubscriptionsValue, authTokenValue, enumStrategyValue, nullableValue);
4852
}
4953
);
5054

@@ -54,13 +58,13 @@ await GenerateClientAsync(uriValue, outputFolderValue, namespaceValue, clientNam
5458
}
5559

5660
private static async Task GenerateClientAsync(Uri uri, string outputFolder, string namespaceName, string name,
57-
bool includeSubscriptions, string authToken, string enumStrategy)
61+
bool includeSubscriptions, string authToken, string enumStrategy, bool nullable)
5862
{
5963
var enumStrat = enumStrategy != null && enumStrategy.Equals("AddUnknownOption", StringComparison.InvariantCultureIgnoreCase)
6064
? EnumGeneratorStrategy.AddUnknownOption
6165
: EnumGeneratorStrategy.FailIfMissing;
6266

63-
var generator = new ClientGenerator(namespaceName, name, includeSubscriptions, enumStrat);
67+
var generator = new ClientGenerator(namespaceName, name, includeSubscriptions, enumStrat, nullable);
6468
var entries = await generator.GenerateAsync(uri, authToken);
6569

6670
var outputPath = Path.GetFullPath(outputFolder, Environment.CurrentDirectory);

src/Linq2GraphQL.Generator/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"profiles": {
33
"Linq2GraphQL.Generator": {
44
"commandName": "Project",
5-
"commandLineArgs": "https://localhost:7184/graphql/ -c=\"SampleClient\" -n=\"Linq2GraphQL.TestClient\" -o=\"C:\\Code\\Linq2GraphQL\\test\\Linq2GraphQL.TestClient\\Generated\" -s=true -es=\"AddUnknownOption\""
5+
"commandLineArgs": "https://localhost:50741/graphql/ -c=\"SampleNullableClient\" -n=\"Linq2GraphQL.TestClientNullable\" -o=\"C:\\temp\\Linq2GraphQL\\Linq2GraphQL.TestClientNullable\\Generated\" -s=true -nu=true"
66
}
77
}
88
}

test/Linq2GraphQL.TestClientNullable/Generated/Client/QueryMethods.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ public GraphQuery<List<Customer>> CustomerList()
2222
return new GraphQuery<List<Customer>>(client, "customerList", OperationType.Query, arguments);
2323
}
2424

25-
public GraphQuery<Customer> CustomerNullable()
25+
public GraphQuery<Customer?> CustomerNullable()
2626
{
2727
var arguments = new List<ArgumentValue>
2828
{
2929
};
3030

31-
return new GraphQuery<Customer>(client, "customerNullable", OperationType.Query, arguments);
31+
return new GraphQuery<Customer?>(client, "customerNullable", OperationType.Query, arguments);
3232
}
3333

3434
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text.Json.Serialization;
4+
using Linq2GraphQL.Client;
5+
6+
namespace Linq2GraphQL.TestClientNullable;
7+
8+
//public static class IF
9+
//{
10+
//}
11+
12+

test/Linq2GraphQL.TestClientNullable/Generated/Types/Customer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ public partial class Customer : GraphQLTypeBase
2121
public List<Order> Orders { get; set; }
2222

2323
[JsonPropertyName("address")]
24-
public Address Address { get; set; }
24+
public Address? Address { get; set; }
2525

2626
}

0 commit comments

Comments
 (0)