private static CachedField GetFieldsAndFragmentNames(
            ValidationContext context,
            Dictionary <SelectionSet, CachedField> cachedFieldsAndFragmentNames,
            IGraphType?parentType,
            SelectionSet selectionSet)
        {
            cachedFieldsAndFragmentNames.TryGetValue(selectionSet, out CachedField cached);

            if (cached == null)
            {
                var nodeAndDef    = new Dictionary <string, List <FieldDefPair> >();
                var fragmentNames = new HashSet <string>();

                CollectFieldsAndFragmentNames(
                    context,
                    parentType,
                    selectionSet,
                    nodeAndDef,
                    fragmentNames);

                cached = new CachedField {
                    NodeAndDef = nodeAndDef, Names = fragmentNames.ToList()
                };
                cachedFieldsAndFragmentNames.Add(selectionSet, cached);
            }
            return(cached);
        }
Пример #2
0
 /// <summary>
 /// Initializes an instance of <see cref="ExecutionNode"/> with the specified values
 /// </summary>
 /// <param name="parent">The parent node, or <see langword="null"/> if this is the root node</param>
 /// <param name="graphType">The graph type of this node, unwrapped if it is a <see cref="NonNullGraphType"/>. Array nodes will be a <see cref="ListGraphType"/> instance.</param>
 /// <param name="field">The AST field of this node</param>
 /// <param name="fieldDefinition">The graph's field type of this node</param>
 /// <param name="indexInParentNode">For child array item nodes of a <see cref="ListGraphType"/>, the index of this array item within the field; otherwise, <see langword="null"/></param>
 protected ExecutionNode(ExecutionNode?parent, IGraphType?graphType, Field?field, FieldType?fieldDefinition, int?indexInParentNode)
 {
     Parent            = parent;
     GraphType         = graphType;
     Field             = field;
     FieldDefinition   = fieldDefinition;
     IndexInParentNode = indexInParentNode;
 }
Пример #3
0
 internal static (IGraphType?resolvedType, Type?type) GetNamedTypes(this IGraphType?type)
 {
     return(type switch
     {
         NonNullGraphType nonNull => nonNull.ResolvedType != null?GetNamedTypes(nonNull.ResolvedType) : (null, GetNamedType(nonNull.Type !)),
             ListGraphType list => list.ResolvedType != null?GetNamedTypes(list.ResolvedType) : (null, GetNamedType(list.Type !)),
                 _ => (type, null)
     });
        private static void CollectFieldsAndFragmentNames(
            ValidationContext context,
            IGraphType?parentType,
            SelectionSet selectionSet,
            Dictionary <string, List <FieldDefPair> > nodeAndDefs,
            HashSet <string> fragments)
        {
            for (int i = 0; i < selectionSet.Selections.Count; i++)
            {
                var selection = selectionSet.Selections[i];

                if (selection is Field field)
                {
                    var       fieldName = field.Name;
                    FieldType?fieldDef  = null;
                    if (isObjectType(parentType) || isInterfaceType(parentType))
                    {
                        fieldDef = (parentType as IComplexGraphType) !.GetField(fieldName);
                    }

                    var responseName = !string.IsNullOrWhiteSpace(field.Alias) ? field.Alias ! : fieldName;

                    if (!nodeAndDefs.ContainsKey(responseName))
                    {
                        nodeAndDefs[responseName] = new List <FieldDefPair>();
                    }

                    nodeAndDefs[responseName].Add(new FieldDefPair
                    {
                        ParentType = parentType,
                        Field      = selection,
                        FieldDef   = fieldDef
                    });
                }
                else if (selection is FragmentSpread fragmentSpread)
                {
                    fragments.Add(fragmentSpread.Name);
                }
                else if (selection is InlineFragment inlineFragment)
                {
                    var typeCondition      = inlineFragment.Type;
                    var inlineFragmentType =
                        typeCondition != null
                            ? typeCondition.GraphTypeFromType(context.Schema)
                            : parentType;

                    CollectFieldsAndFragmentNames(
                        context,
                        inlineFragmentType,
                        inlineFragment.SelectionSet,
                        nodeAndDefs,
                        fragments);
                }
            }
        }
Пример #5
0
        /// <summary>
        /// Returns the parent graph type of this node.
        /// </summary>
        public IObjectGraphType?GetParentType(ISchema schema)
        {
            IGraphType?parentType = Parent?.GraphType;

            if (parentType is IObjectGraphType objectType)
            {
                return(objectType);
            }

            if (parentType is IAbstractGraphType abstractType)
            {
                return(abstractType.GetObjectType(Parent !.Result !, schema));
            }

            return(null);
        }
Пример #6
0
        private static void Field(IGraphType?type, Field field, ValidationContext context)
        {
            if (type == null)
            {
                return;
            }

            if (type.IsLeafType())
            {
                if (field.SelectionSet != null && field.SelectionSet.Selections.Count > 0)
                {
                    context.ReportError(new ScalarLeafsError(context, field.SelectionSet, field, type));
                }
            }
            else if (field.SelectionSet == null || field.SelectionSet.Selections.Count == 0)
            {
                context.ReportError(new ScalarLeafsError(context, field, type));
            }
        }
        public static object ToObject(this IDictionary <string, object?> source, Type type, IGraphType?mappedType = null)
        {
            // Given Field(x => x.FName).Name("FirstName") and key == "FirstName" returns "FName"
            string GetPropertyName(string key, out FieldType?field)
            {
                var complexType = mappedType?.GetNamedType() as IComplexGraphType;

                // type may not contain mapping information
                field = complexType?.GetField(key);
                return(field?.GetMetadata(ComplexGraphType <object> .ORIGINAL_EXPRESSION_PROPERTY_NAME, key) ?? key);
            }

            // Returns values (from source or defaults) that match constructor signature + used keys from source
            (List <object>?, List <string>?) GetValuesAndUsedKeys(ParameterInfo[] parameters)
            {
                // parameterless constructors are the most common use case
                if (parameters.Length == 0)
                {
                    return(_emptyValues, null);
                }

                // otherwise we have to iterate over the parameters - worse performance but this is rather rare case
                List <object>?values = null;
                List <string>?keys   = null;

                if (parameters.All(p =>
                {
                    // Source values take precedence
                    if (source.Any(keyValue =>
                    {
                        bool matched = string.Equals(GetPropertyName(keyValue.Key, out var _), p.Name, StringComparison.InvariantCultureIgnoreCase);
                        if (matched)
                        {
                            (values ??= new List <object>()).Add(keyValue.Value);
                            (keys ??= new List <string>()).Add(keyValue.Key);
                        }
                        return(matched);
                    }))
                    {
                        return(true);
                    }

                    // Then check for default values if any
                    if (p.HasDefaultValue)
                    {
                        (values ??= new List <object>()).Add(p.DefaultValue);
                        return(true);
                    }

                    return(false);
                }))
                {
                    return(values, keys);
                }

                return(null, null);
            }

            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            // force sourceType to be IDictionary<string, object>
            if (ValueConverter.TryConvertTo(source, type, out object?result, typeof(IDictionary <string, object>)))
            {
                return(result !);
            }

            // attempt to use the most specific constructor sorting in decreasing order of parameters number
            var ctorCandidates = _types.GetOrAdd(type, t => t.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).OrderByDescending(ctor => ctor.GetParameters().Length).ToArray());

            ConstructorInfo?targetCtor = null;

            ParameterInfo[]? ctorParameters = null;
            List <object>?values   = null;
            List <string>?usedKeys = null;

            foreach (var ctor in ctorCandidates)
            {
                var parameters = ctor.GetParameters();
                (values, usedKeys) = GetValuesAndUsedKeys(parameters);
                if (values != null)
                {
                    targetCtor     = ctor;
                    ctorParameters = parameters;
                    break;
                }
            }

            if (targetCtor == null || ctorParameters == null || values == null)
            {
                throw new ArgumentException($"Type '{type}' does not contain a constructor that could be used for current input arguments.", nameof(type));
            }

            object?[] ctorArguments = ctorParameters.Length == 0 ? Array.Empty <object>() : new object[ctorParameters.Length];

            for (int i = 0; i < ctorParameters.Length; ++i)
            {
                object?arg = GetPropertyValue(values[i], ctorParameters[i].ParameterType);
                ctorArguments[i] = arg;
            }

            object obj;

            try
            {
                obj = targetCtor.Invoke(ctorArguments);
            }
            catch (TargetInvocationException ex)
            {
                ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
                return(""); // never executed, necessary only for intellisense
            }

            foreach (var item in source)
            {
                // these parameters have already been used in the constructor, no need to set property
                if (usedKeys?.Any(k => k == item.Key) == true)
                {
                    continue;
                }

                string       propertyName = GetPropertyName(item.Key, out var field);
                PropertyInfo?propertyInfo = null;

                try
                {
                    propertyInfo = type.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                }
                catch (AmbiguousMatchException)
                {
                    propertyInfo = type.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
                }

                if (propertyInfo != null && propertyInfo.CanWrite)
                {
                    object?value = GetPropertyValue(item.Value, propertyInfo.PropertyType, field?.ResolvedType);
                    propertyInfo.SetValue(obj, value, null); //issue: this works even if propertyInfo is ValueType and value is null
                }
            }

            return(obj);
        }
        public static object?GetPropertyValue(this object?propertyValue, Type fieldType, IGraphType?mappedType = null)
        {
            // Short-circuit conversion if the property value already of the right type
            if (propertyValue == null || fieldType == typeof(object) || fieldType.IsInstanceOfType(propertyValue))
            {
                return(propertyValue);
            }

            if (ValueConverter.TryConvertTo(propertyValue, fieldType, out object?result))
            {
                return(result);
            }

            var enumerableInterface = fieldType.Name == "IEnumerable`1"
              ? fieldType
              : fieldType.GetInterface("IEnumerable`1");

            if (fieldType != typeof(string) && enumerableInterface != null)
            {
                IList newCollection;
                var   elementType              = enumerableInterface.GetGenericArguments()[0];
                var   underlyingType           = Nullable.GetUnderlyingType(elementType) ?? elementType;
                var   fieldTypeImplementsIList = fieldType.GetInterface("IList") != null;

                var propertyValueAsIList = propertyValue as IList;

                // Custom container
                if (fieldTypeImplementsIList && !fieldType.IsArray)
                {
                    newCollection = (IList)Activator.CreateInstance(fieldType);
                }
                // Array of known size is created immediately
                else if (fieldType.IsArray && propertyValueAsIList != null)
                {
                    newCollection = Array.CreateInstance(elementType, propertyValueAsIList.Count);
                }
                // List<T>
                else
                {
                    var genericListType = typeof(List <>).MakeGenericType(elementType);
                    newCollection = (IList)Activator.CreateInstance(genericListType);
                }

                if (!(propertyValue is IEnumerable valueList))
                {
                    return(newCollection);
                }

                // Array of known size is populated in-place
                if (fieldType.IsArray && propertyValueAsIList != null)
                {
                    for (int i = 0; i < propertyValueAsIList.Count; ++i)
                    {
                        var listItem = propertyValueAsIList[i];
                        newCollection[i] = listItem == null ? null : GetPropertyValue(listItem, underlyingType, mappedType);
                    }
                }
                // Array of unknown size is created only after populating list
                else
                {
                    foreach (var listItem in valueList)
                    {
                        newCollection.Add(listItem == null ? null : GetPropertyValue(listItem, underlyingType, mappedType));
                    }

                    if (fieldType.IsArray)
                    {
                        newCollection = ((dynamic)newCollection).ToArray();
                    }
                }

                return(newCollection);
            }

            var value = propertyValue;

            var nullableFieldType = Nullable.GetUnderlyingType(fieldType);

            // if this is a nullable type and the value is null, return null
            if (nullableFieldType != null && value == null)
            {
                return(null);
            }

            if (nullableFieldType != null)
            {
                fieldType = nullableFieldType;
            }

            if (propertyValue is IDictionary <string, object?> objects)
            {
                return(ToObject(objects, fieldType, mappedType));
            }

            if (fieldType.IsEnum)
            {
                if (value == null)
                {
                    var enumNames = Enum.GetNames(fieldType);
                    value = enumNames[0];
                }

                if (!IsDefinedEnumValue(fieldType, value))
                {
                    throw new InvalidOperationException($"Unknown value '{value}' for enum '{fieldType.Name}'.");
                }

                string str = value.ToString();
                value = Enum.Parse(fieldType, str, true);
            }

            return(ValueConverter.ConvertTo(value, fieldType));
        }
Пример #9
0
 public ObjectExecutionNode(ExecutionNode?parent, IGraphType?graphType, Field?field, FieldType?fieldDefinition, int?indexInParentNode)
     : base(parent, graphType, field, fieldDefinition, indexInParentNode)
 {
 }
Пример #10
0
 /// <summary>
 /// Initializes a new instance for the specified inner graph type.
 /// </summary>
 public NonNullGraphType(IGraphType?type)
 {
     ResolvedType = type;
 }
 private static bool isObjectType(IGraphType?parentType)
 {
     return(parentType is IObjectGraphType);
 }
 private static bool isInterfaceType(IGraphType?parentType)
 {
     return(parentType is IInterfaceGraphType);
 }
 public int Compare(IGraphType?x, IGraphType?y) => (x?.Name ?? "").CompareTo(y?.Name ?? "");
        private static List <Conflict> FindConflictsWithinSelectionSet(
            ValidationContext context,
            Dictionary <SelectionSet, CachedField> cachedFieldsAndFragmentNames,
            PairSet comparedFragmentPairs,
            IGraphType?parentType,
            SelectionSet selectionSet)
        {
            var conflicts = new List <Conflict>();

            CachedField cachedField = GetFieldsAndFragmentNames(
                context,
                cachedFieldsAndFragmentNames,
                parentType,
                selectionSet);

            var fieldMap      = cachedField.NodeAndDef;
            var fragmentNames = cachedField.Names;

            CollectConflictsWithin(
                context,
                conflicts,
                cachedFieldsAndFragmentNames,
                comparedFragmentPairs,
                fieldMap);

            if (fragmentNames.Count != 0)
            {
                // (B) Then collect conflicts between these fields and those represented by
                // each spread fragment name found.
                var comparedFragments = new HashSet <string>();
                for (int i = 0; i < fragmentNames.Count; i++)
                {
                    CollectConflictsBetweenFieldsAndFragment(
                        context,
                        conflicts,
                        cachedFieldsAndFragmentNames,
                        comparedFragments,
                        comparedFragmentPairs,
                        false,
                        fieldMap,
                        fragmentNames[i]);

                    // (C) Then compare this fragment with all other fragments found in this
                    // selection set to collect conflicts between fragments spread together.
                    // This compares each item in the list of fragment names to every other
                    // item in that same list (except for itself).
                    for (int j = i + 1; j < fragmentNames.Count; j++)
                    {
                        CollectConflictsBetweenFragments(
                            context,
                            conflicts,
                            cachedFieldsAndFragmentNames,
                            comparedFragmentPairs,
                            false,
                            fragmentNames[i],
                            fragmentNames[j]);
                    }
                }
            }
            return(conflicts);
        }
        private static List <Conflict> FindConflictsBetweenSubSelectionSets(
            ValidationContext context,
            Dictionary <SelectionSet, CachedField> cachedFieldsAndFragmentNames,
            PairSet comparedFragmentPairs,
            bool areMutuallyExclusive,
            IGraphType?parentType1,
            SelectionSet selectionSet1,
            IGraphType?parentType2,
            SelectionSet selectionSet2)
        {
            var conflicts = new List <Conflict>();

            var cachedField1 = GetFieldsAndFragmentNames(
                context,
                cachedFieldsAndFragmentNames,
                parentType1,
                selectionSet1);

            var fieldMap1      = cachedField1.NodeAndDef;
            var fragmentNames1 = cachedField1.Names;

            var cachedField2 = GetFieldsAndFragmentNames(
                context,
                cachedFieldsAndFragmentNames,
                parentType2,
                selectionSet2);

            var fieldMap2      = cachedField2.NodeAndDef;
            var fragmentNames2 = cachedField2.Names;

            // (H) First, collect all conflicts between these two collections of field.
            CollectConflictsBetween(
                context,
                conflicts,
                cachedFieldsAndFragmentNames,
                comparedFragmentPairs,
                areMutuallyExclusive,
                fieldMap1,
                fieldMap2);

            // (I) Then collect conflicts between the first collection of fields and
            // those referenced by each fragment name associated with the second.
            if (fragmentNames2.Count != 0)
            {
                var comparedFragments = new HashSet <string>();

                for (var j = 0; j < fragmentNames2.Count; j++)
                {
                    CollectConflictsBetweenFieldsAndFragment(
                        context,
                        conflicts,
                        cachedFieldsAndFragmentNames,
                        comparedFragments,
                        comparedFragmentPairs,
                        areMutuallyExclusive,
                        fieldMap1,
                        fragmentNames2[j]);
                }
            }

            // (I) Then collect conflicts between the second collection of fields and
            // those referenced by each fragment name associated with the first.
            if (fragmentNames1.Count != 0)
            {
                var comparedFragments = new HashSet <string>();

                for (var i = 0; i < fragmentNames1.Count; i++)
                {
                    CollectConflictsBetweenFieldsAndFragment(
                        context,
                        conflicts,
                        cachedFieldsAndFragmentNames,
                        comparedFragments,
                        comparedFragmentPairs,
                        areMutuallyExclusive,
                        fieldMap2,
                        fragmentNames1[i]);
                }
            }

            // (J) Also collect conflicts between any fragment names by the first and
            // fragment names by the second. This compares each item in the first set of
            // names to each item in the second set of names.
            for (var i = 0; i < fragmentNames1.Count; i++)
            {
                for (var j = 0; j < fragmentNames2.Count; j++)
                {
                    CollectConflictsBetweenFragments(
                        context,
                        conflicts,
                        cachedFieldsAndFragmentNames,
                        comparedFragmentPairs,
                        areMutuallyExclusive,
                        fragmentNames1[i],
                        fragmentNames2[j]);
                }
            }

            return(conflicts);
        }
Пример #16
0
        public virtual void RegisterCommands(IEnumerable <Type> commandHandlerTypes)
        {
            foreach (var commandHandlerType in commandHandlerTypes)
            {
                var genericType = commandHandlerType.GetInterfaces().Single(x => x.GetTypeInfo().IsAssignableToGenericType(typeof(ICommandHandler <,>)) ||
                                                                            x.GetTypeInfo().IsAssignableToGenericType(typeof(IAsyncCommandHandler <,>)));
                var genericArguments = genericType.GetGenericArguments();
                var commandType      = genericArguments[0];
                var resultType       = genericArguments[1];

                var descriptionAttribute = commandType.GetCustomAttribute <DescriptionAttribute>();
                var exposeAttribute      = commandType.GetCustomAttribute <ExposeGraphQLAttribute>();
                var authorizeAttribute   = commandType.GetCustomAttribute <AuthorizeAttribute>();

                if (exposeAttribute == null)
                {
                    continue;
                }

                IInputObjectGraphType?inputGqlType = null;

                var properties = commandType.GetProperties(BindingFlags.Instance | BindingFlags.Public);

                if (properties.Any())
                {
                    var inputObjectType = typeof(InputObjectGraphType <>).MakeGenericType(commandType);
                    inputGqlType             = (IInputObjectGraphType)Activator.CreateInstance(inputObjectType);
                    inputGqlType.Name        = commandType.Name;
                    inputGqlType.Description = descriptionAttribute?.Description;

                    var addFieldMethod = inputGqlType.GetType().GetMethod("AddField");

                    foreach (var propertyInfo in properties)
                    {
                        addFieldMethod.Invoke(inputGqlType,
                                              new[]
                        {
                            new FieldType()
                            {
                                Name        = propertyInfo.Name.ToCamelCase(),
                                Type        = propertyInfo.PropertyType.GetGraphTypeFromType(),
                                Description = propertyInfo.GetCustomAttribute <DescriptionAttribute>()?.Description
                            }
                        });
                    }
                }

                IGraphType?resultGqlType = null;

                if (!GraphTypeTypeRegistry.Contains(resultType))
                {
                    var resultTypeName   = resultType.Name;
                    var returnObjectType = typeof(EntityGraphType <>).MakeGenericType(resultType);
                    resultGqlType      = (IGraphType)Activator.CreateInstance(returnObjectType, null);
                    resultGqlType.Name = resultTypeName;

                    if (authorizeAttribute != null)
                    {
                        var permissions = resultGqlType.GetMetadata <List <string> >(GraphQLExtensions.PermissionsKey);

                        if (permissions == null)
                        {
                            permissions = new List <string>();
                            resultGqlType.Metadata[GraphQLExtensions.PermissionsKey] = permissions;
                        }

                        if (!string.IsNullOrWhiteSpace(authorizeAttribute.Permission))
                        {
                            permissions.Add(authorizeAttribute.Permission);
                        }
                    }
                }

                var arguments = new List <QueryArgument>();

                if (inputGqlType != null)
                {
                    var argument = AllowNullCommand ? new QueryArgument(inputGqlType) : new QueryArgument(new NonNullGraphType(inputGqlType));
                    argument.Name = "command";
                    arguments.Add(argument);
                }

                var mutationName = exposeAttribute.IsFieldNameSet ? exposeAttribute.FieldName : new Regex("Command$").Replace(commandType.Name, "");

                if (!Mutation.HasField(mutationName))
                {
                    var type = new FieldType
                    {
                        Type = resultGqlType == null?GraphTypeTypeRegistry.Get(resultType) : null,
                                   ResolvedType = resultGqlType,
                                   Resolver     = new CommandResolver(_container, commandHandlerType, commandType, GetJsonSerializerSettings()),
                                   Name         = GetNormalizedFieldName(mutationName),
                                   Description  = descriptionAttribute?.Description,
                                   Arguments    = new QueryArguments(arguments)
                    };

                    Mutation.AddField(type);
                }
            }
        }
Пример #17
0
 internal static bool IsGraphQLTypeReference(this IGraphType?type)
 {
     var(namedType, _) = type.GetNamedTypes();
     return(namedType is GraphQLTypeReference);
 }
 public ListGraphType(IGraphType?type)
 {
     ResolvedType = type;
 }
Пример #19
0
        public virtual void RegisterQueries(IEnumerable <Type> queryHandlerTypes)
        {
            foreach (var queryHandlerType in queryHandlerTypes)
            {
                var genericType = queryHandlerType.GetInterfaces().Single(x => x.GetTypeInfo().IsAssignableToGenericType(typeof(IQueryHandler <,>)) ||
                                                                          x.GetTypeInfo().IsAssignableToGenericType(typeof(IAsyncQueryHandler <,>)));
                var genericArguments = genericType.GetGenericArguments();
                var queryType        = genericArguments[0];
                var resultType       = genericArguments[1];

                if (queryType.GetCustomAttribute <ExposeGraphQLAttribute>() == null)
                {
                    continue;
                }

                var isCollection = resultType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(resultType);

                if (isCollection)
                {
                    resultType = resultType.GetGenericArguments()[0];
                }

                var descriptionAttribute = queryType.GetCustomAttribute <DescriptionAttribute>();
                var exposeAttribute      = queryType.GetCustomAttribute <ExposeGraphQLAttribute>();
                var authorizeAttribute   = queryType.GetCustomAttribute <AuthorizeAttribute>();

                if (exposeAttribute == null)
                {
                    continue;
                }

                var properties = queryType.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(x => x.PropertyType != typeof(ResolveFieldContext));
                IInputObjectGraphType?inputGqlType = null;

                if (properties.Any())
                {
                    var inputObjectType = typeof(AutoInputGraphType <>).MakeGenericType(queryType);
                    inputGqlType             = (IInputObjectGraphType)_container.GetInstance(inputObjectType);
                    inputGqlType.Description = descriptionAttribute?.Description;

                    var addFieldMethod = inputGqlType.GetType().GetMethod("AddField");

                    foreach (var propertyInfo in properties)
                    {
                        addFieldMethod.Invoke(inputGqlType, new[]
                        {
                            new FieldType()
                            {
                                Name        = GetNormalizedFieldName(propertyInfo.Name),
                                Type        = propertyInfo.PropertyType.GetGraphTypeFromType(IsNullableProperty(propertyInfo)),
                                Description = propertyInfo.GetCustomAttribute <DescriptionAttribute>()?.Description
                            }
                        });
                    }
                }

                IGraphType?resultGqlType = null;

                if (!GraphTypeTypeRegistry.Contains(resultType))
                {
                    var resultTypeName   = GetTypeName(resultType);
                    var returnObjectType = typeof(AutoObjectGraphType <>).MakeGenericType(resultType);
                    resultGqlType      = (IGraphType)_container.GetInstance(returnObjectType);
                    resultGqlType.Name = resultTypeName;

                    if (isCollection)
                    {
                        var name        = resultGqlType.Name;
                        var listGqlType = (ListGraphType)Activator.CreateInstance(typeof(ListGraphType <>).MakeGenericType(returnObjectType), null);
                        listGqlType.ResolvedType = resultGqlType;
                        resultGqlType            = (IGraphType)listGqlType;
                        resultGqlType.Name       = "ListOf" + name;
                    }

                    if (authorizeAttribute != null)
                    {
                        var permissions = resultGqlType.GetMetadata <List <string> >(GraphQLExtensions.PermissionsKey);

                        if (permissions == null)
                        {
                            permissions = new List <string>();
                            resultGqlType.Metadata[GraphQLExtensions.PermissionsKey] = permissions;
                        }

                        if (!string.IsNullOrWhiteSpace(authorizeAttribute.Permission))
                        {
                            permissions.Add(authorizeAttribute.Permission);
                        }
                    }
                }

                var arguments = new List <QueryArgument>();

                if (inputGqlType != null)
                {
                    var argument = AllowNullQuery ? new QueryArgument(inputGqlType) : new QueryArgument(new NonNullGraphType(inputGqlType));
                    argument.Name = "query";
                    arguments.Add(argument);
                }

                var queryName = exposeAttribute.IsFieldNameSet ? exposeAttribute.FieldName : new Regex("Query").Replace(queryType.Name, "");

                if (!Query.HasField(queryName))
                {
                    var type = new FieldType
                    {
                        Type = resultGqlType == null?GraphTypeTypeRegistry.Get(resultType) : null,
                                   ResolvedType = resultGqlType,
                                   Resolver     = new QueryResolver(_container, queryHandlerType, queryType, GetJsonSerializerSettings()),
                                   Name         = GetNormalizedFieldName(queryName),
                                   Description  = descriptionAttribute?.Description,
                                   Arguments    = new QueryArguments(arguments)
                    };

                    Query.AddField(type);
                }
            }
        }