/// <summary> /// Searches current api for true mutation container /// </summary> /// <param name="apiMutation">The mutation</param> /// <param name="apiRoot">The api root</param> /// <returns>The mutation container</returns> private static MergedField FindContainer(ApiMutation apiMutation, MergedApiRoot apiRoot) { var path = apiMutation.Name.Split('.').ToList(); path.RemoveAt(path.Count - 1); MergedObjectType type = apiRoot; MergedField field = null; var queue = new Queue <string>(path); while (queue.Count > 0) { if (type == null) { return(null); } var fieldName = queue.Dequeue(); if (!type.Fields.TryGetValue(fieldName, out field)) { return(null); } type = field.Type as MergedObjectType; } return(field); }
/// <summary> /// Merges schemes from multiple APIs /// </summary> /// <param name="providers"> /// The API providers descriptions /// </param> /// <param name="createdTypes"> /// The list of created types. /// <remarks> /// This is the mutation dictionary and will be filled during creation process /// </remarks> /// </param> /// <returns> /// Merged API /// </returns> private static MergedApiRoot MergeApis(List <ApiProvider> providers, Dictionary <string, MergedType> createdTypes) { var apiRoot = new MergedApiRoot("api"); apiRoot.AddProviders(providers.Select(p => new FieldProvider { Provider = p, FieldType = p.Description })); apiRoot.Category = providers.Count > 1 ? MergedObjectType.EnCategory.MultipleApiType : MergedObjectType.EnCategory.SingleApiType; foreach (var provider in providers) { MergeFields(apiRoot, provider.Description.Fields, provider, new List <string>(), false, createdTypes); foreach (var apiMutation in provider.Description.Mutations) { var mutationName = $"{MergedType.EscapeName(provider.Description.ApiName)}_{MergedType.EscapeName(apiMutation.Name)}"; MergedField mutation = null; switch (apiMutation.Type) { case ApiMutation.EnType.ConnectionCreate: case ApiMutation.EnType.ConnectionUpdate: case ApiMutation.EnType.ConnectionDelete: case ApiMutation.EnType.Connection: mutation = RegisterConnectionMutation(provider, apiMutation, apiRoot, createdTypes); break; case ApiMutation.EnType.Untyped: mutation = RegisterUntypedMutation(provider, apiMutation, apiRoot, createdTypes); break; } if (mutation != null) { apiRoot.Mutations[mutationName] = mutation; } } } var nodeSearcher = new NodeSearcher(apiRoot); apiRoot.NodeSearher = nodeSearcher; return(apiRoot); }
/// <summary> /// Generates the list of used end-types /// </summary> /// <param name="providers">The list of defined api providers</param> /// <param name="types">The list of merged types</param> /// <param name="nodeInterface">The node interface (for relay compliance)</param> /// <param name="allInterfaces">The list of defined type interfaces</param> /// <param name="api">The api root element</param> /// <param name="mutationType">The type containing all mutation methods</param> /// <returns>The list of defined types</returns> private static Dictionary <string, IGraphType> GenerateApiTypes( List <ApiProvider> providers, List <MergedType> types, NodeInterface nodeInterface, Dictionary <string, IGraphType> allInterfaces, MergedApiRoot api, out IObjectGraphType mutationType) { var graphTypes = types.ToDictionary( type => type.ComplexTypeName, type => type.GenerateGraphType(nodeInterface, GetTypeInterfaces(type, providers, allInterfaces))); mutationType = api.GenerateMutationType(); graphTypes[mutationType.Name] = mutationType; graphTypes.Values.OfType <IComplexGraphType>().SelectMany(a => a.Fields).ForEach( f => { var fieldDescription = f.GetMetadata <MergedField>(MergedType.MetaDataTypeKey); if (fieldDescription == null) { return; } SetFieldArguments(f, fieldDescription, graphTypes); f.ResolvedType = GetTypeForField(fieldDescription, graphTypes); if (f.Resolver == null) { f.Resolver = fieldDescription.Resolver ?? fieldDescription.Type; } if (!string.IsNullOrWhiteSpace(fieldDescription.Description)) { f.Description = fieldDescription.Description; } }); return(graphTypes); }
/// <summary> /// Register the mutation /// </summary> /// <param name="provider">The mutation api provider</param> /// <param name="apiMutation">The mutation description</param> /// <param name="apiRoot">The api root</param> /// <param name="typesCreated">The list of created types</param> /// <returns>The mutation as merged field </returns> private static MergedField RegisterConnectionMutation( ApiProvider provider, ApiMutation apiMutation, MergedApiRoot apiRoot, Dictionary <string, MergedType> typesCreated) { var field = FindContainer(apiMutation, apiRoot); var connectionType = field?.Type as MergedConnectionType; if (connectionType == null) { return(null); } var errorDescriptionApiType = provider.Description.Types.FirstOrDefault(t => t.TypeName == "ErrorDescription") as ApiObjectType; MergedType errorDescriptionType = null; if (errorDescriptionApiType != null) { errorDescriptionType = CreateConnectionType(errorDescriptionApiType, provider, typesCreated); } var returnType = new MergedConnectionMutationResultType( connectionType.ElementType, apiRoot, errorDescriptionType, provider); typesCreated[returnType.ComplexTypeName] = returnType; var inputType = new MergedInputType(apiMutation.Name); inputType.AddProvider( new FieldProvider { Provider = provider, FieldType = new ApiObjectType(apiMutation.Name) }); typesCreated[inputType.ComplexTypeName] = inputType; foreach (var apiField in apiMutation.Arguments) { inputType.Fields.Add( apiField.Name, new MergedField( apiField.Name, CreateMergedType(provider, apiField, null, new List <string>(), true, typesCreated), provider, apiMutation, apiMutation.Flags, description: apiField.Description)); } inputType.Fields["clientMutationId"] = new MergedField( "clientMutationId", CreateScalarType(EnScalarType.String, typesCreated), provider, apiMutation); var arguments = new Dictionary <string, MergedField> { { "input", new MergedField( "input", inputType, provider, apiMutation) } }; return(new MergedField( apiMutation.Name, returnType, provider, apiMutation, apiMutation.Flags, arguments, apiMutation.Description)); }
/// <summary> /// Register the mutation /// </summary> /// <param name="provider">The mutation api provider</param> /// <param name="apiMutation">The mutation description</param> /// <param name="apiRoot">The api root</param> /// <param name="typesCreated">The list of created types</param> /// <returns>The mutation as merged field </returns> private static MergedField RegisterUntypedMutation( ApiProvider provider, ApiMutation apiMutation, MergedApiRoot apiRoot, Dictionary <string, MergedType> typesCreated) { var returnType = CreateMergedType(provider, apiMutation, null, new List <string>(), false, typesCreated); var inputType = new MergedInputType(apiMutation.Name); inputType.AddProvider( new FieldProvider { Provider = provider, FieldType = new ApiObjectType(apiMutation.Name) }); typesCreated[inputType.ComplexTypeName] = inputType; foreach (var apiField in apiMutation.Arguments) { inputType.Fields.Add( apiField.Name, new MergedField( apiField.Name, CreateMergedType(provider, apiField, null, new List <string>(), true, typesCreated), provider, apiMutation.Clone(), apiMutation.Flags, description: apiField.Description)); } inputType.Fields["clientMutationId"] = new MergedField( "clientMutationId", CreateScalarType(EnScalarType.String, typesCreated), provider, apiMutation); var arguments = new Dictionary <string, MergedField> { { "input", new MergedField( "input", inputType, provider, apiMutation) } }; var payload = new MergedUntypedMutationResult(returnType, apiRoot, provider, apiMutation); typesCreated[payload.ComplexTypeName] = payload; var untypedMutation = new MergedField( apiMutation.Name, payload, provider, apiMutation, apiMutation.Flags, arguments, apiMutation.Description); return(untypedMutation); }