Skip to content

Commit 0a232c3

Browse files
authored
Fixed: Type discovery now correctly discovers argument types. (#344)
1 parent 7c533e0 commit 0a232c3

37 files changed

+616
-230
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
3+
namespace HotChocolate
4+
{
5+
[AttributeUsage(AttributeTargets.Class
6+
| AttributeTargets.Property
7+
| AttributeTargets.Method
8+
| AttributeTargets.Parameter)]
9+
public sealed class GraphQLDescriptionAttribute
10+
: Attribute
11+
{
12+
public GraphQLDescriptionAttribute(string description)
13+
{
14+
if (string.IsNullOrEmpty(description))
15+
{
16+
throw new ArgumentNullException(nameof(description));
17+
}
18+
19+
Description = description;
20+
}
21+
22+
public string Description { get; }
23+
}
24+
}

src/Abstractions/GraphQLNameAttribute.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ namespace HotChocolate
44
{
55
[AttributeUsage(AttributeTargets.Class
66
| AttributeTargets.Property
7-
| AttributeTargets.Method)]
7+
| AttributeTargets.Method
8+
| AttributeTargets.Parameter)]
89
public sealed class GraphQLNameAttribute
910
: Attribute
1011
{
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
namespace HotChocolate
4+
{
5+
[AttributeUsage(AttributeTargets.Property
6+
| AttributeTargets.Method)]
7+
public sealed class GraphQLNonNullAttribute
8+
: Attribute
9+
{
10+
public bool ElementIsNullable { get; set; } = false;
11+
public bool IsNullable { get; set; } = false;
12+
}
13+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
3+
namespace HotChocolate
4+
{
5+
[AttributeUsage(AttributeTargets.Property
6+
| AttributeTargets.Method)]
7+
public sealed class GraphQLTypeAttribute
8+
: Attribute
9+
{
10+
public GraphQLTypeAttribute(Type type)
11+
{
12+
if (type == null)
13+
{
14+
throw new ArgumentNullException(nameof(type));
15+
}
16+
17+
Type = type;
18+
}
19+
20+
public Type Type { get; }
21+
}
22+
}

src/Core.Tests/Execution/Utilities/VariableValueBuilderTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,30 @@ public void CreateValues_ObjectAsDictionary_Object()
278278
Assert.Equal(BarEnum.B, bar.F.B);
279279
}
280280

281+
[Fact]
282+
public void CreateValues_ListOfObject_ListOfString()
283+
{
284+
// arrange
285+
Schema schema = CreateSchema();
286+
OperationDefinitionNode operation = CreateQuery(
287+
"query test($test: [String]) { a }");
288+
289+
var variableValues = new Dictionary<string, object>();
290+
variableValues.Add("test", new List<object> { "a", "b" });
291+
292+
var resolver = new VariableValueBuilder(schema, operation);
293+
294+
// act
295+
VariableCollection coercedVariableValues =
296+
resolver.CreateValues(variableValues);
297+
298+
// assert
299+
string[] list = coercedVariableValues.GetVariable<string[]>("test");
300+
Assert.Collection(list,
301+
t => Assert.Equal("a", t),
302+
t => Assert.Equal("b", t));
303+
}
304+
281305
[Fact]
282306
public void CreateValues_SerializedDecimal_Decimal()
283307
{

src/Core/Execution/Utilities/DictionaryToObjectConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace HotChocolate.Execution
1010
internal class DictionaryToObjectConverter
1111
: QueryResultVisitor<DeserializationContext>
1212
{
13-
public override void VisitObject(
13+
protected override void VisitObject(
1414
ICollection<KeyValuePair<string, object>> dictionary,
1515
DeserializationContext context)
1616
{

src/Core/Execution/Utilities/QueryResultVisitor.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,23 @@ namespace HotChocolate.Execution
99
{
1010
internal abstract class QueryResultVisitor<TContext>
1111
{
12-
public virtual void VisitObject(
12+
public virtual void Visit(object value, TContext context)
13+
{
14+
if (value is IDictionary<string, object> dictionary)
15+
{
16+
VisitObject(dictionary, context);
17+
}
18+
else if (value is IList<object> list)
19+
{
20+
VisitList(list, context);
21+
}
22+
else
23+
{
24+
VisitValue(value, context);
25+
}
26+
}
27+
28+
protected virtual void VisitObject(
1329
ICollection<KeyValuePair<string, object>> dictionary,
1430
TContext context)
1531
{
@@ -38,21 +54,5 @@ protected virtual void VisitValue(object value, TContext context)
3854
{
3955

4056
}
41-
42-
protected virtual void Visit(object value, TContext context)
43-
{
44-
if (value is IDictionary<string, object> dictionary)
45-
{
46-
VisitObject(dictionary, context);
47-
}
48-
else if (value is IList<object> list)
49-
{
50-
VisitList(list, context);
51-
}
52-
else
53-
{
54-
VisitValue(value, context);
55-
}
56-
}
5757
}
5858
}

src/Core/Execution/Utilities/VariableValueBuilder.cs

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public VariableCollection CreateValues(
4747
_operation.VariableDefinitions)
4848
{
4949
Variable variable = CreateVariable(variableDefinition);
50-
CoerceVariableValue(values, ref variable);
50+
variable = CoerceVariableValue(values, variable);
5151
coercedValues[variable.Name] = variable.ParseLiteral();
5252
}
5353

@@ -73,35 +73,14 @@ private Variable CreateVariable(
7373
variableName));
7474
}
7575

76-
private void CoerceVariableValue(
76+
private Variable CoerceVariableValue(
7777
IReadOnlyDictionary<string, object> variableValues,
78-
ref Variable variable)
78+
Variable variable)
7979
{
8080
IValueNode valueNode = null;
8181
if (variableValues.TryGetValue(variable.Name, out var rawValue))
8282
{
83-
object value = rawValue;
84-
85-
if (rawValue is ICollection<KeyValuePair<string, object>> dict)
86-
{
87-
var ctx = new DeserializationContext();
88-
ctx.Type = variable.Type.ClrType;
89-
90-
var converter = new DictionaryToObjectConverter();
91-
converter.VisitObject(dict, ctx);
92-
value = ctx.Object;
93-
}
94-
95-
if (!(value is IValueNode)
96-
&& variable.Type is ISerializableType st
97-
&& !variable.Type.ClrType.IsInstanceOfType(value))
98-
{
99-
value = st.Deserialize(value);
100-
}
101-
102-
valueNode = (value is IValueNode v)
103-
? v
104-
: variable.Type.ParseValue(value);
83+
valueNode = Normalize(variable, rawValue);
10584
}
10685
else
10786
{
@@ -113,9 +92,36 @@ private void CoerceVariableValue(
11392

11493
CheckForNullValueViolation(variable);
11594
CheckForInvalidValueType(variable);
95+
96+
return variable;
11697
}
11798

99+
private IValueNode Normalize(Variable variable, object rawValue)
100+
{
101+
object value = rawValue;
102+
103+
if (rawValue is ICollection<KeyValuePair<string, object>>
104+
|| rawValue is IList<object>)
105+
{
106+
var ctx = new DeserializationContext();
107+
ctx.Type = variable.Type.ClrType;
108+
109+
var converter = new DictionaryToObjectConverter();
110+
converter.Visit(rawValue, ctx);
111+
value = ctx.Object;
112+
}
118113

114+
if (!(value is IValueNode)
115+
&& variable.Type is ISerializableType st
116+
&& !variable.Type.ClrType.IsInstanceOfType(value))
117+
{
118+
value = st.Deserialize(value);
119+
}
120+
121+
return (value is IValueNode v)
122+
? v
123+
: variable.Type.ParseValue(value);
124+
}
119125

120126
private IValueNode CleanUpValue(IInputType type, IValueNode value)
121127
{

0 commit comments

Comments
 (0)