Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project>
<PropertyGroup>
<NoWarn>CS1591;NU5104;CS1573;CS9107;NU1608</NoWarn>
<Version>28.0.0</Version>
<Version>28.1.0</Version>
<LangVersion>preview</LangVersion>
<AssemblyVersion>1.0.0</AssemblyVersion>
<PackageTags>EntityFrameworkCore, EntityFramework, GraphQL</PackageTags>
Expand Down
187 changes: 128 additions & 59 deletions src/GraphQL.EntityFramework/GraphApi/EfGraphQLService_First.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,22 @@ public FieldBuilder<object, TReturn> AddFirstField<TReturn>(
return new FieldBuilderEx<object, TReturn>(field);
}

public FieldBuilder<object, TReturn> AddFirstField<TReturn>(
IObjectGraphType graph,
string name,
Func<ResolveEfFieldContext<TDbContext, object>, Task<IQueryable<TReturn>>> resolve,
Func<ResolveEfFieldContext<TDbContext, object>, TReturn, Task>? mutate = null,
Type? graphType = null,
bool nullable = false,
bool omitQueryArguments = false,
bool idOnly = false)
where TReturn : class
{
var field = BuildFirstField(name, resolve, mutate, graphType, nullable, omitQueryArguments, idOnly);
graph.AddField(field);
return new FieldBuilderEx<object, TReturn>(field);
}

public FieldBuilder<object, TReturn> AddFirstField<TReturn>(
IComplexGraphType graph,
string name,
Expand All @@ -35,6 +51,22 @@ public FieldBuilder<object, TReturn> AddFirstField<TReturn>(
return new FieldBuilderEx<object, TReturn>(field);
}

public FieldBuilder<object, TReturn> AddFirstField<TReturn>(
IComplexGraphType graph,
string name,
Func<ResolveEfFieldContext<TDbContext, object>, Task<IQueryable<TReturn>>> resolve,
Func<ResolveEfFieldContext<TDbContext, object>, TReturn, Task>? mutate = null,
Type? graphType = null,
bool nullable = false,
bool omitQueryArguments = false,
bool idOnly = false)
where TReturn : class
{
var field = BuildFirstField(name, resolve, mutate, graphType, nullable, omitQueryArguments, idOnly);
graph.AddField(field);
return new FieldBuilderEx<object, TReturn>(field);
}

public FieldBuilder<TSource, TReturn> AddFirstField<TSource, TReturn>(
IComplexGraphType graph,
string name,
Expand All @@ -51,6 +83,22 @@ public FieldBuilder<TSource, TReturn> AddFirstField<TSource, TReturn>(
return new FieldBuilderEx<TSource, TReturn>(field);
}

public FieldBuilder<TSource, TReturn> AddFirstField<TSource, TReturn>(
IComplexGraphType graph,
string name,
Func<ResolveEfFieldContext<TDbContext, TSource>, Task<IQueryable<TReturn>>> resolve,
Func<ResolveEfFieldContext<TDbContext, TSource>, TReturn, Task>? mutate = null,
Type? graphType = null,
bool nullable = false,
bool omitQueryArguments = false,
bool idOnly = false)
where TReturn : class
{
var field = BuildFirstField(name, resolve, mutate, graphType, nullable, omitQueryArguments, idOnly);
graph.AddField(field);
return new FieldBuilderEx<TSource, TReturn>(field);
}

FieldType BuildFirstField<TSource, TReturn>(
string name,
Func<ResolveEfFieldContext<TDbContext, TSource>, IQueryable<TReturn>> resolve,
Expand All @@ -60,6 +108,28 @@ FieldType BuildFirstField<TSource, TReturn>(
bool omitQueryArguments,
bool idOnly)
where TReturn : class
=> BuildFirstField(
name,
_ =>
{
var queryable = resolve(_);
return Task.FromResult(queryable);
},
mutate,
graphType,
nullable,
omitQueryArguments,
idOnly);

FieldType BuildFirstField<TSource, TReturn>(
string name,
Func<ResolveEfFieldContext<TDbContext, TSource>, Task<IQueryable<TReturn>>> resolve,
Func<ResolveEfFieldContext<TDbContext, TSource>, TReturn, Task>? mutate,
Type? graphType,
bool nullable,
bool omitQueryArguments,
bool idOnly)
where TReturn : class
{
Guard.AgainstWhiteSpace(nameof(name), name);

Expand All @@ -71,79 +141,78 @@ FieldType BuildFirstField<TSource, TReturn>(
{
Name = name,
Type = graphType,
Resolver = new FuncFieldResolver<TSource, TReturn?>(
async context =>
{
var efFieldContext = BuildContext(context);
Resolver = new FuncFieldResolver<TSource, TReturn?>(async context =>
{
var efFieldContext = BuildContext(context);

var query = resolve(efFieldContext);
if (disableTracking)
{
query = query.AsNoTracking();
}
var query = await resolve(efFieldContext);
if (disableTracking)
{
query = query.AsNoTracking();
}

query = includeAppender.AddIncludes(query, context);
query = query.ApplyGraphQlArguments(context, names, false, omitQueryArguments);
query = includeAppender.AddIncludes(query, context);
query = query.ApplyGraphQlArguments(context, names, false, omitQueryArguments);

QueryLogger.Write(query);
QueryLogger.Write(query);

TReturn? first;
try
{
if (disableAsync)
{
first = query.FirstOrDefault();
}
else
{
first = await query.FirstOrDefaultAsync(context.CancellationToken);
}
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
TReturn? first;
try
{
if (disableAsync)
{
throw;
first = query.FirstOrDefault();
}
catch (Exception exception)
else
{
throw new(
$"""
Failed to execute query for field `{name}`
GraphType: {graphType.FullName}
TSource: {typeof(TSource).FullName}
TReturn: {typeof(TReturn).FullName}
DisableAsync: {disableAsync}
OmitQueryArguments: {omitQueryArguments}
Nullable: {nullable}
KeyNames: {JoinKeys(names)}
Query: {query.ToQueryString()}
""",
exception);
first = await query.FirstOrDefaultAsync(context.CancellationToken);
}

if (first is not null)
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception exception)
{
throw new(
$"""
Failed to execute query for field `{name}`
GraphType: {graphType.FullName}
TSource: {typeof(TSource).FullName}
TReturn: {typeof(TReturn).FullName}
DisableAsync: {disableAsync}
OmitQueryArguments: {omitQueryArguments}
Nullable: {nullable}
KeyNames: {JoinKeys(names)}
Query: {query.ToQueryString()}
""",
exception);
}

if (first is not null)
{
if (await efFieldContext.Filters.ShouldInclude(context.UserContext, context.User, first))
{
if (await efFieldContext.Filters.ShouldInclude(context.UserContext, context.User, first))
if (mutate is not null)
{
if (mutate is not null)
{
await mutate.Invoke(efFieldContext, first);
}

return first;
await mutate.Invoke(efFieldContext, first);
}
}

if (nullable)
{
return null;
return first;
}
}

if (nullable)
{
return null;
}

throw new FirstEntityNotFoundException();
})
throw new FirstEntityNotFoundException();
})
};

if (!omitQueryArguments)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ public FieldBuilder<object, TReturn> AddQueryField<TReturn>(
return new FieldBuilderEx<object, TReturn>(field);
}

public FieldBuilder<object, TReturn> AddQueryField<TReturn>(
IComplexGraphType graph,
string name,
Func<ResolveEfFieldContext<TDbContext, object>, Task<IQueryable<TReturn>>>? resolve = null,
Type? graphType = null,
bool omitQueryArguments = false)
where TReturn : class
{
var field = BuildQueryField(graphType, name, resolve, omitQueryArguments);
graph.AddField(field);
return new FieldBuilderEx<object, TReturn>(field);
}

public FieldBuilder<TSource, TReturn> AddQueryField<TSource, TReturn>(
IComplexGraphType graph,
string name,
Expand All @@ -29,11 +42,36 @@ public FieldBuilder<TSource, TReturn> AddQueryField<TSource, TReturn>(
return new FieldBuilderEx<TSource, TReturn>(field);
}

public FieldBuilder<TSource, TReturn> AddQueryField<TSource, TReturn>(
IComplexGraphType graph,
string name,
Func<ResolveEfFieldContext<TDbContext, TSource>, Task<IQueryable<TReturn>>>? resolve = null,
Type? itemGraphType = null,
bool omitQueryArguments = false)
where TReturn : class
{
var field = BuildQueryField(itemGraphType, name, resolve, omitQueryArguments);
graph.AddField(field);
return new FieldBuilderEx<TSource, TReturn>(field);
}

FieldType BuildQueryField<TSource, TReturn>(
Type? itemGraphType,
string name,
Func<ResolveEfFieldContext<TDbContext, TSource>, IQueryable<TReturn>>? resolve,
bool omitQueryArguments)
where TReturn : class =>
BuildQueryField<TSource, TReturn>(
itemGraphType,
name,
resolve == null ? null : context => Task.FromResult(resolve(context)),
omitQueryArguments);

FieldType BuildQueryField<TSource, TReturn>(
Type? itemGraphType,
string name,
Func<ResolveEfFieldContext<TDbContext, TSource>, Task<IQueryable<TReturn>>>? resolve,
bool omitQueryArguments)
where TReturn : class
{
Guard.AgainstWhiteSpace(nameof(name), name);
Expand All @@ -53,7 +91,7 @@ FieldType BuildQueryField<TSource, TReturn>(
async context =>
{
var fieldContext = BuildContext(context);
var query = resolve(fieldContext);
var query = await resolve(fieldContext);
if (disableTracking)
{
query = query.AsNoTracking();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ public ConnectionBuilder<object> AddQueryConnectionField<TReturn>(
Func<ResolveEfFieldContext<TDbContext, object>, IOrderedQueryable<TReturn>>? resolve = null,
Type? itemGraphType = null,
bool omitQueryArguments = false)
where TReturn : class =>
AddQueryConnectionField<TReturn>(
graph,
name,
resolve == null ? null : context => Task.FromResult(resolve(context)),
itemGraphType,
omitQueryArguments);

public ConnectionBuilder<object> AddQueryConnectionField<TReturn>(
IComplexGraphType graph,
string name,
Func<ResolveEfFieldContext<TDbContext, object>, Task<IOrderedQueryable<TReturn>>>? resolve = null,
Type? itemGraphType = null,
bool omitQueryArguments = false)
where TReturn : class
{
itemGraphType ??= GraphTypeFinder.FindGraphType<TReturn>();
Expand Down Expand Up @@ -54,6 +68,20 @@ public ConnectionBuilder<TSource> AddQueryConnectionField<TSource, TReturn>(
Func<ResolveEfFieldContext<TDbContext, TSource>, IOrderedQueryable<TReturn>>? resolve = null,
Type? itemGraphType = null,
bool omitQueryArguments = false)
where TReturn : class =>
AddQueryConnectionField<TSource, TReturn>(
graph,
name,
resolve == null ? null : context => Task.FromResult(resolve(context)),
itemGraphType,
omitQueryArguments);

public ConnectionBuilder<TSource> AddQueryConnectionField<TSource, TReturn>(
IComplexGraphType graph,
string name,
Func<ResolveEfFieldContext<TDbContext, TSource>, Task<IOrderedQueryable<TReturn>>>? resolve = null,
Type? itemGraphType = null,
bool omitQueryArguments = false)
where TReturn : class
{
itemGraphType ??= GraphTypeFinder.FindGraphType<TReturn>();
Expand Down Expand Up @@ -95,7 +123,7 @@ public ConnectionBuilder<TSource> AddQueryConnectionField<TSource, TReturn>(
ConnectionBuilder<TSource> AddQueryableConnection<TSource, TGraph, TReturn>(
IComplexGraphType graph,
string name,
Func<ResolveEfFieldContext<TDbContext, TSource>, IQueryable<TReturn>>? resolve,
Func<ResolveEfFieldContext<TDbContext, TSource>, Task<IOrderedQueryable<TReturn>>>? resolve,
bool omitQueryArguments)
where TGraph : IGraphType
where TReturn : class
Expand All @@ -109,7 +137,7 @@ ConnectionBuilder<TSource> AddQueryableConnection<TSource, TGraph, TReturn>(
async context =>
{
var efFieldContext = BuildContext(context);
var query = resolve(efFieldContext);
IQueryable<TReturn> query = await resolve(efFieldContext);
if (disableTracking)
{
query = query.AsNoTracking();
Expand Down
Loading