Example #1
0
        private object DeserializeObject(object resultValue, InputObjectType type, Path path)
        {
            if (resultValue is IReadOnlyDictionary <string, object?> map)
            {
                var fieldValues = new object?[type.Fields.Count];
                var consumed    = 0;

                for (var i = 0; i < type.Fields.Count; i++)
                {
                    InputField field = type.Fields[i];

                    if (map.TryGetValue(field.Name.Value, out var fieldValue))
                    {
                        Path fieldPath = path.Append(field.Name);

                        if (fieldValue is null && field.Type.Kind == TypeKind.NonNull)
                        {
                            throw NonNullInputViolation(type, fieldPath, field);
                        }

                        var value = Deserialize(fieldValue, field.Type, fieldPath, field);
                        value = FormatValue(field, value);
                        value = ConvertValue(field.RuntimeType, value);

                        if (field.IsOptional)
                        {
                            value = new Optional(value, true);
                        }

                        fieldValues[i] = value;
                        consumed++;
                    }
                    else
                    {
                        fieldValues[i] = CreateDefaultValue(field, path.Append(field.Name), 0);
                    }
                }

                if (consumed < map.Count)
                {
                    var invalidFieldNames = new List <string>();

                    foreach (string key in map.Keys)
                    {
                        if (!type.Fields.ContainsField(key))
                        {
                            invalidFieldNames.Add(key);
                        }
                    }

                    throw InvalidInputFieldNames(type, invalidFieldNames, path);
                }

                return(type.CreateInstance(fieldValues));
            }

            if (type.RuntimeType != typeof(object) &&
                type.RuntimeType.IsInstanceOfType(resultValue))
            {
                return(resultValue);
            }

            if (resultValue is ObjectValueNode node)
            {
                return(ParseObject(node, type, path, 0, true));
            }

            throw ParseInputObject_InvalidObjectKind(type, resultValue.GetType(), path);
        }
Example #2
0
        private object ParseObject(
            IValueNode resultValue,
            InputObjectType type,
            Path path,
            int stack,
            bool defaults)
        {
            if (resultValue.Kind == SyntaxKind.ObjectValue)
            {
                bool[]? processedBuffer = null;
                Span <bool> processed = stack <= 256 && type.Fields.Count <= 32
                    ? stackalloc bool[type.Fields.Count]
                    : processedBuffer = ArrayPool <bool> .Shared.Rent(type.Fields.Count);

                var processedCount = 0;

                if (processedBuffer is null)
                {
                    stack += type.Fields.Count;
                }

                var           fieldValues       = new object?[type.Fields.Count];
                List <string>?invalidFieldNames = null;

                try
                {
                    IReadOnlyList <ObjectFieldNode> fields = ((ObjectValueNode)resultValue).Fields;

                    for (var i = 0; i < fields.Count; i++)
                    {
                        ObjectFieldNode fieldValue = fields[i];

                        if (type.Fields.TryGetField(fieldValue.Name.Value, out InputField? field))
                        {
                            IValueNode literal   = fieldValue.Value;
                            Path       fieldPath = path.Append(field.Name);

                            if (literal.Kind == SyntaxKind.NullValue &&
                                field.Type.Kind == TypeKind.NonNull)
                            {
                                throw NonNullInputViolation(type, fieldPath, field);
                            }

                            var value = ParseLiteralInternal(
                                literal,
                                field.Type,
                                fieldPath,
                                stack,
                                defaults,
                                field);
                            value = FormatValue(field, value);
                            value = ConvertValue(field.RuntimeType, value);

                            if (field.IsOptional)
                            {
                                value = new Optional(value, true);
                            }

                            fieldValues[field.Index] = value;
                            processed[field.Index]   = true;
                            processedCount++;
                        }
                        else
                        {
                            invalidFieldNames ??= new List <string>();
                            invalidFieldNames.Add(fieldValue.Name.Value);
                        }
                    }

                    if (invalidFieldNames?.Count > 0)
                    {
                        throw InvalidInputFieldNames(type, invalidFieldNames, path);
                    }

                    if (processedCount < type.Fields.Count)
                    {
                        for (var i = 0; i < type.Fields.Count; i++)
                        {
                            if (!processed[i])
                            {
                                InputField field     = type.Fields[i];
                                Path       fieldPath = path.Append(field.Name);
                                fieldValues[i] = CreateDefaultValue(field, fieldPath, stack);
                            }
                        }
                    }
                }
                finally
                {
                    if (processedBuffer is not null)
                    {
                        ArrayPool <bool> .Shared.Return(processedBuffer);
                    }
                }

                return(type.CreateInstance(fieldValues));
            }

            throw ParseInputObject_InvalidSyntaxKind(type, resultValue.Kind, path);
        }