Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
        /// <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);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Sets the field arguments from the field metadata
        /// </summary>
        /// <param name="field">The field</param>
        /// <param name="fieldDescription">The field description</param>
        /// <param name="graphTypes">The list of end-types</param>
        private static void SetFieldArguments(
            FieldType field,
            MergedField fieldDescription,
            Dictionary <string, IGraphType> graphTypes)
        {
            var typeArguments  = fieldDescription.Type.GenerateArguments(graphTypes) ?? new QueryArguments();
            var fieldArguments =
                fieldDescription.Arguments.Select(
                    p =>
                    new QueryArgument(typeof(VirtualInputGraphType))
            {
                Name         = p.Key,
                ResolvedType =
                    GetTypeForField(p.Value, graphTypes),
                Description = p.Value.Description
            });

            var resultingArguments = typeArguments.Union(fieldArguments).ToList();

            if (resultingArguments.Any())
            {
                field.Arguments = new QueryArguments(resultingArguments);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Insert new fields from new provider into current type
        /// </summary>
        /// <param name="parentType">
        /// Field to update
        /// </param>
        /// <param name="apiFields">
        /// The list of subfields from api
        /// </param>
        /// <param name="provider">
        /// The api provider
        /// </param>
        /// <param name="path">
        /// The types names path to avoid circular references.
        /// </param>
        /// <param name="createAsInput">A value indicating that an input type is assembled</param>
        /// <param name="typesCreated">The list of previously created types</param>
        private static void MergeFields(
            MergedObjectType parentType,
            IEnumerable <ApiField> apiFields,
            ApiProvider provider,
            ICollection <string> path,
            bool createAsInput,
            Dictionary <string, MergedType> typesCreated)
        {
            var fields = createAsInput
                             ? apiFields.Where(
                f =>
                f.Flags.HasFlag(EnFieldFlags.CanBeUsedInInput) &&
                f.Arguments.All(a => a.Flags.HasFlag(EnFieldFlags.IsTypeArgument)))
                             : apiFields.Where(f => f.Flags.HasFlag(EnFieldFlags.Queryable));

            foreach (var apiField in fields)
            {
                MergedField complexField;
                if (parentType.Fields.TryGetValue(apiField.Name, out complexField))
                {
                    if (apiField.ScalarType != EnScalarType.None || createAsInput ||
                        apiField.Flags.HasFlag(EnFieldFlags.IsConnection) ||
                        apiField.Flags.HasFlag(EnFieldFlags.IsArray) || !(complexField.Type is MergedObjectType) ||
                        complexField.Arguments.Any() || apiField.Arguments.Any())
                    {
                        // todo: write merge error
                        continue;
                    }
                }

                var flags = apiField.Flags;

                if (createAsInput && flags.HasFlag(EnFieldFlags.IsConnection))
                {
                    flags &= ~EnFieldFlags.IsConnection;
                    flags |= EnFieldFlags.IsArray;
                }

                var cloneField = apiField.Clone();
                cloneField.Flags = flags;

                var fieldType = CreateMergedType(provider, cloneField, complexField, path, createAsInput, typesCreated);

                if (fieldType == null)
                {
                    continue;
                }

                var fieldArguments = new Dictionary <string, MergedField>();

                if (!createAsInput)
                {
                    foreach (var argument in apiField.Arguments)
                    {
                        var fieldArgumentType = CreateMergedType(provider, argument, null, path, true, typesCreated);
                        fieldArguments[argument.Name] = new MergedField(
                            argument.Name,
                            fieldArgumentType,
                            provider,
                            apiField,
                            argument.Flags,
                            description: argument.Description);
                    }
                }

                var description = string.Join(
                    "\n",
                    new[] { complexField?.Description, apiField.Description }.Where(s => !string.IsNullOrWhiteSpace(s)));

                var field = new MergedField(
                    apiField.Name,
                    fieldType,
                    provider,
                    cloneField,
                    flags,
                    fieldArguments,
                    string.IsNullOrWhiteSpace(description) ? null : description);
                if (complexField != null)
                {
                    foreach (var complexFieldProvider in complexField.Providers)
                    {
                        field.AddProvider(
                            complexFieldProvider,
                            complexField.OriginalFields[complexFieldProvider.Description.ApiName]);
                    }
                }

                parentType.Fields[apiField.Name] = field;
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Creates field from api description
        /// </summary>
        /// <param name="provider">The api provider</param>
        /// <param name="apiField">The api field description</param>
        /// <param name="complexField">The same field merged from previous api descriptions</param>
        /// <param name="path">The list of processed types</param>
        /// <param name="createAsInput">A value indicating that an input type is assembled</param>
        /// <param name="typesCreated">The list of already created types</param>
        /// <returns>The field description</returns>
        private static MergedType CreateMergedType(
            ApiProvider provider,
            ApiField apiField,
            MergedField complexField,
            ICollection <string> path,
            bool createAsInput,
            Dictionary <string, MergedType> typesCreated)
        {
            MergedType createdType;

            if (apiField.ScalarType != EnScalarType.None)
            {
                return(CreateScalarType(apiField.ScalarType, typesCreated));
            }

            var apiType = provider.Description.Types.FirstOrDefault(t => t.TypeName == apiField.TypeName);

            if (apiType == null)
            {
                throw new Exception("type was not found");
            }

            var apiEnumType = apiType as ApiEnumType;

            if (apiEnumType != null)
            {
                return(CreateEnumType(apiEnumType, provider, typesCreated));
            }

            var apiObjectType = (ApiObjectType)apiType;

            if (apiField.Flags.HasFlag(EnFieldFlags.IsConnection))
            {
                var typedArgumentNames =
                    apiField.Arguments.Where(a => a.Flags.HasFlag(EnFieldFlags.IsTypeArgument))
                    .Select(f => f.Name)
                    .ToList();
                return(CreateConnectionType(apiObjectType, provider, typesCreated, typedArgumentNames));
            }

            var objectType = (complexField?.Type as MergedObjectType)?.Clone()
                             ?? (createAsInput
                                     ? new MergedInputType($"{provider.Description.ApiName}_{apiField.TypeName}")
                                     : new MergedObjectType($"{provider.Description.ApiName}_{apiField.TypeName}"));

            objectType.AddProvider(new FieldProvider {
                FieldType = apiObjectType, Provider = provider
            });
            if (complexField != null)
            {
                objectType.Category = MergedObjectType.EnCategory.MultipleApiType;
            }

            if (typesCreated.TryGetValue(objectType.ComplexTypeName, out createdType))
            {
                return(createdType);
            }

            typesCreated[objectType.ComplexTypeName] = objectType;

            MergeFields(
                objectType,
                apiObjectType.Fields,
                provider,
                path.Union(new[] { apiObjectType.TypeName }).ToList(),
                createAsInput,
                typesCreated);

            objectType.Initialize();
            return(objectType);
        }
Ejemplo n.º 6
0
 /// <summary>
 /// Gets the end-type for field
 /// </summary>
 /// <param name="field">The field description</param>
 /// <param name="graphTypes">The list of defined types</param>
 /// <returns>The field resolved type</returns>
 private static IGraphType GetTypeForField(MergedField field, Dictionary <string, IGraphType> graphTypes)
 {
     return(field.Flags.HasFlag(EnFieldFlags.IsArray)
                ? new ListGraphType(graphTypes[field.Type.ComplexTypeName])
                : graphTypes[field.Type.ComplexTypeName]);
 }
Ejemplo n.º 7
0
        /// <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);
        }