Skip to content

Commit b2c74a6

Browse files
committed
Refactor interface generation and enhance null safety in ClientGenerator and Schema classes.
Added XML documentation comments for clarity in InterfaceTemplate and MethodsTemplate.
1 parent 6a3e327 commit b2c74a6

File tree

5 files changed

+124
-93
lines changed

5 files changed

+124
-93
lines changed

src/Linq2GraphQL.Generator/ClientGenerator.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,16 +104,21 @@ public List<FileEntry> Generate(string schemaJson)
104104

105105
Console.WriteLine("Generate Interfaces");
106106

107-
var classInterfacesList = schema.GetClassTypes().Where(e => e.HasInterfaces)
108-
.SelectMany(i => i.Interfaces.ToDictionary(e => i.Name, e => e.Name)).ToList();
109-
foreach (var interfaceType in schema.GetInterfaces())
107+
var classInterfacesList = schema.GetClassTypes()?.Where(e => e.HasInterfaces)
108+
?.SelectMany(i => i.Interfaces?.ToDictionary(e => i.Name, e => e.Name))?.ToList() ?? new List<KeyValuePair<string, string>>();
109+
110+
var interfaces = schema.GetInterfaces();
111+
if (interfaces != null)
110112
{
111-
var implementedBy = classInterfacesList.Where(e => e.Value == interfaceType.Name).Select(e => e.Key)
112-
.ToList();
113-
114-
var interfaceTemplte =
115-
new InterfaceTemplate(interfaceType, namespaceName, implementedBy).TransformText();
116-
AddFile("Interfaces", interfaceType.FileName, interfaceTemplte);
113+
foreach (var interfaceType in interfaces)
114+
{
115+
var implementedBy = classInterfacesList.Where(e => e.Value == interfaceType.Name).Select(e => e.Key)
116+
.ToList();
117+
118+
var interfaceTemplte =
119+
new InterfaceTemplate(interfaceType, namespaceName, implementedBy).TransformText();
120+
AddFile("Interfaces", interfaceType.FileName, interfaceTemplte);
121+
}
117122
}
118123

119124
Console.WriteLine("Generate Types...");

src/Linq2GraphQL.Generator/GraphQLSchema/Schema.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,17 @@ public class Schema
2121

2222
[JsonPropertyName("subscriptionType")] public GraphqlSchemaType SchemaSubscriptionType { get; set; }
2323

24-
[JsonIgnore] public GraphqlType QueryType => Types.FirstOrDefault(e => e.Name == SchemaQueryType?.Name);
24+
[JsonIgnore] public GraphqlType QueryType => Types?.FirstOrDefault(e => e.Name == SchemaQueryType?.Name);
2525

26-
[JsonIgnore] public GraphqlType MutationType => Types.FirstOrDefault(e => e.Name == SchemaMutationType?.Name);
26+
[JsonIgnore] public GraphqlType MutationType => Types?.FirstOrDefault(e => e.Name == SchemaMutationType?.Name);
2727

2828
[JsonIgnore]
29-
public GraphqlType SubscriptionType => Types.FirstOrDefault(e => e.Name == SchemaSubscriptionType?.Name);
29+
public GraphqlType SubscriptionType => Types?.FirstOrDefault(e => e.Name == SchemaSubscriptionType?.Name);
3030

3131
public List<GraphqlType> GetAllTypesExceptSystemTypes()
3232
{
33+
if (Types == null) return new List<GraphqlType>();
34+
3335
return Types.Where(e => e.Name != SchemaQueryType?.Name &&
3436
!e.Name.StartsWith("__") &&
3537
!BuiltInTypes.Contains(e.Name) &&
@@ -40,6 +42,8 @@ public List<GraphqlType> GetAllTypesExceptSystemTypes()
4042

4143
public void PopulateFieldTypes()
4244
{
45+
if (Types == null) return;
46+
4347
foreach (var typeGroup in Types.Where(e => e.AllFields != null && e.AllFields.Any())
4448
.SelectMany(e => e.AllFields).GroupBy(e => e.Type.GetBaseBaseType().Name))
4549
{
@@ -76,6 +80,6 @@ public List<GraphqlType> GetInterfaces()
7680
return GetAllTypesExceptSystemTypes().Where(e => e.Kind == TypeKind.Interface).ToList();
7781
}
7882

79-
public GraphqlType GetGraphqlType(string name) => Types.FirstOrDefault(e => e.Name == name);
83+
public GraphqlType GetGraphqlType(string name) => Types?.FirstOrDefault(e => e.Name == name);
8084

8185
}

src/Linq2GraphQL.Generator/Templates/Interface/InterfaceTemplate.tt

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ using Linq2GraphQL.Client.Converters;
99

1010
namespace <#= namespaceName #>;
1111

12-
public static class <#= classType.Name #>Extentions
12+
/// <summary>
13+
/// Extension methods for <#= classType.Name #> interface type casting
14+
/// </summary>
15+
public static class <#= classType.Name #>Extensions
1316
{
14-
1517
<# foreach (var field in implementedBy) { #>
16-
18+
/// <summary>
19+
/// Casts <#= classType.Name #> to <#= field #> if the runtime type matches
20+
/// </summary>
21+
/// <param name="value">The interface value to cast</param>
22+
/// <returns><#= field #> instance or null if type doesn't match</returns>
1723
[GraphInterface]
1824
public static <#= field #> <#= field #>(this <#= classType.Name #> value)
1925
{
@@ -23,56 +29,69 @@ public static class <#= classType.Name #>Extentions
2329
}
2430
return null;
2531
}
32+
2633
<# } #>
2734
}
2835

29-
36+
/// <summary>
37+
/// JSON converter for <#= classType.Name #> interface deserialization
38+
/// </summary>
3039
internal class <#= GetInterfaceConverterName() #> : InterfaceJsonConverter<<#= classType.Name #>>
3140
{
41+
/// <summary>
42+
/// Deserializes JSON to the appropriate concrete type based on __typename
43+
/// </summary>
44+
/// <param name="typeName">The GraphQL type name from __typename field</param>
45+
/// <param name="json">The JSON object to deserialize</param>
46+
/// <returns>Deserialized instance of the appropriate concrete type</returns>
3247
public override <#= classType.Name #> Deserialize(string typeName, JsonObject json) => typeName switch
3348
{
34-
<# foreach (var field in implementedBy) { #>
35-
"<#= field #>" => json.Deserialize<<#= field #>>(),
49+
<# foreach (var field in implementedBy) { #>
50+
"<#= field #>" => json.Deserialize<<#= field #>>(),
3651
<# } #>
37-
_ => json.Deserialize< <#= GetInterfaceConcreteName() #>>()
52+
_ => json.Deserialize<<#= GetInterfaceConcreteName() #>>()
3853
};
3954
}
4055

41-
42-
43-
56+
/// <summary>
57+
/// GraphQL interface <#= classType.Name #> with all common fields
58+
/// </summary>
4459
[JsonConverter(typeof(<#= GetInterfaceConverterName() #>))]
4560
public interface <#= classType.Name #> <#= classType.GetInterfacesString() #>
4661
{
47-
<#
48-
foreach (var field in classType.AllFields)
49-
{
50-
var coreType = field.CoreType;
51-
#>
52-
[GraphQLMember("<#= field.Name #>")]
53-
public <#= coreType.CSharpTypeDefinition #> <#= field.CSharpName #> { get; set; }
54-
<#
55-
}
56-
#>
57-
[GraphQLMember("__typename")]
58-
public string __TypeName { get; set; }
62+
<# foreach (var field in classType.AllFields) {
63+
var coreType = field.CoreType; #>
64+
/// <summary>
65+
/// <#= field.Name #> field from GraphQL schema
66+
/// </summary>
67+
[GraphQLMember("<#= field.Name #>")]
68+
<#= coreType.CSharpTypeDefinition #> <#= field.CSharpName #> { get; set; }
5969

70+
<# } #>
71+
/// <summary>
72+
/// GraphQL __typename field for runtime type resolution
73+
/// </summary>
74+
[GraphQLMember("__typename")]
75+
string __TypeName { get; set; }
6076
}
6177

78+
/// <summary>
79+
/// Concrete implementation of <#= classType.Name #> interface for fallback deserialization
80+
/// </summary>
6281
internal class <#= GetInterfaceConcreteName() #> : <#= classType.Name #>
6382
{
64-
<#
65-
foreach (var field in classType.AllFields)
66-
{
67-
var coreType = field.CoreType;
68-
#>
69-
[GraphQLMember("<#= field.Name #>")]
70-
public <#= coreType.CSharpTypeDefinition #> <#= field.CSharpName #> { get; set; }
71-
<#
72-
}
73-
#>
83+
<# foreach (var field in classType.AllFields) {
84+
var coreType = field.CoreType; #>
85+
/// <summary>
86+
/// <#= field.Name #> field from GraphQL schema
87+
/// </summary>
88+
[GraphQLMember("<#= field.Name #>")]
89+
<#= coreType.CSharpTypeDefinition #> <#= field.CSharpName #> { get; set; }
7490

91+
<# } #>
92+
/// <summary>
93+
/// GraphQL __typename field for runtime type resolution
94+
/// </summary>
7595
[GraphQLMember("__typename")]
76-
public string __TypeName { get; set; }
77-
96+
string __TypeName { get; set; }
7897
}
Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
11
<#@ template language="C#" #>
22
<#@ assembly name="System.Core" #>
3+
using System;
34
using System.Collections.Generic;
45
using Linq2GraphQL.Client;
5-
<#
6-
if (isSubscription)
7-
{
8-
#>
6+
<# if (isSubscription) { #>
97
using Linq2GraphQL.Client.Subscriptions;
10-
<#
11-
}
12-
#>
8+
<# } #>
139

1410
namespace <#= namespaceName #>;
1511

12+
/// <summary>
13+
/// Interface for <#= ClassName #> GraphQL operations
14+
/// </summary>
1615
public interface I<#= ClassName #>
1716
{
18-
<#
19-
foreach (var field in methodsType.AllFields)
20-
{
21-
var coreType = field.CoreType;
22-
#>
17+
<# foreach (var field in methodsType.AllFields) {
18+
var coreType = field.CoreType; #>
19+
/// <summary>
20+
/// Executes <#= field.Name #> GraphQL operation
21+
/// </summary>
2322
<# if (field.IsDeprecated) { #>
23+
/// <remarks>
24+
/// This operation is deprecated: <#= field.DeprecationReason #>
25+
/// </remarks>
2426
[Obsolete("<#= field.DeprecationReason #>")]
2527
<# } #>
28+
/// <param name="<#= field.CSharpName.ToCamelCase() #>">The operation parameters</param>
29+
/// <returns>GraphQL query result of type <#= GetReturnTypeString(field) #></returns>
2630
<#= GetReturnTypeString(field) #> <#= field.CSharpName #>(<#= field.GetArgString(false) #>);
27-
<#
28-
}
29-
#>
31+
32+
<# } #>
3033
}
Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,54 @@
11
<#@ template language="C#" #>
22
<#@ assembly name="System.Core" #>
3-
using System.Collections.Generic;
43
using System;
4+
using System.Collections.Generic;
55
using Linq2GraphQL.Client;
6-
<#
7-
if (isSubscription)
8-
{
9-
#>
6+
<# if (isSubscription) { #>
107
using Linq2GraphQL.Client.Subscriptions;
11-
<#
12-
}
13-
#>
8+
<# } #>
149

1510
namespace <#= namespaceName #>;
1611

12+
/// <summary>
13+
/// Implementation of <#= ClassName #> GraphQL operations
14+
/// </summary>
1715
public class <#= ClassName #> : I<#= ClassName #>
1816
{
1917
private readonly GraphClient client;
2018

19+
/// <summary>
20+
/// Initializes a new instance of the <#= ClassName #> class
21+
/// </summary>
22+
/// <param name="client">The GraphQL client instance</param>
2123
public <#= ClassName #>(GraphClient client)
2224
{
23-
this.client = client;
25+
this.client = client ?? throw new ArgumentNullException(nameof(client));
2426
}
2527

26-
<#
27-
foreach (var field in methodsType.AllFields)
28-
{
29-
var coreType = field.CoreType;
30-
#>
28+
<# foreach (var field in methodsType.AllFields) {
29+
var coreType = field.CoreType; #>
30+
/// <summary>
31+
/// Executes <#= field.Name #> GraphQL operation
32+
/// </summary>
3133
<# if (field.IsDeprecated) { #>
32-
[Obsolete("<#= field.DeprecationReason #>")]
33-
<# } #>
34-
public <#= GetReturnTypeString(field) #> <#= field.CSharpName #>(<#= field.GetArgString(false) #>)
34+
/// <remarks>
35+
/// This operation is deprecated: <#= field.DeprecationReason #>
36+
/// </remarks>
37+
[Obsolete("<#= field.DeprecationReason #>")]
38+
<# } #>
39+
/// <param name="<#= field.CSharpName.ToCamelCase() #>">The operation parameters</param>
40+
/// <returns>GraphQL query result of type <#= GetReturnTypeString(field) #></returns>
41+
public <#= GetReturnTypeString(field) #> <#= field.CSharpName #>(<#= field.GetArgString(false) #>)
3542
{
36-
var arguments = new List<ArgumentValue>
37-
{
38-
<#
39-
foreach (var arg in field.Args)
43+
var arguments = new List<ArgumentValue>
4044
{
41-
#>
42-
new("<#= arg.Name #>","<#= arg.CoreType.GraphQLTypeDefinition #>", <#= arg.Name.ToCamelCase() #>),
43-
<#
44-
}
45-
#>
46-
};
45+
<# foreach (var arg in field.Args) { #>
46+
new("<#= arg.Name #>", "<#= arg.CoreType.GraphQLTypeDefinition #>", <#= arg.Name.ToCamelCase() #>),
47+
<# } #>
48+
};
4749

48-
return <#= GetReturnBuilderString(field) #>(client, "<#= field.Name #>", <#= operationType #>, arguments);
50+
return <#= GetReturnBuilderString(field) #>(client, "<#= field.Name #>", <#= operationType #>, arguments);
4951
}
5052

51-
<#
52-
}
53-
#>
53+
<# } #>
5454
}

0 commit comments

Comments
 (0)