public static IReadOnlyCollection <ISchemaError> Validate( IEnumerable <ITypeSystemObject> typeSystemObjects, IReadOnlySchemaOptions options) { if (typeSystemObjects is null) { throw new ArgumentNullException(nameof(typeSystemObjects)); } if (options is null) { throw new ArgumentNullException(nameof(options)); } var types = typeSystemObjects.ToList(); var errors = new List <ISchemaError>(); foreach (ISchemaValidationRule rule in _rules) { rule.Validate(types, options, errors); } return(errors); }
public void Initialize( Func <ISchema> schemaResolver, IReadOnlySchemaOptions options) { if (schemaResolver is null) { throw new ArgumentNullException(nameof(schemaResolver)); } if (options is null) { throw new ArgumentNullException(nameof(options)); } // first we are going to find and initialize all types that belong to our schema. var typeRegistrar = new TypeDiscoverer( _context, _typeRegistry, _typeLookup, _initialTypes, _interceptor); if (typeRegistrar.DiscoverTypes() is { Count : > 0 } errors) { throw new SchemaException(errors); } // next lets tell the type interceptors what types we have initialized. if (_interceptor.TriggerAggregations) { _interceptor.OnTypesInitialized( _typeRegistry.Types.Select(t => t.DiscoveryContext).ToList()); } // before we can start completing type names we need to register the field resolvers. RegisterResolvers(); // now that we have the resolvers sorted and know what types our schema will roughly // consist of we are going to have a look if we can infer interface usage // from .NET classes that implement .NET interfaces. RegisterImplicitInterfaceDependencies(); // with all types (implicit and explicit) known we complete the type names. CompleteNames(schemaResolver); // with the type names all known we can now build pairs to bring together types and // their type extensions. MergeTypeExtensions(); // external resolvers are resolvers that are defined on the schema and are associated // with the types after they have received a name and the extensions are removed. RegisterExternalResolvers(); // with all resolvers in place we compile the once inferred from a C# member. CompileResolvers(); // last we complete the types. Completing types means that we will assign all // the fields resolving all missing parts and then making the types immutable. CompleteTypes(); // if we do not have any errors we will validate the types for spec violations. if (_errors.Count == 0) { _errors.AddRange(SchemaValidator.Validate( _typeRegistry.Types.Select(t => t.Type), options)); } if (_errors.Count > 0) { throw new SchemaException(_errors); } }
private void CompleteResolver( ITypeCompletionContext context, ObjectFieldDefinition definition) { var isIntrospectionField = IsIntrospectionField || DeclaringType.IsIntrospectionType(); IReadOnlyList <FieldMiddlewareDefinition> fieldMiddlewareDefinitions = definition.GetMiddlewareDefinitions(); IReadOnlySchemaOptions options = context.DescriptorContext.Options; var skipMiddleware = options.FieldMiddleware != FieldMiddlewareApplication.AllFields && isIntrospectionField; FieldResolverDelegates resolvers = CompileResolver(context, definition); Resolver = resolvers.Resolver; if (resolvers.PureResolver is not null && IsPureContext()) { PureResolver = FieldMiddlewareCompiler.Compile( definition.GetResultConverters(), resolvers.PureResolver, skipMiddleware); } // by definition fields with pure resolvers are parallel executable. if (!IsParallelExecutable && PureResolver is not null) { IsParallelExecutable = true; } Middleware = FieldMiddlewareCompiler.Compile( context.GlobalComponents, fieldMiddlewareDefinitions, definition.GetResultConverters(), Resolver, skipMiddleware); if (Resolver is null && Middleware is null) { if (_executableDirectives.Length > 0) { Middleware = _ => default; } else { context.ReportError( ObjectField_HasNoResolver( context.Type.Name, Name, context.Type, SyntaxNode)); } } bool IsPureContext() { return(skipMiddleware || context.GlobalComponents.Count == 0 && fieldMiddlewareDefinitions.Count == 0 && _executableDirectives.Length == 0); } }