8000 Fix - as per spec - `_Type.fields` should be `null` for `INPUT_OBJECT` · EntityGraphQL/EntityGraphQL@68ca6de · GitHub
[go: up one dir, main page]

Skip to content

Commit 68ca6de

Browse files
committed
Fix - as per spec - _Type.fields should be null for INPUT_OBJECT
1 parent 9476180 commit 68ca6de

File tree

17 files changed

+220
-99
lines changed

17 files changed

+220
-99
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
- Add `net10.0` as a target
1616
- When using Offset Paging the total items expression is now only executed if the query requests `hasNextPage` or `totalItems` fields
1717
- When using Connection Paging the total count expression is now only executed if the query requests `totalCount` or `pageInfo` fields or the 'last' argument is used
18+
- Added `IField.AsService()` to signal that a field should (or can) be treated as a service field. This means null-checks are differently and they are executed after EF related calls (if `ExecutionOptions.ExecuteServiceFieldsSeparately = true`). Useful for fields that operate with data fully in-memory and do not need a registered service to fetch data or work
1819

1920
## Fixes
2021

2122
- #481 - handle `ResolveAsync` on a top level field
2223
- #488 - Support async fields with `[GraphQLField]`
2324
- #487 - Fix `ResolveAsync` with arguments
25+
- As per spec - `_Type.fields` should be `null` for `INPUT_OBJECT`. Previously the `inputFields` were repeated.
2426

2527
# 6.0.0-beta2
2628

src/EntityGraphQL/Compiler/GqlNodes/BaseGraphQLField.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public abstract class BaseGraphQLField : IGraphQLNode, IFieldKey
6868
/// <summary>
6969
/// True if this field directly has services
7070
/// </summary>
71-
public bool HasServices => Field?.Services.Count > 0;
71+
public bool HasServices => Field?.Services.Count > 0 || Field?.ExecuteAsService == true;
7272

7373
public BaseGraphQLField(
7474
ISchemaProvider schema,
@@ -112,7 +112,7 @@ public BaseGraphQLField(BaseGraphQLField context, Expression? nextFieldContext)
112112
/// <value></value>
113113
public virtual bool HasServicesAtOrBelow(IReadOnlyDictionary<string, GraphQLFragmentStatement> fragments)
114114
{
115-
return Field?.Services.Count > 0 || QueryFields.Any(f => f.HasServicesAtOrBelow(fragments));
115+
return Field?.Services.Count > 0 || Field?.ExecuteAsService == true || QueryFields.Any(f => f.HasServicesAtOrBelow(fragments));
116116
}
117117

118118
/// <summary>

src/EntityGraphQL/Compiler/GqlNodes/ExecutableGraphQLStatement.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public abstract class ExecutableGraphQLStatement : IGraphQLNode
3636
public ParameterExpression? OpVariableParameter { get; }
3737

3838
public IField? Field { get; }
39-
public bool HasServices => Field?.Services.Count > 0;
39+
public bool HasServices => Field?.Services.Count > 0 || Field?.ExecuteAsService == true;
4040

4141
public IReadOnlyDictionary<string, object?> Arguments { get; }
4242

@@ -303,7 +303,8 @@ protected static TContext GetContextToUse<TContext>(TContext? context, IServiceP
303303
var contextParam = node.RootParameter;
304304
bool isSecondExec = false;
305305

306-
if (node.HasServicesAtOrBelow(fragments) && compileContext.ExecutionOptions.ExecuteServiceFieldsSeparately)
306+
bool hasServicesAtOrBelow = node.HasServicesAtOrBelow(fragments);
307+
if (hasServicesAtOrBelow && compileContext.ExecutionOptions.ExecuteServiceFieldsSeparately)
307308
{
308309
// build this first as NodeExpression may modify ConstantParameters
309310
// this is without fields that require services
@@ -360,7 +361,6 @@ protected static TContext GetContextToUse<TContext>(TContext? context, IServiceP
360361
#pragma warning disable IDE0074 // Use compound assignment
361362
if (expression == null)
362363
{
363-
// just do things normally
364364
expression = node.GetNodeExpression(compileContext, serviceProvider, fragments, OpVariableParameter, docVariables, contextParam, false, null, null, contextChanged: false, replacer);
365365
}
366366
#pragma warning restore IDE0074 // Use compound assignment

src/EntityGraphQL/Compiler/GqlNodes/GraphQLDocument.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public GraphQLDocument(ISchemaProvider schema)
5555
public string Name => "Query Request Root";
5656

5757
public IField? Field { get; }
58-
public bool HasServices => Field?.Services.Count > 0;
58+
public bool HasServices => Field?.Services.Count > 0 || Field?.ExecuteAsService == true;
5959

6060
public IReadOnlyDictionary<string, object?> Arguments { get; }
6161

src/EntityGraphQL/Compiler/GqlNodes/GraphQLFragmentStatement.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class GraphQLFragmentStatement : IGraphQLNode
1212
public ParameterExpression? RootParameter { get; }
1313

1414
public IField? Field { get; }
15-
public bool HasServices => Field?.Services.Count > 0;
15+
public bool HasServices => Field?.Services.Count > 0 || Field?.ExecuteAsService == true;
1616

1717
public IReadOnlyDictionary<string, object?> Arguments { get; }
1818

src/EntityGraphQL/Compiler/GqlNodes/GraphQLListSelectionField.cs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -115,28 +115,8 @@ ParameterReplacer replacer
115115

116116
Expression? resultExpression = null;
117117
var isAsync = Field?.IsAsync == true;
118-
if (!withoutServiceFields)
119-
{
120-
bool needsServiceWrap = NeedsServiceWrap(withoutServiceFields);
121-
if (needsServiceWrap || isAsync)
122-
{
123-
// To support a common use case where we are coming from a service result to another service field where the
124-
// service is the Query Context. Which we are assuming is likely an EF context and we don't need the null check
125-
// Use ExecutionOptions.ExecuteServiceFieldsSeparately = false to disable this behavior
126-
var nullCheck = Field!.Services.Any(s => s.Type != Field.Schema.QueryContextType);
127-
(resultExpression, PossibleNextContextTypes) = ExpressionUtil.MakeSelectWithDynamicType(
128-
this,
129-
nextFieldContext!,
130-
listContext,
131-
selectionFields,
132-
nullCheck,
133-
isAsync,
134-
withoutServiceFields
135-
);
136-
}
137-
}
138-
139-
var useNullCheckMethods = contextChanged || !compileContext.ExecutionOptions.ExecuteServiceFieldsSeparately || HasServices;
118+
var useNullCheckMethods =
119+
contextChanged || !compileContext.ExecutionOptions.ExecuteServiceFieldsSeparately || HasServices || Field?.Services.Any(s => s.Type != Field.Schema.QueryContextType) == true;
140120
// have this return both the dynamic types so we can use them next, post-service
141121
if (resultExpression == null)
142122
(resultExpression, PossibleNextContextTypes) = ExpressionUtil.MakeSelectWithDynamicType(

src/EntityGraphQL/Compiler/GqlNodes/GraphQLScalarField.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@ public GraphQLScalarField(
1919
)
2020
: base(schema, field, name, nextFieldContext, rootParameter, parentNode, arguments) { }
2121

22-
public override bool HasServicesAtOrBelow(IReadOnlyDictionary<string, GraphQLFragmentStatement> fragments)
23-
{
24-
return Field?.Services.Count > 0;
25-
}
26-
2722
protected override Expression? GetFieldExpression(
2823
CompileContext compileContext,
2924
IServiceProvider? serviceProvider,

src/EntityGraphQL/Schema/BaseField.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public abstract class BaseField : IField
4848
/// Expressions used to resolve the field in a bulk fashion. This is used for optimising the number of calls to the underlying data source.
4949
/// </summary>
5050
public IBulkFieldResolver? BulkResolver { get; protected set; }
51+
public bool ExecuteAsService { get; private set; }
5152

5253
protected BaseField(ISchemaProvider schema, ISchemaType fromType, string name, string? description, GqlTypeInfo returnType)
5354
{
@@ -248,4 +249,10 @@ public IField IsNullable(bool nullable)
248249

249250
return this;
250251
}
252+
253+
public IField AsService()
254+
{
255+
ExecuteAsService = true;
256+
return this;
257+
}
251258
}

src/EntityGraphQL/Schema/Field.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Linq;
34
using System.Linq.Expressions;
4-
using System.Threading.Tasks;
55
using EntityGraphQL.Compiler;
66
using EntityGraphQL.Compiler.Util;
77
using EntityGraphQL.Extensions;
@@ -272,4 +272,10 @@ protected void SetUpField(LambdaExpression fieldExpression, bool withServices, b
272272

273273
ReturnType = SchemaBuilder.MakeGraphQlType(Schema, false, returnType, null, Name, FromType);
274274
}
275+
276+
public new Field AsService()
277+
{
278+
base.AsService();
279+
return this;
280+
}
275281
}

src/EntityGraphQL/Schema/FieldToResolve.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,35 +106,35 @@ public class FieldToResolveWithArgs<TContext, TParams> : FieldWithContextAndArgs
106106
public FieldToResolveWithArgs(ISchemaProvider schema, ISchemaType fromType, string name, string? description, TParams argTypes)
107107
: base(schema, fromType, name, description, argTypes) { }
108108

109-
public Field Resolve(Expression<Func<TContext, TParams, object>> fieldExpression)
109+
public Field Resolve(Expression<Func<TContext, TParams, object?>> fieldExpression)
110110
{
111111
SetUpField(fieldExpression, true, true, false);
112112
return this;
113113
}
114114

115-
public FieldWithContextAndArgs<TContext, TParams> Resolve<TService>(Expression<Func<TContext, TParams, TService, object>> fieldExpression)
115+
public FieldWithContextAndArgs<TContext, TParams> Resolve<TService>(Expression<Func<TContext, TParams, TService, object?>> fieldExpression)
116116
{
117117
SetUpField(fieldExpression, true, true, false);
118118
Services = [fieldExpression.Parameters[2]];
119119
return this;
120120
}
121121

122-
public FieldWithContextAndArgs<TContext, TParams> Resolve<TService1, TService2>(Expression<Func<TContext, TParams, TService1, TService2, object>> fieldExpression)
122+
public FieldWithContextAndArgs<TContext, TParams> Resolve<TService1, TService2>(Expression<Func<TContext, TParams, TService1, TService2, object?>> fieldExpression)
123123
{
124124
SetUpField(fieldExpression, true, true, false);
125125
Services = [fieldExpression.Parameters[2], fieldExpression.Parameters[3]];
126126
return this;
127127
}
128128

129-
public FieldWithContextAndArgs<TContext, TParams> Resolve<TService1, TService2, TService3>(Expression<Func<TContext, TParams, TService1, TService2, TService3, object>> fieldExpression)
129+
public FieldWithContextAndArgs<TContext, TParams> Resolve<TService1, TService2, TService3>(Expression<Func<TContext, TParams, TService1, TService2, TService3, object?>> fieldExpression)
130130
{
131131
SetUpField(fieldExpression, true, true, false);
132132
Services = [fieldExpression.Parameters[2], fieldExpression.Parameters[3], fieldExpression.Parameters[4]];
133133
return this;
134134
}
135135

136136
public FieldWithContextAndArgs<TContext, TParams> Resolve<TService1, TService2, TService3, TService4>(
137-
Expression<Func<TContext, TParams, TService1, TService2, TService3, TService4, object>> fieldExpression
137+
Expression<Func<TContext, TParams, TService1, TService2, TService3, TService4, object?>> fieldExpression
138138
)
139139
{
140140
SetUpField(fieldExpression, true, true, false);
@@ -143,7 +143,7 @@ Expression<Func<TContext, TParams, TService1, TService2, TService3, TService4, o
143143
}
144144

145145
public FieldWithContextAndArgs<TContext, TParams> Resolve<TService1, TService2, TService3, TService4, TService5>(
146-
Expression<Func<TContext, TParams, TService1, TService2, TService3, TService4, TService5, object>> fieldExpression
146+
Expression<Func<TContext, TParams, TService1, TService2, TService3, TService4, TService5, object?>> fieldExpression
147147
)
148148
{
149149
SetUpField(fieldExpression, true, true, false);

0 commit comments

Comments
 (0)
0