public static IValue AstFromValue(this object value, ISchema schema, IGraphType type)
        {
            if (type is NonNullGraphType)
            {
                var nonnull = (NonNullGraphType)type;
                return(AstFromValue(value, schema, nonnull.ResolvedType));
            }

            if (value == null || type == null)
            {
                return(new NullValue());
            }

            // Convert IEnumerable to GraphQL list. If the GraphQLType is a list, but
            // the value is not an IEnumerable, convert the value using the list's item type.
            if (type is ListGraphType)
            {
                var listType = (ListGraphType)type;
                var itemType = listType.ResolvedType;

                if (!(value is string) && value is IEnumerable)
                {
                    var list   = (IEnumerable)value;
                    var values = list.Map(item => AstFromValue(item, schema, itemType));
                    return(new ListValue(values));
                }

                return(AstFromValue(value, schema, itemType));
            }

            // Populate the fields of the input object by creating ASTs from each value
            // in the dictionary according to the fields in the input type.
            if (type is IInputObjectGraphType)
            {
                if (!(value is Dictionary <string, object>))
                {
                    return(null);
                }

                var input = (IInputObjectGraphType)type;
                var dict  = (Dictionary <string, object>)value;

                var fields = dict
                             .Select(pair =>
                {
                    var fieldType = input.GetField(pair.Key)?.ResolvedType;
                    return(new ObjectField(pair.Key, AstFromValue(pair.Value, schema, fieldType)));
                })
                             .ToList();

                return(new ObjectValue(fields));
            }


            Invariant.Check(
                type.IsInputType(),
                $"Must provide Input Type, cannot use: {type}");


            var inputType = type as ScalarGraphType;

            // Since value is an internally represented value, it must be serialized
            // to an externally represented value before converting into an AST.
            var serialized = inputType.Serialize(value);

            if (serialized == null)
            {
                return(null);
            }

            if (serialized is bool)
            {
                return(new BooleanValue((bool)serialized));
            }

            if (serialized is int)
            {
                return(new IntValue((int)serialized));
            }

            if (serialized is long)
            {
                return(new LongValue((long)serialized));
            }

            if (serialized is decimal)
            {
                return(new DecimalValue((decimal)serialized));
            }

            if (serialized is double)
            {
                return(new FloatValue((double)serialized));
            }

            if (serialized is DateTime)
            {
                return(new DateTimeValue((DateTime)serialized));
            }

            if (serialized is Uri uri)
            {
                return(new UriValue(uri));
            }

            if (serialized is DateTimeOffset)
            {
                return(new DateTimeOffsetValue((DateTimeOffset)serialized));
            }

            if (serialized is TimeSpan)
            {
                return(new TimeSpanValue((TimeSpan)serialized));
            }

            if (serialized is string)
            {
                if (type is EnumerationGraphType)
                {
                    return(new EnumValue(serialized.ToString()));
                }

                return(new StringValue(serialized.ToString()));
            }

            var converter = schema.FindValueConverter(serialized, type);

            if (converter != null)
            {
                return(converter.Convert(serialized, type));
            }

            throw new ExecutionError($"Cannot convert value to AST: {serialized}");
        }