-
-
Notifications
You must be signed in to change notification settings - Fork 722
/
ArgumentNonNullValidator.cs
140 lines (115 loc) · 4.23 KB
/
ArgumentNonNullValidator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
using System.Collections.Generic;
using HotChocolate.Language;
using HotChocolate.Types;
namespace HotChocolate.Execution.Processing
{
internal static class ArgumentNonNullValidator
{
public static ValidationResult Validate(IInputField field, IValueNode? value, Path path)
{
// if no value was provided
if (value is null)
{
// the type is a non-null type and no default value has been set we mark this
// field as violation.
if (field.Type.IsNonNullType() && field.DefaultValue.IsNull())
{
return new ValidationResult(field.Type, path);
}
// if the field has a default value or nullable everything is fine and we
// return success.
return default;
}
// if null was explicitly set
if (value is NullValueNode)
{
// and the field type is a non-null type we will mark the field value
// as violation.
if (field.Type.IsNonNullType())
{
return new ValidationResult(field.Type, path);
}
// if the field is nullable we will mark the field as valid.
return default;
}
// if the field has a value we traverse it and make sure the value is correct.
return ValidateInnerType(field.Type, value, path);
}
private static ValidationResult Validate(IType type, IValueNode? value, Path path)
{
if (value.IsNull())
{
return type.IsNonNullType() ? new ValidationResult(type, path) : default;
}
return ValidateInnerType(type, value, path);
}
private static ValidationResult ValidateInnerType(IType type, IValueNode? value, Path path)
{
IType innerType = type.IsNonNullType() ? type.InnerType() : type;
if (innerType is ListType listType)
{
if (value is ListValueNode listValue)
{
return ValidateList(listType, listValue, path);
}
Validate(listType.ElementType, value, path);
}
if (innerType is InputObjectType inputType && value is ObjectValueNode ov)
{
return ValidateObject(inputType, ov, path);
}
return default;
}
private static ValidationResult ValidateObject(
InputObjectType type,
ObjectValueNode value,
Path path)
{
var fields = new Dictionary<NameString, IValueNode>();
for (var i = 0; i < value.Fields.Count; i++)
{
ObjectFieldNode field = value.Fields[i];
fields[field.Name.Value] = field.Value;
}
foreach (InputField field in type.Fields)
{
fields.TryGetValue(field.Name, out IValueNode? fieldValue);
ValidationResult report = Validate(
field,
fieldValue,
path.Append(field.Name));
if (report.HasErrors)
{
return report;
}
}
return default;
}
private static ValidationResult ValidateList(ListType type, ListValueNode list, Path path)
{
IType elementType = type.ElementType();
var i = 0;
foreach (IValueNode element in list.Items)
{
ValidationResult error = Validate(elementType, element, path.Append(i++));
if (error.HasErrors)
{
return error;
}
}
return default;
}
internal readonly ref struct ValidationResult
{
internal ValidationResult(IType type, Path path)
{
Type = type;
Path = path;
HasErrors = true;
}
public bool HasErrors { get; }
public Path Path { get; }
public IType Type { get; }
}
}
}