/// <summary> /// Initializes a new instance for the specified graph types and directives, and with the specified type resolver and name converter. /// </summary> /// <param name="types">A list of graph type instances to register in the lookup table.</param> /// <param name="directives">A list of directives to register.</param> /// <param name="resolveType">A delegate which returns an instance of a graph type from its .NET type.</param> /// <param name="schema">A schema for which this instance is created.</param> public static SchemaTypes Create( IEnumerable <IGraphType> types, IEnumerable <DirectiveGraphType> directives, Func <Type, IGraphType> resolveType, ISchema schema) { var lookup = new SchemaTypes(schema); var ctx = new TypeCollectionContext(t => lookup._builtInScalars.TryGetValue(t, out var graphType) ? graphType : resolveType(t), (name, graphType, context) => { if (lookup[name] == null) { lookup.AddType(graphType, context); } }); foreach (var type in types) { lookup.AddType(type, ctx); } // these fields must not have their field names translated by INameConverter; see HandleField lookup.HandleField(null, lookup.SchemaMetaFieldType, ctx, false); lookup.HandleField(null, lookup.TypeMetaFieldType, ctx, false); lookup.HandleField(null, lookup.TypeNameMetaFieldType, ctx, false); foreach (var directive in directives) { if (directive.Arguments?.Count > 0) { foreach (var arg in directive.Arguments.List) { if (arg.ResolvedType != null) { lookup.AddTypeIfNotRegistered(arg.ResolvedType, ctx); arg.ResolvedType = lookup.ConvertTypeReference(directive, arg.ResolvedType); } else { lookup.AddTypeIfNotRegistered(arg.Type, ctx); arg.ResolvedType = lookup.BuildNamedType(arg.Type, ctx.ResolveType); } } } } lookup.ApplyTypeReferences(); Debug.Assert(ctx.InFlightRegisteredTypes.Count == 0); lookup._sealed = true; return(lookup); }
protected virtual void Dispose(bool disposing) { if (disposing) { if (!_disposed) { _services = null; Query = null; Mutation = null; Subscription = null; Filter = null; _additionalInstances?.Clear(); _additionalTypes?.Clear(); Directives.List.Clear(); _converters.Clear(); _allTypes?.Dictionary.Clear(); _allTypes = null; _disposed = true; } } }
private void CreateSchemaTypes() { IEnumerable <IGraphType> GetTypes() { if (_additionalInstances != null) { foreach (var instance in _additionalInstances) { yield return(instance); } } //TODO: According to the specification, Query is a required type. But if you uncomment these lines, then the mass of tests begin to fail, because they do not set Query. // if (Query == null) // throw new InvalidOperationException("Query root type must be provided. See https://graphql.github.io/graphql-spec/June2018/#sec-Schema-Introspection"); if (Query != null) { yield return(Query); } if (Mutation != null) { yield return(Mutation); } if (Subscription != null) { yield return(Subscription); } if (_additionalTypes != null) { foreach (var type in _additionalTypes) { yield return((IGraphType)_services.GetRequiredService(type.GetNamedType())); } } } IEnumerable <ISchemaNodeVisitor> GetVisitors() { if (_visitors != null) { foreach (var visitor in _visitors) { yield return(visitor); } } if (_visitorTypes != null) { foreach (var type in _visitorTypes) { yield return((ISchemaNodeVisitor)_services.GetRequiredService(type)); } } } _allTypes = SchemaTypes.Create( GetTypes(), Directives, type => (IGraphType)_services.GetRequiredService(type), this); // At this point, Initialized will return false, and Initialize will still lock while waiting for initialization to complete. // However, AllTypes and similar properties will return a reference to SchemaTypes without waiting for a lock. _allTypes.ApplyMiddleware(FieldMiddleware); foreach (var visitor in GetVisitors()) { visitor.Run(this); } Validate(); }