From 2a9d85f4ef595331c6ef863086f5d3e68b7914ba Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Tue, 26 Aug 2025 09:15:41 +1000 Subject: [PATCH] Allow null returned for nullable query resutls --- src/Directory.Build.props | 2 +- .../GraphApi/EfGraphQLService_First.cs | 47 ++-- .../GraphApi/EfGraphQLService_Queryable.cs | 30 +- .../EfGraphQLService_QueryableConnection.cs | 30 +- .../GraphApi/EfGraphQLService_Single.cs | 47 ++-- .../GraphApi/EfInterfaceGraphType.cs | 4 +- .../GraphApi/EfObjectGraphType.cs | 14 +- .../GraphApi/IEfGraphQLService_First.cs | 12 +- .../GraphApi/IEfGraphQLService_Queryable.cs | 9 +- .../IEfGraphQLService_QueryableConnection.cs | 8 +- .../GraphApi/IEfGraphQLService_Single.cs | 12 +- .../GraphApi/QueryGraphType.cs | 14 +- ...tionTests.NullQueryConnection.verified.txt | 9 + ...ationTests.NullQueryableFirst.verified.txt | 5 + ...ullQueryableFirstDisallowNull.verified.txt | 4 + ....NullTaskInnerQueryConnection.verified.txt | 9 + ...s.NullTaskInnerQueryableFirst.verified.txt | 5 + ...nerQueryableFirstDisallowNull.verified.txt | 4 + ....NullTaskInnerQueryableSingle.verified.txt | 5 + ...erQueryableSingleDisallowNull.verified.txt | 4 + ...Tests.NullTaskQueryConnection.verified.txt | 9 + ...nTests.NullTaskQueryableFirst.verified.txt | 5 + ...askQueryableFirstDisallowNull.verified.txt | 4 + ...Tests.NullTaskQueryableSingle.verified.txt | 5 + ...skQueryableSingleDisallowNull.verified.txt | 4 + .../IntegrationTests.SchemaPrint.verified.txt | 48 ++++ ...sts.SingleNullQueryableSingle.verified.txt | 5 + ...llQueryableSingleDisallowNull.verified.txt | 4 + .../IntegrationTests/IntegrationTests.cs | 258 ++++++++++++++++++ src/Tests/IntegrationTests/Query.cs | 75 +++++ 30 files changed, 598 insertions(+), 93 deletions(-) create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullQueryConnection.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullQueryableFirst.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullQueryableFirstDisallowNull.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryConnection.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableFirst.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableFirstDisallowNull.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableSingle.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableSingleDisallowNull.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryConnection.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableFirst.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableFirstDisallowNull.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableSingle.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableSingleDisallowNull.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.SingleNullQueryableSingle.verified.txt create mode 100644 src/Tests/IntegrationTests/IntegrationTests.SingleNullQueryableSingleDisallowNull.verified.txt diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 3e54a2e02..d9c2ca8e4 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,7 +2,7 @@ CS1591;NU5104;CS1573;CS9107;NU1608;NU1109 - 32.0.1 + 32.1.0 preview 1.0.0 EntityFrameworkCore, EntityFramework, GraphQL diff --git a/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_First.cs b/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_First.cs index 0b2ccf66f..e107d855f 100644 --- a/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_First.cs +++ b/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_First.cs @@ -6,7 +6,7 @@ partial class EfGraphQLService public FieldBuilder AddFirstField( IObjectGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -22,7 +22,7 @@ public FieldBuilder AddFirstField( public FieldBuilder AddFirstField( IObjectGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -38,7 +38,7 @@ public FieldBuilder AddFirstField( public FieldBuilder AddFirstField( IComplexGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -54,7 +54,7 @@ public FieldBuilder AddFirstField( public FieldBuilder AddFirstField( IComplexGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -70,7 +70,7 @@ public FieldBuilder AddFirstField( public FieldBuilder AddFirstField( IComplexGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -86,7 +86,7 @@ public FieldBuilder AddFirstField( public FieldBuilder AddFirstField( IComplexGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -101,7 +101,7 @@ public FieldBuilder AddFirstField( FieldType BuildFirstField( string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate, Type? graphType, bool nullable, @@ -123,7 +123,7 @@ FieldType BuildFirstField( FieldType BuildFirstField( string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate, Type? graphType, bool nullable, @@ -143,9 +143,20 @@ FieldType BuildFirstField( Type = graphType, Resolver = new FuncFieldResolver(async context => { - var efFieldContext = BuildContext(context); + var fieldContext = BuildContext(context); + + var task = resolve(fieldContext); + if (task == null) + { + return ReturnNullable(); + } + + var query = await task; + if (query == null) + { + return ReturnNullable(); + } - var query = await resolve(efFieldContext); if (disableTracking) { query = query.AsNoTracking(); @@ -187,24 +198,19 @@ FieldType BuildFirstField( if (first is not null) { - if (efFieldContext.Filters == null || - await efFieldContext.Filters.ShouldInclude(context.UserContext, efFieldContext.DbContext, context.User, first)) + if (fieldContext.Filters == null || + await fieldContext.Filters.ShouldInclude(context.UserContext, fieldContext.DbContext, context.User, first)) { if (mutate is not null) { - await mutate.Invoke(efFieldContext, first); + await mutate.Invoke(fieldContext, first); } return first; } } - if (nullable) - { - return null; - } - - throw new FirstEntityNotFoundException(); + return ReturnNullable(); }) }; @@ -214,5 +220,8 @@ await efFieldContext.Filters.ShouldInclude(context.UserContext, efFieldContext.D } return type; + + TReturn? ReturnNullable() => + nullable ? null : throw new FirstEntityNotFoundException(); } } \ No newline at end of file diff --git a/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_Queryable.cs b/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_Queryable.cs index b56c7d807..dcd169a77 100644 --- a/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_Queryable.cs +++ b/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_Queryable.cs @@ -6,7 +6,7 @@ partial class EfGraphQLService public FieldBuilder AddQueryField( IComplexGraphType graph, string name, - Func, IQueryable>? resolve = null, + Func, IQueryable?>? resolve = null, Type? graphType = null, bool omitQueryArguments = false) where TReturn : class @@ -19,7 +19,7 @@ public FieldBuilder AddQueryField( public FieldBuilder AddQueryField( IComplexGraphType graph, string name, - Func, Task>>? resolve = null, + Func, Task?>?>? resolve = null, Type? graphType = null, bool omitQueryArguments = false) where TReturn : class @@ -32,7 +32,7 @@ public FieldBuilder AddQueryField( public FieldBuilder AddQueryField( IComplexGraphType graph, string name, - Func, IQueryable>? resolve = null, + Func, IQueryable?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class @@ -45,7 +45,7 @@ public FieldBuilder AddQueryField( public FieldBuilder AddQueryField( IComplexGraphType graph, string name, - Func, Task>>? resolve = null, + Func, Task?>?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class @@ -58,7 +58,7 @@ public FieldBuilder AddQueryField( FieldType BuildQueryField( Type? itemGraphType, string name, - Func, IQueryable>? resolve, + Func, IQueryable?>? resolve, bool omitQueryArguments) where TReturn : class => BuildQueryField( @@ -70,7 +70,7 @@ FieldType BuildQueryField( FieldType BuildQueryField( Type? itemGraphType, string name, - Func, Task>>? resolve, + Func, Task?>?>? resolve, bool omitQueryArguments) where TReturn : class { @@ -91,7 +91,19 @@ FieldType BuildQueryField( async context => { var fieldContext = BuildContext(context); - var query = await resolve(fieldContext); + + var task = resolve(fieldContext); + if (task == null) + { + return []; + } + + var query = await task; + if (query == null) + { + return []; + } + if (disableTracking) { query = query.AsNoTracking(); @@ -109,8 +121,8 @@ FieldType BuildQueryField( try { - list = await query - .ToListAsync(context.CancellationToken); + list = await query + .ToListAsync(context.CancellationToken); } catch (TaskCanceledException) { diff --git a/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_QueryableConnection.cs b/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_QueryableConnection.cs index 973b139ea..692ac1fce 100644 --- a/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_QueryableConnection.cs +++ b/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_QueryableConnection.cs @@ -9,7 +9,7 @@ partial class EfGraphQLService public ConnectionBuilder AddQueryConnectionField( IComplexGraphType graph, string name, - Func, IOrderedQueryable>? resolve = null, + Func, IOrderedQueryable?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class => @@ -23,7 +23,7 @@ public ConnectionBuilder AddQueryConnectionField( public ConnectionBuilder AddQueryConnectionField( IComplexGraphType graph, string name, - Func, Task>>? resolve = null, + Func, Task?>?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class @@ -64,7 +64,7 @@ public ConnectionBuilder AddQueryConnectionField( public ConnectionBuilder AddQueryConnectionField( IComplexGraphType graph, string name, - Func, IOrderedQueryable>? resolve = null, + Func, IOrderedQueryable?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class => @@ -78,7 +78,7 @@ public ConnectionBuilder AddQueryConnectionField( public ConnectionBuilder AddQueryConnectionField( IComplexGraphType graph, string name, - Func, Task>>? resolve = null, + Func, Task?>?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class @@ -121,7 +121,7 @@ public ConnectionBuilder AddQueryConnectionField( ConnectionBuilder AddQueryableConnection( IComplexGraphType graph, string name, - Func, Task>>? resolve, + Func, Task?>?>? resolve, bool omitQueryArguments) where TGraph : IGraphType where TReturn : class @@ -134,8 +134,20 @@ ConnectionBuilder AddQueryableConnection( builder.ResolveAsync( async context => { - var efFieldContext = BuildContext(context); - IQueryable query = await resolve(efFieldContext); + var fieldContext = BuildContext(context); + + var task = resolve(fieldContext); + if (task == null) + { + return new Connection(); + } + + IQueryable? query = await task; + if (query == null) + { + return new Connection(); + } + if (disableTracking) { query = query.AsNoTracking(); @@ -154,8 +166,8 @@ ConnectionBuilder AddQueryableConnection( context.Before!, context, context.CancellationToken, - efFieldContext.Filters, - efFieldContext.DbContext); + fieldContext.Filters, + fieldContext.DbContext); } catch (TaskCanceledException) { diff --git a/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_Single.cs b/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_Single.cs index 4d3b1c9de..cb5dcd209 100644 --- a/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_Single.cs +++ b/src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_Single.cs @@ -6,7 +6,7 @@ partial class EfGraphQLService public FieldBuilder AddSingleField( IObjectGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -22,7 +22,7 @@ public FieldBuilder AddSingleField( public FieldBuilder AddSingleField( IObjectGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -38,7 +38,7 @@ public FieldBuilder AddSingleField( public FieldBuilder AddSingleField( IComplexGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -54,7 +54,7 @@ public FieldBuilder AddSingleField( public FieldBuilder AddSingleField( IComplexGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -70,7 +70,7 @@ public FieldBuilder AddSingleField( public FieldBuilder AddSingleField( IComplexGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -86,7 +86,7 @@ public FieldBuilder AddSingleField( public FieldBuilder AddSingleField( IComplexGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -101,7 +101,7 @@ public FieldBuilder AddSingleField( FieldType BuildSingleField( string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate, Type? graphType, bool nullable, @@ -123,7 +123,7 @@ FieldType BuildSingleField( FieldType BuildSingleField( string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate, Type? graphType, bool nullable, @@ -144,9 +144,20 @@ FieldType BuildSingleField( Resolver = new FuncFieldResolver( async context => { - var efFieldContext = BuildContext(context); + var fieldContext = BuildContext(context); + + var task = resolve(fieldContext); + if (task == null) + { + return ReturnNullable(); + } + + var query = await task; + if (query == null) + { + return ReturnNullable(); + } - var query = await resolve(efFieldContext); if (disableTracking) { query = query.AsNoTracking(); @@ -188,24 +199,19 @@ FieldType BuildSingleField( if (single is not null) { - if (efFieldContext.Filters == null || - await efFieldContext.Filters.ShouldInclude(context.UserContext, efFieldContext.DbContext, context.User, single)) + if (fieldContext.Filters == null || + await fieldContext.Filters.ShouldInclude(context.UserContext, fieldContext.DbContext, context.User, single)) { if (mutate is not null) { - await mutate.Invoke(efFieldContext, single); + await mutate.Invoke(fieldContext, single); } return single; } } - if (nullable) - { - return null; - } - - throw new SingleEntityNotFoundException(); + return ReturnNullable(); }) }; @@ -215,5 +221,8 @@ await efFieldContext.Filters.ShouldInclude(context.UserContext, efFieldContext.D } return type; + + TReturn? ReturnNullable() => + nullable ? null : throw new SingleEntityNotFoundException(); } } \ No newline at end of file diff --git a/src/GraphQL.EntityFramework/GraphApi/EfInterfaceGraphType.cs b/src/GraphQL.EntityFramework/GraphApi/EfInterfaceGraphType.cs index 46dfb9f9e..2e82b3bb3 100644 --- a/src/GraphQL.EntityFramework/GraphApi/EfInterfaceGraphType.cs +++ b/src/GraphQL.EntityFramework/GraphApi/EfInterfaceGraphType.cs @@ -33,14 +33,14 @@ public ConnectionBuilder AddQueryConnectionField( string name, Type? graphType = null) where TReturn : class => - GraphQlService.AddQueryConnectionField(this, name, (Func, Task>>?)null, graphType); + GraphQlService.AddQueryConnectionField(this, name, (Func, Task?>?>?)null, graphType); public FieldBuilder AddQueryField( string name, Type? graphType = null, bool omitQueryArguments = false) where TReturn : class => - GraphQlService.AddQueryField(this, name, (Func, Task>>?)null, graphType, omitQueryArguments); + GraphQlService.AddQueryField(this, name, (Func, Task?>?>?)null, graphType, omitQueryArguments); public TDbContext ResolveDbContext(IResolveFieldContext context) => GraphQlService.ResolveDbContext(context); diff --git a/src/GraphQL.EntityFramework/GraphApi/EfObjectGraphType.cs b/src/GraphQL.EntityFramework/GraphApi/EfObjectGraphType.cs index f5b9e9d95..728e9c43e 100644 --- a/src/GraphQL.EntityFramework/GraphApi/EfObjectGraphType.cs +++ b/src/GraphQL.EntityFramework/GraphApi/EfObjectGraphType.cs @@ -45,14 +45,14 @@ public FieldBuilder AddNavigationListField( public ConnectionBuilder AddQueryConnectionField( string name, - Func, IOrderedQueryable> resolve, + Func, IOrderedQueryable?> resolve, Type? graphType = null) where TReturn : class => GraphQlService.AddQueryConnectionField(this, name, resolve, graphType); public FieldBuilder AddQueryField( string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Type? graphType = null, bool omitQueryArguments = false) where TReturn : class => @@ -60,7 +60,7 @@ public FieldBuilder AddQueryField( public FieldBuilder AddQueryField( string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Type? graphType = null, bool omitQueryArguments = false) where TReturn : class => @@ -74,7 +74,7 @@ public TDbContext ResolveDbContext(IResolveFieldContext context) => public FieldBuilder AddSingleField( string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -85,7 +85,7 @@ public FieldBuilder AddSingleField( public FieldBuilder AddSingleField( string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -96,7 +96,7 @@ public FieldBuilder AddSingleField( public FieldBuilder AddFirstField( string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -107,7 +107,7 @@ public FieldBuilder AddFirstField( public FieldBuilder AddFirstField( string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, diff --git a/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_First.cs b/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_First.cs index 0fd83bbb8..e05c3aa58 100644 --- a/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_First.cs +++ b/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_First.cs @@ -5,7 +5,7 @@ public partial interface IEfGraphQLService FieldBuilder AddFirstField( IObjectGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -16,7 +16,7 @@ FieldBuilder AddFirstField( FieldBuilder AddFirstField( IObjectGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -27,7 +27,7 @@ FieldBuilder AddFirstField( FieldBuilder AddFirstField( IComplexGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -38,7 +38,7 @@ FieldBuilder AddFirstField( FieldBuilder AddFirstField( IComplexGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -49,7 +49,7 @@ FieldBuilder AddFirstField( FieldBuilder AddFirstField( IComplexGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -60,7 +60,7 @@ FieldBuilder AddFirstField( FieldBuilder AddFirstField( IComplexGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, diff --git a/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_Queryable.cs b/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_Queryable.cs index eba394be2..3204d1294 100644 --- a/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_Queryable.cs +++ b/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_Queryable.cs @@ -5,14 +5,15 @@ public partial interface IEfGraphQLService FieldBuilder AddQueryField( IComplexGraphType graph, string name, - Func, IQueryable>? resolve = null, + Func, IQueryable?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class; + FieldBuilder AddQueryField( IComplexGraphType graph, string name, - Func, Task>>? resolve = null, + Func, Task?>?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class; @@ -20,7 +21,7 @@ FieldBuilder AddQueryField( FieldBuilder AddQueryField( IComplexGraphType graph, string name, - Func, IQueryable>? resolve = null, + Func, IQueryable?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class; @@ -28,7 +29,7 @@ FieldBuilder AddQueryField( FieldBuilder AddQueryField( IComplexGraphType graph, string name, - Func, Task>>? resolve = null, + Func, Task?>?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class; diff --git a/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_QueryableConnection.cs b/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_QueryableConnection.cs index 1deb6637d..8edd44788 100644 --- a/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_QueryableConnection.cs +++ b/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_QueryableConnection.cs @@ -5,7 +5,7 @@ public partial interface IEfGraphQLService ConnectionBuilder AddQueryConnectionField( IComplexGraphType graph, string name, - Func, IOrderedQueryable>? resolve = null, + Func, IOrderedQueryable?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class; @@ -13,7 +13,7 @@ ConnectionBuilder AddQueryConnectionField( ConnectionBuilder AddQueryConnectionField( IComplexGraphType graph, string name, - Func, Task>>? resolve = null, + Func, Task?>?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class; @@ -21,7 +21,7 @@ ConnectionBuilder AddQueryConnectionField( ConnectionBuilder AddQueryConnectionField( IComplexGraphType graph, string name, - Func, IOrderedQueryable>? resolve = null, + Func, IOrderedQueryable?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class; @@ -29,7 +29,7 @@ ConnectionBuilder AddQueryConnectionField( ConnectionBuilder AddQueryConnectionField( IComplexGraphType graph, string name, - Func, Task>>? resolve = null, + Func, Task?>?>? resolve = null, Type? itemGraphType = null, bool omitQueryArguments = false) where TReturn : class; diff --git a/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_Single.cs b/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_Single.cs index 5254540f7..ee050f711 100644 --- a/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_Single.cs +++ b/src/GraphQL.EntityFramework/GraphApi/IEfGraphQLService_Single.cs @@ -5,7 +5,7 @@ public partial interface IEfGraphQLService FieldBuilder AddSingleField( IObjectGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -16,7 +16,7 @@ FieldBuilder AddSingleField( FieldBuilder AddSingleField( IObjectGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -27,7 +27,7 @@ FieldBuilder AddSingleField( FieldBuilder AddSingleField( IComplexGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -38,7 +38,7 @@ FieldBuilder AddSingleField( FieldBuilder AddSingleField( IComplexGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -49,7 +49,7 @@ FieldBuilder AddSingleField( FieldBuilder AddSingleField( IComplexGraphType graph, string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, @@ -60,7 +60,7 @@ FieldBuilder AddSingleField( FieldBuilder AddSingleField( IComplexGraphType graph, string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, bool nullable = false, diff --git a/src/GraphQL.EntityFramework/GraphApi/QueryGraphType.cs b/src/GraphQL.EntityFramework/GraphApi/QueryGraphType.cs index c7aacaf0d..3754ab380 100644 --- a/src/GraphQL.EntityFramework/GraphApi/QueryGraphType.cs +++ b/src/GraphQL.EntityFramework/GraphApi/QueryGraphType.cs @@ -14,14 +14,14 @@ public TDbContext ResolveDbContext(IResolveFieldContext context) => public ConnectionBuilder AddQueryConnectionField( string name, - Func, IOrderedQueryable> resolve, + Func, IOrderedQueryable?> resolve, Type? graphType = null) where TReturn : class => GraphQlService.AddQueryConnectionField(this, name, resolve, graphType); public FieldBuilder AddQueryField( string name, - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Type? graphType = null, bool omitQueryArguments = false) where TReturn : class => @@ -29,14 +29,14 @@ public FieldBuilder AddQueryField( public FieldBuilder AddQueryField( string name, - Func, Task>> resolve, + Func, Task?>?> resolve, Type? graphType = null, bool omitQueryArguments = false) where TReturn : class => GraphQlService.AddQueryField(this, name, resolve, graphType, omitQueryArguments); public FieldBuilder AddSingleField( - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, string name = nameof(TReturn), @@ -47,7 +47,7 @@ public FieldBuilder AddSingleField( GraphQlService.AddSingleField(this, name, resolve, mutate, graphType, nullable, omitQueryArguments, idOnly); public FieldBuilder AddSingleField( - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, string name = nameof(TReturn), @@ -58,7 +58,7 @@ public FieldBuilder AddSingleField( GraphQlService.AddSingleField(this, name, resolve, mutate, graphType, nullable, omitQueryArguments, idOnly); public FieldBuilder AddFirstField( - Func, IQueryable> resolve, + Func, IQueryable?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, string name = nameof(TReturn), @@ -69,7 +69,7 @@ public FieldBuilder AddFirstField( GraphQlService.AddFirstField(this, name, resolve, mutate, graphType, nullable, omitQueryArguments, idOnly); public FieldBuilder AddFirstField( - Func, Task>> resolve, + Func, Task?>?> resolve, Func, TReturn, Task>? mutate = null, Type? graphType = null, string name = nameof(TReturn), diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullQueryConnection.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullQueryConnection.verified.txt new file mode 100644 index 000000000..55093a37a --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullQueryConnection.verified.txt @@ -0,0 +1,9 @@ +{ + "data": { + "nullQueryConnection": { + "totalCount": null, + "edges": null, + "items": null + } + } +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullQueryableFirst.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullQueryableFirst.verified.txt new file mode 100644 index 000000000..8e9c8b977 --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullQueryableFirst.verified.txt @@ -0,0 +1,5 @@ +{ + "data": { + "nullQueryableFirst": null + } +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullQueryableFirstDisallowNull.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullQueryableFirstDisallowNull.verified.txt new file mode 100644 index 000000000..a2f11ff75 --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullQueryableFirstDisallowNull.verified.txt @@ -0,0 +1,4 @@ +{ + Type: FirstEntityNotFoundException, + Message: Not found +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryConnection.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryConnection.verified.txt new file mode 100644 index 000000000..7edc19aa5 --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryConnection.verified.txt @@ -0,0 +1,9 @@ +{ + "data": { + "nullTaskInnerQueryConnection": { + "totalCount": null, + "edges": null, + "items": null + } + } +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableFirst.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableFirst.verified.txt new file mode 100644 index 000000000..6a4d49616 --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableFirst.verified.txt @@ -0,0 +1,5 @@ +{ + "data": { + "nullTaskInnerQueryableFirst": null + } +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableFirstDisallowNull.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableFirstDisallowNull.verified.txt new file mode 100644 index 000000000..a2f11ff75 --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableFirstDisallowNull.verified.txt @@ -0,0 +1,4 @@ +{ + Type: FirstEntityNotFoundException, + Message: Not found +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableSingle.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableSingle.verified.txt new file mode 100644 index 000000000..8cb3a8e57 --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableSingle.verified.txt @@ -0,0 +1,5 @@ +{ + "data": { + "nullTaskInnerQueryableSingle": null + } +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableSingleDisallowNull.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableSingleDisallowNull.verified.txt new file mode 100644 index 000000000..d91e56216 --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullTaskInnerQueryableSingleDisallowNull.verified.txt @@ -0,0 +1,4 @@ +{ + Type: SingleEntityNotFoundException, + Message: Not found +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryConnection.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryConnection.verified.txt new file mode 100644 index 000000000..8a4baf3c7 --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryConnection.verified.txt @@ -0,0 +1,9 @@ +{ + "data": { + "nullTaskQueryConnection": { + "totalCount": null, + "edges": null, + "items": null + } + } +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableFirst.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableFirst.verified.txt new file mode 100644 index 000000000..e8eb798bb --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableFirst.verified.txt @@ -0,0 +1,5 @@ +{ + "data": { + "nullTaskQueryableFirst": null + } +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableFirstDisallowNull.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableFirstDisallowNull.verified.txt new file mode 100644 index 000000000..a2f11ff75 --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableFirstDisallowNull.verified.txt @@ -0,0 +1,4 @@ +{ + Type: FirstEntityNotFoundException, + Message: Not found +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableSingle.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableSingle.verified.txt new file mode 100644 index 000000000..db6b63add --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableSingle.verified.txt @@ -0,0 +1,5 @@ +{ + "data": { + "nullTaskQueryableSingle": null + } +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableSingleDisallowNull.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableSingleDisallowNull.verified.txt new file mode 100644 index 000000000..d91e56216 --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.NullTaskQueryableSingleDisallowNull.verified.txt @@ -0,0 +1,4 @@ +{ + Type: SingleEntityNotFoundException, + Message: Not found +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.SchemaPrint.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.SchemaPrint.verified.txt index ffc66aea0..c993194c2 100644 --- a/src/Tests/IntegrationTests/IntegrationTests.SchemaPrint.verified.txt +++ b/src/Tests/IntegrationTests/IntegrationTests.SchemaPrint.verified.txt @@ -90,6 +90,54 @@ parentEntityViewNullableFirst(where: [WhereExpression!]): ParentEntityView ownedParent(id: ID, ids: [ID!], where: [WhereExpression!]): OwnedParent ownedParentFirst(id: ID, ids: [ID!], where: [WhereExpression!]): OwnedParent + nullQueryableSingle(id: ID, ids: [ID!], where: [WhereExpression!]): Parent + nullQueryableFirst(id: ID, ids: [ID!], where: [WhereExpression!]): Parent + nullTaskQueryableSingle(id: ID, ids: [ID!], where: [WhereExpression!]): Parent + nullTaskInnerQueryableSingle(id: ID, ids: [ID!], where: [WhereExpression!]): Parent + nullTaskQueryableFirst(id: ID, ids: [ID!], where: [WhereExpression!]): Parent + nullTaskInnerQueryableFirst(id: ID, ids: [ID!], where: [WhereExpression!]): Parent + nullQueryableSingleDisallowNull(id: ID, ids: [ID!], where: [WhereExpression!]): Parent! + nullQueryableFirstDisallowNull(id: ID, ids: [ID!], where: [WhereExpression!]): Parent! + nullTaskQueryableSingleDisallowNull(id: ID, ids: [ID!], where: [WhereExpression!]): Parent! + nullTaskInnerQueryableSingleDisallowNull(id: ID, ids: [ID!], where: [WhereExpression!]): Parent! + nullTaskQueryableFirstDisallowNull(id: ID, ids: [ID!], where: [WhereExpression!]): Parent! + nullTaskInnerQueryableFirstDisallowNull(id: ID, ids: [ID!], where: [WhereExpression!]): Parent! + nullQueryConnection( + "Only return edges after the specified cursor." + after: String, + "Specifies the maximum number of edges to return, starting after the cursor specified by 'after', or the first number of edges if 'after' is not specified." + first: Int, + "Only return edges prior to the specified cursor." + before: String, + "Specifies the maximum number of edges to return, starting prior to the cursor specified by 'before', or the last number of edges if 'before' is not specified." + last: Int, + where: [WhereExpression!], + orderBy: [OrderBy!], + ids: [ID!]): ParentConnection! + nullTaskQueryConnection( + "Only return edges after the specified cursor." + after: String, + "Specifies the maximum number of edges to return, starting after the cursor specified by 'after', or the first number of edges if 'after' is not specified." + first: Int, + "Only return edges prior to the specified cursor." + before: String, + "Specifies the maximum number of edges to return, starting prior to the cursor specified by 'before', or the last number of edges if 'before' is not specified." + last: Int, + where: [WhereExpression!], + orderBy: [OrderBy!], + ids: [ID!]): ParentConnection! + nullTaskInnerQueryConnection( + "Only return edges after the specified cursor." + after: String, + "Specifies the maximum number of edges to return, starting after the cursor specified by 'after', or the first number of edges if 'after' is not specified." + first: Int, + "Only return edges prior to the specified cursor." + before: String, + "Specifies the maximum number of edges to return, starting prior to the cursor specified by 'before', or the last number of edges if 'before' is not specified." + last: Int, + where: [WhereExpression!], + orderBy: [OrderBy!], + ids: [ID!]): ParentConnection! } type CustomType { diff --git a/src/Tests/IntegrationTests/IntegrationTests.SingleNullQueryableSingle.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.SingleNullQueryableSingle.verified.txt new file mode 100644 index 000000000..676e350ce --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.SingleNullQueryableSingle.verified.txt @@ -0,0 +1,5 @@ +{ + "data": { + "nullQueryableSingle": null + } +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.SingleNullQueryableSingleDisallowNull.verified.txt b/src/Tests/IntegrationTests/IntegrationTests.SingleNullQueryableSingleDisallowNull.verified.txt new file mode 100644 index 000000000..d91e56216 --- /dev/null +++ b/src/Tests/IntegrationTests/IntegrationTests.SingleNullQueryableSingleDisallowNull.verified.txt @@ -0,0 +1,4 @@ +{ + Type: SingleEntityNotFoundException, + Message: Not found +} \ No newline at end of file diff --git a/src/Tests/IntegrationTests/IntegrationTests.cs b/src/Tests/IntegrationTests/IntegrationTests.cs index 2708c5318..48b0d2b66 100644 --- a/src/Tests/IntegrationTests/IntegrationTests.cs +++ b/src/Tests/IntegrationTests/IntegrationTests.cs @@ -3021,4 +3021,262 @@ static IEnumerable GetGraphQlTypes() => .Assembly .GetTypes() .Where(_ => !_.IsAbstract && _.IsAssignableTo()); + + [Fact] + public async Task SingleNullQueryableSingle() + { + var query = + """ + { + nullQueryableSingle(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task NullQueryableFirst() + { + var query = + """ + { + nullQueryableFirst(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task NullTaskQueryableSingle() + { + var query = + """ + { + nullTaskQueryableSingle(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task NullTaskInnerQueryableSingle() + { + var query = + """ + { + nullTaskInnerQueryableSingle(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task NullTaskQueryableFirst() + { + var query = + """ + { + nullTaskQueryableFirst(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task NullTaskInnerQueryableFirst() + { + var query = + """ + { + nullTaskInnerQueryableFirst(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task SingleNullQueryableSingleDisallowNull() + { + var query = + """ + { + nullQueryableSingleDisallowNull(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task NullQueryableFirstDisallowNull() + { + var query = + """ + { + nullQueryableFirstDisallowNull(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task NullTaskQueryableSingleDisallowNull() + { + var query = + """ + { + nullTaskQueryableSingleDisallowNull(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task NullTaskInnerQueryableSingleDisallowNull() + { + var query = + """ + { + nullTaskInnerQueryableSingleDisallowNull(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task NullTaskQueryableFirstDisallowNull() + { + var query = + """ + { + nullTaskQueryableFirstDisallowNull(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task NullTaskInnerQueryableFirstDisallowNull() + { + var query = + """ + { + nullTaskInnerQueryableFirstDisallowNull(id: "00000000-0000-0000-0000-000000000001") { + property + } + } + """; + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, []); + } + + [Fact] + public async Task NullQueryConnection() + { + var query = + """ + { + nullQueryConnection(first:2, after: "0") { + totalCount + edges { + cursor + node { + property + } + } + items { + property + } + } + } + """; + var entities = BuildEntities(8); + + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, entities.ToArray()); + } + + [Fact] + public async Task NullTaskQueryConnection() + { + var query = + """ + { + nullTaskQueryConnection(first:2, after: "0") { + totalCount + edges { + cursor + node { + property + } + } + items { + property + } + } + } + """; + var entities = BuildEntities(8); + + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, entities.ToArray()); + } + + [Fact] + public async Task NullTaskInnerQueryConnection() + { + var query = + """ + { + nullTaskInnerQueryConnection(first:2, after: "0") { + totalCount + edges { + cursor + node { + property + } + } + items { + property + } + } + } + """; + var entities = BuildEntities(8); + + await using var database = await sqlInstance.Build(); + await RunQuery(database, query, null, null, false, entities.ToArray()); + } } \ No newline at end of file diff --git a/src/Tests/IntegrationTests/Query.cs b/src/Tests/IntegrationTests/Query.cs index ebbac7c8d..30d14ccff 100644 --- a/src/Tests/IntegrationTests/Query.cs +++ b/src/Tests/IntegrationTests/Query.cs @@ -178,5 +178,80 @@ public Query(IEfGraphQLService efGraphQlService) name: "ownedParentFirst", resolve: _ => _.DbContext.OwnedParents, nullable: true); + + AddSingleField( + name: "nullQueryableSingle", + resolve: IQueryable? (_) => null, + nullable: true); + + AddFirstField( + name: "nullQueryableFirst", + resolve: IQueryable? (_) => null, + nullable: true); + + AddSingleField( + name: "nullTaskQueryableSingle", + resolve: Task?>? (_) => null, + nullable: true); + + AddSingleField( + name: "nullTaskInnerQueryableSingle", + resolve: Task?>? (_) => Task.FromResult?>(null), + nullable: true); + + AddFirstField( + name: "nullTaskQueryableFirst", + resolve: Task?>? (_) => null, + nullable: true); + + AddFirstField( + name: "nullTaskInnerQueryableFirst", + resolve: Task?>? (_) => Task.FromResult?>(null), + nullable: true); + + AddSingleField( + name: "nullQueryableSingleDisallowNull", + resolve: IQueryable? (_) => null); + + AddFirstField( + name: "nullQueryableFirstDisallowNull", + resolve: IQueryable? (_) => null); + + AddSingleField( + name: "nullTaskQueryableSingleDisallowNull", + resolve: Task?>? (_) => null); + + AddSingleField( + name: "nullTaskInnerQueryableSingleDisallowNull", + resolve: Task?>? (_) => Task.FromResult?>(null)); + + AddFirstField( + name: "nullTaskQueryableFirstDisallowNull", + resolve: Task?>? (_) => null); + + AddFirstField( + name: "nullTaskInnerQueryableFirstDisallowNull", + resolve: Task?>? (_) => Task.FromResult?>(null)); + + efGraphQlService + .AddQueryConnectionField( + this, + name: "nullQueryConnection", + resolve: IOrderedQueryable? (_) => null) + .PageSize(10); + + efGraphQlService + .AddQueryConnectionField( + this, + name: "nullTaskQueryConnection", + resolve: Task?>? (_) => null) + .PageSize(10); + + efGraphQlService + .AddQueryConnectionField( + this, + name: "nullTaskInnerQueryConnection", + resolve: Task?>? (_) => Task.FromResult?>(null)) + .PageSize(10); } } \ No newline at end of file