From 4d6db2e79bfbb6193fd26d9157c25b46d0c700c4 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Mon, 16 May 2022 08:44:08 +0200 Subject: [PATCH] Removed the schema resolver delegate (#5067) --- .../Contracts/ITypeCompletionContext.cs | 2 - .../RegisteredType.CompletionContext.cs | 19 --------- .../Types/Configuration/TypeInitializer.cs | 5 --- .../Properties/TypeResources.Designer.cs | 12 ++++++ .../src/Types/Properties/TypeResources.resx | 6 +++ src/HotChocolate/Core/src/Types/Schema.cs | 2 +- .../Core/src/Types/SchemaBuilder.Setup.cs | 23 +++++------ .../Core/src/Types/SchemaTypes.cs | 39 ++++++++++++------- .../Core/src/Types/SchemaTypesDefinition.cs | 12 +++--- .../Conventions/DescriptorContext.cs | 1 + .../Types/InterfaceType.Initialization.cs | 16 +++----- .../Configuration/TypeInitializerTests.cs | 37 ------------------ 12 files changed, 65 insertions(+), 109 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Configuration/Contracts/ITypeCompletionContext.cs b/src/HotChocolate/Core/src/Types/Configuration/Contracts/ITypeCompletionContext.cs index 97892a9dcd9..7237c0fdb19 100644 --- a/src/HotChocolate/Core/src/Types/Configuration/Contracts/ITypeCompletionContext.cs +++ b/src/HotChocolate/Core/src/Types/Configuration/Contracts/ITypeCompletionContext.cs @@ -93,6 +93,4 @@ public interface ITypeCompletionContext : ITypeSystemObjectContext bool TryGetDirectiveType( IDirectiveReference directiveRef, [NotNullWhen(true)] out DirectiveType? directiveType); - - Func GetSchemaResolver(); } diff --git a/src/HotChocolate/Core/src/Types/Configuration/RegisteredType.CompletionContext.cs b/src/HotChocolate/Core/src/Types/Configuration/RegisteredType.CompletionContext.cs index a08b9f86de5..463738542c9 100644 --- a/src/HotChocolate/Core/src/Types/Configuration/RegisteredType.CompletionContext.cs +++ b/src/HotChocolate/Core/src/Types/Configuration/RegisteredType.CompletionContext.cs @@ -14,7 +14,6 @@ namespace HotChocolate.Configuration; internal sealed partial class RegisteredType : ITypeCompletionContext { private TypeReferenceResolver? _typeReferenceResolver; - private Func? _schemaResolver; public TypeStatus Status { get; set; } = TypeStatus.Initialized; @@ -43,12 +42,10 @@ IReadOnlyList ITypeCompletionContext.GlobalComponents public void PrepareForCompletion( TypeReferenceResolver typeReferenceResolver, - Func schemaResolver, List globalComponents, IsOfTypeFallback? isOfType) { _typeReferenceResolver = typeReferenceResolver; - _schemaResolver = schemaResolver; GlobalComponents = globalComponents; IsOfType = isOfType; } @@ -129,20 +126,4 @@ public ITypeReference GetNamedTypeReference(ITypeReference typeRef) return _typeReferenceResolver.TryGetDirectiveType(directiveRef, out directiveType); } - - /// - public Func GetSchemaResolver() - { - if (_schemaResolver is null) - { - throw new InvalidOperationException(RegisteredType_Completion_NotYetReady); - } - - if (Status == TypeStatus.Initialized) - { - throw new NotSupportedException(); - } - - return _schemaResolver; - } } diff --git a/src/HotChocolate/Core/src/Types/Configuration/TypeInitializer.cs b/src/HotChocolate/Core/src/Types/Configuration/TypeInitializer.cs index b9a0690580d..a9b8019737b 100644 --- a/src/HotChocolate/Core/src/Types/Configuration/TypeInitializer.cs +++ b/src/HotChocolate/Core/src/Types/Configuration/TypeInitializer.cs @@ -24,7 +24,6 @@ internal class TypeInitializer private readonly TypeInterceptor _interceptor; private readonly IsOfTypeFallback? _isOfType; private readonly Func _getTypeKind; - private readonly Func _schemaResolver; private readonly IReadOnlySchemaOptions _options; private readonly TypeRegistry _typeRegistry; private readonly TypeLookup _typeLookup; @@ -40,7 +39,6 @@ internal class TypeInitializer IReadOnlyList initialTypes, IsOfTypeFallback? isOfType, Func getTypeKind, - Func schemaResolver, IReadOnlySchemaOptions options) { _context = descriptorContext ?? @@ -51,8 +49,6 @@ internal class TypeInitializer throw new ArgumentNullException(nameof(initialTypes)); _getTypeKind = getTypeKind ?? throw new ArgumentNullException(nameof(getTypeKind)); - _schemaResolver = schemaResolver ?? - throw new ArgumentNullException(nameof(schemaResolver)); _options = options ?? throw new ArgumentNullException(nameof(options)); @@ -227,7 +223,6 @@ internal bool CompleteTypeName(RegisteredType registeredType) { registeredType.PrepareForCompletion( _typeReferenceResolver, - _schemaResolver, _globalComps, _isOfType); diff --git a/src/HotChocolate/Core/src/Types/Properties/TypeResources.Designer.cs b/src/HotChocolate/Core/src/Types/Properties/TypeResources.Designer.cs index 63812dd8123..d08e98bfb96 100644 --- a/src/HotChocolate/Core/src/Types/Properties/TypeResources.Designer.cs +++ b/src/HotChocolate/Core/src/Types/Properties/TypeResources.Designer.cs @@ -1496,5 +1496,17 @@ internal class TypeResources { return ResourceManager.GetString("ResolverContextExtensions_ContextData_KeyNotFound", resourceCulture); } } + + internal static string SchemaTypes_GetType_DoesNotExist { + get { + return ResourceManager.GetString("SchemaTypes_GetType_DoesNotExist", resourceCulture); + } + } + + internal static string SchemaTypes_DefinitionInvalid { + get { + return ResourceManager.GetString("SchemaTypes_DefinitionInvalid", resourceCulture); + } + } } } diff --git a/src/HotChocolate/Core/src/Types/Properties/TypeResources.resx b/src/HotChocolate/Core/src/Types/Properties/TypeResources.resx index dec74659b2c..5686ea89ad5 100644 --- a/src/HotChocolate/Core/src/Types/Properties/TypeResources.resx +++ b/src/HotChocolate/Core/src/Types/Properties/TypeResources.resx @@ -858,4 +858,10 @@ Type: `{0}` The specified key `{0}` does not exist on `context.ContextData` + + The specified type `{0}` does not exist or is not of the specified kind `{1}`. + + + The schema types definition is in an invalid state. + diff --git a/src/HotChocolate/Core/src/Types/Schema.cs b/src/HotChocolate/Core/src/Types/Schema.cs index 7b9f1be72b7..b78c97b6eec 100644 --- a/src/HotChocolate/Core/src/Types/Schema.cs +++ b/src/HotChocolate/Core/src/Types/Schema.cs @@ -122,7 +122,7 @@ public IReadOnlyList GetPossibleTypes(INamedType abstractType) throw new ArgumentNullException(nameof(abstractType)); } - if (_types.TryGetPossibleTypes(abstractType.Name, out IReadOnlyList types)) + if (_types.TryGetPossibleTypes(abstractType.Name, out IReadOnlyList? types)) { return types; } diff --git a/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs b/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs index 47db3993d25..953deb3bfa7 100644 --- a/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs +++ b/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs @@ -65,8 +65,7 @@ public static Schema Create(SchemaBuilder builder) IReadOnlyList typeReferences = CreateTypeReferences(builder, context); - TypeRegistry typeRegistry = - InitializeTypes(builder, context, typeReferences, lazySchema); + TypeRegistry typeRegistry = InitializeTypes(builder, context, typeReferences); return CompleteSchema(builder, context, lazySchema, typeRegistry); } @@ -127,7 +126,7 @@ public static Schema Create(SchemaBuilder builder) { var types = new List(); var documents = new List(); - context.ContextData[WellKnownContextData.SchemaDocuments] = documents; + context.ContextData[WellKnownContextData.SchemaDocuments] = documents; foreach (LoadSchemaDocument fetchSchema in builder._documents) { @@ -194,12 +193,11 @@ public static Schema Create(SchemaBuilder builder) private static TypeRegistry InitializeTypes( SchemaBuilder builder, IDescriptorContext context, - IReadOnlyList types, - LazySchema lazySchema) + IReadOnlyList types) { var typeRegistry = new TypeRegistry(context.TypeInterceptor); TypeInitializer initializer = - CreateTypeInitializer(builder, context, types, typeRegistry, lazySchema); + CreateTypeInitializer(builder, context, types, typeRegistry); initializer.Initialize(); return typeRegistry; } @@ -208,8 +206,7 @@ public static Schema Create(SchemaBuilder builder) SchemaBuilder builder, IDescriptorContext context, IReadOnlyList typeReferences, - TypeRegistry typeRegistry, - LazySchema lazySchema) + TypeRegistry typeRegistry) { var operations = builder._operations.ToDictionary( @@ -222,7 +219,6 @@ public static Schema Create(SchemaBuilder builder) typeReferences, builder._isOfType, type => GetOperationKind(type, context.TypeInspector, operations), - () => lazySchema.Schema, builder._options); foreach (FieldMiddleware component in builder._globalComponents) @@ -256,7 +252,7 @@ public static Schema Create(SchemaBuilder builder) { var serviceFactory = new ServiceFactory { Services = services }; - foreach (object interceptorOrType in registered) + foreach (var interceptorOrType in registered) { if (interceptorOrType is Type type) { @@ -398,10 +394,9 @@ public static Schema Create(SchemaBuilder builder) OperationType.Subscription, builder._options.SubscriptionTypeName); - Dictionary operations = - builder._operations.ToDictionary( - t => t.Key, - t => t.Value(context.TypeInspector)); + var operations = builder._operations.ToDictionary( + static t => t.Key, + t => t.Value(context.TypeInspector)); ResolveOperations(definition, operations, typeRegistry); diff --git a/src/HotChocolate/Core/src/Types/SchemaTypes.cs b/src/HotChocolate/Core/src/Types/SchemaTypes.cs index 0a56ccd5098..cdd89dea636 100644 --- a/src/HotChocolate/Core/src/Types/SchemaTypes.cs +++ b/src/HotChocolate/Core/src/Types/SchemaTypes.cs @@ -1,7 +1,11 @@ +#nullable enable + using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using HotChocolate.Types; +using static HotChocolate.Properties.TypeResources; namespace HotChocolate; @@ -17,38 +21,43 @@ public SchemaTypes(SchemaTypesDefinition definition) throw new ArgumentNullException(nameof(definition)); } + if (definition.Types is null || definition.DirectiveTypes is null) + { + throw new ArgumentException( + SchemaTypes_DefinitionInvalid, + nameof(definition)); + } + _types = definition.Types.ToDictionary(t => t.Name); _possibleTypes = CreatePossibleTypeLookup(definition.Types); - QueryType = definition.QueryType; + QueryType = definition.QueryType!; MutationType = definition.MutationType; SubscriptionType = definition.SubscriptionType; } public ObjectType QueryType { get; } - public ObjectType MutationType { get; } + public ObjectType? MutationType { get; } - public ObjectType SubscriptionType { get; } + public ObjectType? SubscriptionType { get; } public T GetType(NameString typeName) where T : IType { - if (_types.TryGetValue(typeName, out INamedType namedType) + if (_types.TryGetValue(typeName, out INamedType? namedType) && namedType is T type) { return type; } - // TODO : resource throw new ArgumentException( - $"The specified type `{typeName}` does not exist or " + - $"is not of the specified kind `{typeof(T).Name}`.", + string.Format(SchemaTypes_GetType_DoesNotExist, typeName, typeof(T).Name), nameof(typeName)); } - public bool TryGetType(NameString typeName, out T type) + public bool TryGetType(NameString typeName, [NotNullWhen(true)] out T? type) where T : IType { - if (_types.TryGetValue(typeName, out INamedType namedType) + if (_types.TryGetValue(typeName, out INamedType? namedType) && namedType is T t) { type = t; @@ -64,9 +73,9 @@ public IReadOnlyCollection GetTypes() return _types.Values; } - public bool TryGetClrType(NameString typeName, out Type clrType) + public bool TryGetClrType(NameString typeName, [NotNullWhen(true)] out Type? clrType) { - if (_types.TryGetValue(typeName, out INamedType type) + if (_types.TryGetValue(typeName, out INamedType? type) && type is IHasRuntimeType ct && ct.RuntimeType != typeof(object)) { @@ -80,9 +89,9 @@ public bool TryGetClrType(NameString typeName, out Type clrType) public bool TryGetPossibleTypes( string abstractTypeName, - out IReadOnlyList types) + [NotNullWhen(true)] out IReadOnlyList? types) { - if (_possibleTypes.TryGetValue(abstractTypeName, out List pt)) + if (_possibleTypes.TryGetValue(abstractTypeName, out List? pt)) { types = pt; return true; @@ -103,7 +112,7 @@ public bool TryGetClrType(NameString typeName, out Type clrType) foreach (InterfaceType interfaceType in objectType.Implements) { - if (!possibleTypes.TryGetValue(interfaceType.Name, out List pt)) + if (!possibleTypes.TryGetValue(interfaceType.Name, out List? pt)) { pt = new List(); possibleTypes[interfaceType.Name] = pt; @@ -118,7 +127,7 @@ public bool TryGetClrType(NameString typeName, out Type clrType) foreach (ObjectType objectType in unionType.Types.Values) { if (!possibleTypes.TryGetValue( - unionType.Name, out List pt)) + unionType.Name, out List? pt)) { pt = new List(); possibleTypes[unionType.Name] = pt; diff --git a/src/HotChocolate/Core/src/Types/SchemaTypesDefinition.cs b/src/HotChocolate/Core/src/Types/SchemaTypesDefinition.cs index 873de864d76..6e6242bf445 100644 --- a/src/HotChocolate/Core/src/Types/SchemaTypesDefinition.cs +++ b/src/HotChocolate/Core/src/Types/SchemaTypesDefinition.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.Collections.Generic; using HotChocolate.Types; @@ -5,10 +7,10 @@ namespace HotChocolate; internal sealed class SchemaTypesDefinition { - public ObjectType QueryType { get; set; } - public ObjectType MutationType { get; set; } - public ObjectType SubscriptionType { get; set; } + public ObjectType? QueryType { get; set; } + public ObjectType? MutationType { get; set; } + public ObjectType? SubscriptionType { get; set; } - public IReadOnlyList Types { get; set; } - public IReadOnlyList DirectiveTypes { get; set; } + public IReadOnlyList? Types { get; set; } + public IReadOnlyList? DirectiveTypes { get; set; } } diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DescriptorContext.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DescriptorContext.cs index 4edae494007..11e12b6d684 100644 --- a/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DescriptorContext.cs +++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DescriptorContext.cs @@ -62,6 +62,7 @@ public sealed class DescriptorContext : IDescriptorContext void OnSchemaOnCompleted(object? sender, EventArgs args) { SchemaCompleted?.Invoke(this, new SchemaCompletedEventArgs(schema.Schema)); + SchemaCompleted = null; } } diff --git a/src/HotChocolate/Core/src/Types/Types/InterfaceType.Initialization.cs b/src/HotChocolate/Core/src/Types/Types/InterfaceType.Initialization.cs index cd6d630ea2f..1967032f638 100644 --- a/src/HotChocolate/Core/src/Types/Types/InterfaceType.Initialization.cs +++ b/src/HotChocolate/Core/src/Types/Types/InterfaceType.Initialization.cs @@ -16,6 +16,7 @@ public partial class InterfaceType private InterfaceType[] _implements = Array.Empty(); private Action? _configure; private ResolveAbstractType? _resolveAbstractType; + private ISchema _schema = default!; protected override InterfaceTypeDefinition CreateDefinition( ITypeDiscoveryContext context) @@ -56,8 +57,9 @@ public partial class InterfaceType SyntaxNode = definition.SyntaxNode; Fields = OnCompleteFields(context, definition); + context.DescriptorContext.SchemaCompleted += (_, args) => _schema = args.Schema; - CompleteAbstractTypeResolver(context, definition.ResolveAbstractType); + CompleteAbstractTypeResolver(definition.ResolveAbstractType); _implements = CompleteInterfaces(context, definition.GetInterfaces(), this); } @@ -70,24 +72,16 @@ static InterfaceField CreateField(InterfaceFieldDefinition fieldDef, int index) => new(fieldDef, index); } - private void CompleteAbstractTypeResolver( - ITypeCompletionContext context, - ResolveAbstractType? resolveAbstractType) + private void CompleteAbstractTypeResolver(ResolveAbstractType? resolveAbstractType) { if (resolveAbstractType is null) { - Func schemaResolver = context.GetSchemaResolver(); - // if there is no custom type resolver we will use this default // abstract type resolver. IReadOnlyCollection? types = null; _resolveAbstractType = (c, r) => { - if (types is null) - { - ISchema schema = schemaResolver.Invoke(); - types = schema.GetPossibleTypes(this); - } + types ??= _schema.GetPossibleTypes(this); foreach (ObjectType type in types) { diff --git a/src/HotChocolate/Core/test/Types.Tests/Configuration/TypeInitializerTests.cs b/src/HotChocolate/Core/test/Types.Tests/Configuration/TypeInitializerTests.cs index 796417ae2c7..bf46a572a48 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Configuration/TypeInitializerTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Configuration/TypeInitializerTests.cs @@ -30,7 +30,6 @@ public void Register_SchemaType_ClrTypeExists() }, null, t => t is FooType ? RootTypeKind.Query : RootTypeKind.None, - () => null, new SchemaOptions()); // act @@ -86,7 +85,6 @@ public void Register_ClrType_InferSchemaTypes() _ => RootTypeKind.None }; }, - () => null, new SchemaOptions()); // act @@ -116,40 +114,6 @@ public void Register_ClrType_InferSchemaTypes() new { fooType, barType }.MatchSnapshot(); } - [Fact] - public void Initializer_SchemaResolver_Is_Null() - { - // arrange - var typeInterceptor = new AggregateTypeInterceptor(); - typeInterceptor.SetInterceptors(new[] { new IntrospectionTypeInterceptor() }); - IDescriptorContext context = DescriptorContext.Create( - typeInterceptor: typeInterceptor); - var typeRegistry = new TypeRegistry(context.TypeInterceptor); - - // act - void Action() => new TypeInitializer( - context, - typeRegistry, - new List - { - context.TypeInspector.GetTypeRef(typeof(Foo), TypeContext.Output) - }, - null!, - t => - { - return t switch - { - ObjectType => RootTypeKind.Query, - _ => RootTypeKind.None - }; - }, - null!, - new SchemaOptions()); - - // assert - Assert.Throws(Action); - } - [Fact] public void Initializer_SchemaOptions_Are_Null() { @@ -177,7 +141,6 @@ public void Initializer_SchemaOptions_Are_Null() _ => RootTypeKind.None }; }, - () => null, null!); // assert