Skip to content

Commit 843aec9

Browse files
authored
Merge pull request #197 from graphql-dotnet/fix-numeric-deserializetion-in-extensions
Fix numeric deserializetion in extensions
2 parents 54cf670 + 2c79e45 commit 843aec9

File tree

10 files changed

+39
-44
lines changed

10 files changed

+39
-44
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,41 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Runtime.InteropServices;
34
using Newtonsoft.Json;
45
using Newtonsoft.Json.Linq;
56

67
namespace GraphQL.Client.Serializer.Newtonsoft
78
{
8-
public class GraphQLExtensionsConverter : JsonConverter<GraphQLExtensionsType>
9+
public class MapConverter : JsonConverter<Map>
910
{
10-
public override void WriteJson(JsonWriter writer, GraphQLExtensionsType value, JsonSerializer serializer) =>
11+
public override void WriteJson(JsonWriter writer, Map value, JsonSerializer serializer) =>
1112
throw new NotImplementedException(
1213
"This converter currently is only intended to be used to read a JSON object into a strongly-typed representation.");
1314

14-
public override GraphQLExtensionsType ReadJson(JsonReader reader, Type objectType, GraphQLExtensionsType existingValue,
15+
public override Map ReadJson(JsonReader reader, Type objectType, Map existingValue,
1516
bool hasExistingValue, JsonSerializer serializer)
1617
{
1718
var rootToken = JToken.ReadFrom(reader);
1819
if (rootToken is JObject)
1920
{
20-
return ReadDictionary<GraphQLExtensionsType>(rootToken);
21+
return ReadDictionary<Map>(rootToken);
2122
}
2223
else
2324
throw new ArgumentException("This converter can only parse when the root element is a JSON Object.");
2425
}
2526

2627
private object ReadToken(JToken? token) =>
27-
token.Type switch
28+
token switch
2829
{
29-
JTokenType.Undefined => null,
30-
JTokenType.None => null,
31-
JTokenType.Null => null,
32-
JTokenType.Object => ReadDictionary<Dictionary<string, object>>(token),
33-
JTokenType.Array => ReadArray(token),
34-
JTokenType.Integer => token.Value<int>(),
35-
JTokenType.Float => token.Value<double>(),
36-
JTokenType.Raw => token.Value<string>(),
37-
JTokenType.String => token.Value<string>(),
38-
JTokenType.Uri => token.Value<string>(),
39-
JTokenType.Boolean => token.Value<bool>(),
40-
JTokenType.Date => token.Value<DateTime>(),
41-
JTokenType.Bytes => token.Value<byte[]>(),
42-
JTokenType.Guid => token.Value<Guid>(),
43-
JTokenType.TimeSpan => token.Value<TimeSpan>(),
44-
JTokenType.Constructor => throw new ArgumentOutOfRangeException(nameof(token.Type), "cannot deserialize a JSON constructor"),
45-
JTokenType.Property => throw new ArgumentOutOfRangeException(nameof(token.Type), "cannot deserialize a JSON property"),
46-
JTokenType.Comment => throw new ArgumentOutOfRangeException(nameof(token.Type), "cannot deserialize a JSON comment"),
30+
JObject jObject => ReadDictionary<Dictionary<string, object>>(jObject),
31+
JArray jArray => ReadArray(jArray),
32+
JValue jValue => jValue.Value,
33+
JConstructor _ => throw new ArgumentOutOfRangeException(nameof(token.Type),
34+
"cannot deserialize a JSON constructor"),
35+
JProperty _ => throw new ArgumentOutOfRangeException(nameof(token.Type),
36+
"cannot deserialize a JSON property"),
37+
JContainer _ => throw new ArgumentOutOfRangeException(nameof(token.Type),
38+
"cannot deserialize a JSON comment"),
4739
_ => throw new ArgumentOutOfRangeException(nameof(token.Type))
4840
};
4941

@@ -69,6 +61,8 @@ private IEnumerable<object> ReadArray(JToken element)
6961
}
7062
}
7163

64+
private object ReadNumber(JToken token) => ((JValue) token).Value;
65+
7266
private bool IsUnsupportedJTokenType(JTokenType type) => type == JTokenType.Constructor || type == JTokenType.Property || type == JTokenType.Comment;
7367
}
7468
}

src/GraphQL.Client.Serializer.Newtonsoft/NewtonsoftJsonSerializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public NewtonsoftJsonSerializer(JsonSerializerSettings jsonSerializerSettings)
3131
}
3232

3333
// deserialize extensions to Dictionary<string, object>
34-
private void ConfigureMandatorySerializerOptions() => JsonSerializerSettings.Converters.Insert(0, new GraphQLExtensionsConverter());
34+
private void ConfigureMandatorySerializerOptions() => JsonSerializerSettings.Converters.Insert(0, new MapConverter());
3535

3636
public string SerializeToString(GraphQLRequest request) => JsonConvert.SerializeObject(request, JsonSerializerSettings);
3737

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ namespace GraphQL.Client.Serializer.SystemTextJson
1313
/// <remarks>
1414
/// Taken and modified from GraphQL.SystemTextJson.ObjectDictionaryConverter (GraphQL.NET)
1515
/// </remarks>
16-
public class GraphQLExtensionsConverter : JsonConverter<GraphQLExtensionsType>
16+
public class MapConverter : JsonConverter<Map>
1717
{
18-
public override GraphQLExtensionsType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
18+
public override Map Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1919
{
2020
using var doc = JsonDocument.ParseValue(ref reader);
2121

@@ -24,10 +24,10 @@ public override GraphQLExtensionsType Read(ref Utf8JsonReader reader, Type typeT
2424
throw new ArgumentException("This converter can only parse when the root element is a JSON Object.");
2525
}
2626

27-
return ReadDictionary<GraphQLExtensionsType>(doc.RootElement);
27+
return ReadDictionary<Map>(doc.RootElement);
2828
}
2929

30-
public override void Write(Utf8JsonWriter writer, GraphQLExtensionsType value, JsonSerializerOptions options)
30+
public override void Write(Utf8JsonWriter writer, Map value, JsonSerializerOptions options)
3131
=> throw new NotImplementedException(
3232
"This converter currently is only intended to be used to read a JSON object into a strongly-typed representation.");
3333

src/GraphQL.Client.Serializer.SystemTextJson/SystemTextJsonSerializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public SystemTextJsonSerializer(JsonSerializerOptions options)
3030
private void ConfigureMandatorySerializerOptions()
3131
{
3232
// deserialize extensions to Dictionary<string, object>
33-
Options.Converters.Insert(0, new GraphQLExtensionsConverter());
33+
Options.Converters.Insert(0, new MapConverter());
3434
// allow the JSON field "data" to match the property "Data" even without JsonNamingPolicy.CamelCase
3535
Options.PropertyNameCaseInsensitive = true;
3636
}

src/GraphQL.Primitives/GraphQLError.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class GraphQLError : IEquatable<GraphQLError?>
3434
/// The extensions of the error
3535
/// </summary>
3636
[DataMember(Name = "extensions")]
37-
public GraphQLExtensionsType? Extensions { get; set; }
37+
public Map? Extensions { get; set; }
3838

3939
/// <summary>
4040
/// Returns a value that indicates whether this instance is equal to a specified object

src/GraphQL.Primitives/GraphQLExtensionsType.cs

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/GraphQL.Primitives/GraphQLResponse.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class GraphQLResponse<T> : IEquatable<GraphQLResponse<T>?>
1616
public GraphQLError[]? Errors { get; set; }
1717

1818
[DataMember(Name = "extensions")]
19-
public GraphQLExtensionsType? Extensions { get; set; }
19+
public Map? Extensions { get; set; }
2020

2121
public override bool Equals(object? obj) => Equals(obj as GraphQLResponse<T>);
2222

src/GraphQL.Primitives/Map.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Collections.Generic;
2+
3+
namespace GraphQL
4+
{
5+
6+
/// <summary>
7+
/// A type equivalent to a javascript map. Create a custom json converter for this class to customize your serializers behaviour
8+
/// </summary>
9+
public class Map : Dictionary<string, object> { }
10+
}

tests/GraphQL.Client.Serializer.Tests/TestData/DeserializeResponseTestData.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ public IEnumerator<object[]> GetEnumerator()
1818
Errors = new[] {
1919
new GraphQLError {
2020
Message = "Throttled",
21-
Extensions = new GraphQLExtensionsType {
21+
Extensions = new Map {
2222
{"code", "THROTTLED" },
2323
{"documentation", "https://help.shopify.com/api/graphql-admin-api/graphql-admin-api-rate-limits" }
2424
}
2525
}
2626
},
27-
Extensions = new GraphQLExtensionsType {
27+
Extensions = new Map {
2828
{"cost", new Dictionary<string, object> {
2929
{"requestedQueryCost", 992},
3030
{"actualQueryCost", null},

tests/GraphQL.Client.Tests.Common/Chat/Schema/ChatQuery.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ public class ChatQuery : ObjectGraphType
1010

1111
public static readonly Dictionary<string, object> TestExtensions = new Dictionary<string, object> {
1212
{"extension1", "hello world"},
13-
{"another extension", 4711}
13+
{"another extension", 4711},
14+
{"long", 19942590700}
1415
};
1516

1617
// properties for unit testing

0 commit comments

Comments
 (0)