Skip to content

Commit 56ee4d6

Browse files
committed
WIP Migrating from Newtonsoft.Json to System.Text.Json
1 parent 9b33b65 commit 56ee4d6

20 files changed

+422
-298
lines changed

Postgrest/Attributes/ColumnAttribute.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22
using System.Runtime.CompilerServices;
3-
using Newtonsoft.Json;
3+
using System.Text.Json.Serialization;
44
namespace Supabase.Postgrest.Attributes
55
{
66

@@ -26,7 +26,7 @@ public class ColumnAttribute : Attribute
2626
/// <summary>
2727
/// Specifies what should be serialized in the event this column's value is NULL
2828
/// </summary>
29-
public NullValueHandling NullValueHandling { get; set; }
29+
public JsonIgnoreCondition NullValueHandling { get; set; }
3030

3131
/// <summary>
3232
/// If the performed query is an Insert or Upsert, should this value be ignored?
@@ -39,7 +39,7 @@ public class ColumnAttribute : Attribute
3939
public bool IgnoreOnUpdate { get; }
4040

4141
/// <inheritdoc />
42-
public ColumnAttribute([CallerMemberName] string? columnName = null, NullValueHandling nullValueHandling = NullValueHandling.Include, bool ignoreOnInsert = false, bool ignoreOnUpdate = false)
42+
public ColumnAttribute([CallerMemberName] string? columnName = null, JsonIgnoreCondition nullValueHandling = JsonIgnoreCondition.Never, bool ignoreOnInsert = false, bool ignoreOnUpdate = false)
4343
{
4444
ColumnName = columnName!; // Will either be user specified or given by runtime compiler.
4545
NullValueHandling = nullValueHandling;

Postgrest/Client.cs

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,39 @@
22
using System.Collections.Generic;
33
using System.Net.Http;
44
using System.Threading.Tasks;
5-
using Newtonsoft.Json;
6-
using Newtonsoft.Json.Converters;
5+
using System.Text.Json;
6+
using System.Text.Json.Serialization;
77
using Supabase.Core.Extensions;
88
using Supabase.Postgrest.Interfaces;
99
using Supabase.Postgrest.Models;
1010
using Supabase.Postgrest.Responses;
11+
using System.Text.Json.Serialization.Metadata;
12+
using System.Reflection;
13+
using Supabase.Postgrest.Converters;
1114

1215
namespace Supabase.Postgrest
1316
{
1417
/// <inheritdoc />
1518
public class Client : IPostgrestClient
1619
{
1720
/// <summary>
18-
/// Custom Serializer resolvers and converters that will be used for encoding and decoding Postgrest JSON responses.
21+
/// Custom Serializer options that will be used for encoding and decoding Postgrest JSON responses.
1922
///
20-
/// By default, Postgrest seems to use a date format that C# and Newtonsoft do not like, so this initial
23+
/// By default, Postgrest seems to use a date format that C# does not like, so this initial
2124
/// configuration handles that.
2225
/// </summary>
23-
public static JsonSerializerSettings SerializerSettings(ClientOptions? options = null)
26+
public static JsonSerializerOptions SerializerOptions(ClientOptions? options = null)
2427
{
2528
options ??= new ClientOptions();
2629

27-
return new JsonSerializerSettings
30+
return new JsonSerializerOptions
2831
{
29-
ContractResolver = new PostgrestContractResolver(),
32+
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
3033
Converters =
3134
{
32-
// 2020-08-28T12:01:54.763231
33-
new IsoDateTimeConverter
34-
{
35-
DateTimeStyles = options.DateTimeStyles,
36-
DateTimeFormat = ClientOptions.DATE_TIME_FORMAT
37-
}
35+
new JsonStringEnumConverter(),
36+
// new PostgrestDateTimeConverter(options.DateTimeStyles, ClientOptions.DATE_TIME_FORMAT)
37+
new RangeConverter()
3838
}
3939
};
4040
}
@@ -70,7 +70,7 @@ public void RemoveDebugHandler(IPostgrestDebugger.DebugEventHandler handler) =>
7070

7171
/// <summary>
7272
/// Function that can be set to return dynamic headers.
73-
///
73+
///
7474
/// Headers specified in the constructor options will ALWAYS take precedence over headers returned by this function.
7575
/// </summary>
7676
public Func<Dictionary<string, string>>? GetHeaders { get; set; }
@@ -87,29 +87,27 @@ public Client(string baseUrl, ClientOptions? options = null)
8787
Options = options ?? new ClientOptions();
8888
}
8989

90-
9190
/// <inheritdoc />
9291
public IPostgrestTable<T> Table<T>() where T : BaseModel, new() =>
93-
new Table<T>(BaseUrl, SerializerSettings(Options), Options)
92+
new Table<T>(BaseUrl, SerializerOptions(Options), Options)
9493
{
9594
GetHeaders = GetHeaders
9695
};
9796

9897
/// <inheritdoc />
9998
public IPostgrestTableWithCache<T> Table<T>(IPostgrestCacheProvider cacheProvider)
10099
where T : BaseModel, new() =>
101-
new TableWithCache<T>(BaseUrl, cacheProvider, SerializerSettings(Options), Options)
100+
new TableWithCache<T>(BaseUrl, cacheProvider, SerializerOptions(Options), Options)
102101
{
103102
GetHeaders = GetHeaders
104103
};
105104

106-
107105
/// <inheritdoc />
108106
public async Task<TModeledResponse?> Rpc<TModeledResponse>(string procedureName, object? parameters = null)
109107
{
110108
var response = await Rpc(procedureName, parameters);
111109

112-
return string.IsNullOrEmpty(response.Content) ? default : JsonConvert.DeserializeObject<TModeledResponse>(response.Content!);
110+
return string.IsNullOrEmpty(response.Content) ? default : JsonSerializer.Deserialize<TModeledResponse>(response.Content!, SerializerOptions(Options));
113111
}
114112

115113
/// <inheritdoc />
@@ -120,13 +118,13 @@ public Task<BaseResponse> Rpc(string procedureName, object? parameters = null)
120118

121119
var canonicalUri = builder.Uri.ToString();
122120

123-
var serializerSettings = SerializerSettings(Options);
121+
var serializerOptions = SerializerOptions(Options);
124122

125123
// Prepare parameters
126124
Dictionary<string, object>? data = null;
127125
if (parameters != null)
128-
data = JsonConvert.DeserializeObject<Dictionary<string, object>>(
129-
JsonConvert.SerializeObject(parameters, serializerSettings));
126+
data = JsonSerializer.Deserialize<Dictionary<string, object>>(
127+
JsonSerializer.Serialize(parameters, serializerOptions));
130128

131129
// Prepare headers
132130
var headers = Helpers.PrepareRequestHeaders(HttpMethod.Post,
@@ -137,8 +135,8 @@ public Task<BaseResponse> Rpc(string procedureName, object? parameters = null)
137135

138136
// Send request
139137
var request =
140-
Helpers.MakeRequest(Options, HttpMethod.Post, canonicalUri, serializerSettings, data, headers);
138+
Helpers.MakeRequest(Options, HttpMethod.Post, canonicalUri, serializerOptions, data, headers);
141139
return request;
142140
}
143141
}
144-
}
142+
}

Postgrest/Converters/DateTimeConverter.cs

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4-
using Newtonsoft.Json;
5-
using Newtonsoft.Json.Linq;
4+
using System.Text.Json;
5+
using System.Text.Json.Serialization;
66
namespace Supabase.Postgrest.Converters
77
{
88

99
/// <inheritdoc />
10-
public class DateTimeConverter : JsonConverter
10+
public class DateTimeConverter : JsonConverter<object>
1111
{
1212
/// <inheritdoc />
13-
public override bool CanConvert(Type objectType)
13+
public override bool CanConvert(Type typeToConvert)
1414
{
15-
throw new NotImplementedException();
15+
return typeToConvert == typeof(DateTime) || typeToConvert == typeof(List<DateTime>);
1616
}
1717

1818
/// <inheritdoc />
19-
public override bool CanWrite => false;
20-
21-
/// <inheritdoc />
22-
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
19+
public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
2320
{
24-
if (reader.Value != null)
21+
if (reader.TokenType == JsonTokenType.String)
2522
{
26-
var str = reader.Value.ToString();
23+
var str = reader.GetString();
24+
if (str == null)
25+
{
26+
return null;
27+
}
2728

2829
var infinity = ParseInfinity(str);
2930

@@ -32,38 +33,46 @@ public override bool CanConvert(Type objectType)
3233
return (DateTime)infinity;
3334
}
3435

35-
var date = DateTime.Parse(str);
36-
return date;
36+
return DateTime.Parse(str);
3737
}
3838

39-
var result = new List<DateTime>();
40-
41-
try
39+
if (reader.TokenType == JsonTokenType.StartArray)
4240
{
43-
var jo = JArray.Load(reader);
41+
var result = new List<DateTime>();
4442

45-
foreach (var item in jo.ToArray())
43+
while (reader.Read())
4644
{
47-
var inner = item.ToString();
48-
49-
var infinity = ParseInfinity(inner);
50-
51-
if (infinity != null)
45+
if (reader.TokenType == JsonTokenType.EndArray)
5246
{
53-
result.Add((DateTime)infinity);
47+
break;
5448
}
5549

56-
var date = DateTime.Parse(inner);
57-
result.Add(date);
50+
if (reader.TokenType == JsonTokenType.String)
51+
{
52+
var inner = reader.GetString();
53+
if (inner == null)
54+
{
55+
return null;
56+
}
57+
58+
var infinity = ParseInfinity(inner);
59+
60+
if (infinity != null)
61+
{
62+
result.Add((DateTime)infinity);
63+
}
64+
else
65+
{
66+
var date = DateTime.Parse(inner);
67+
result.Add(date);
68+
}
69+
}
5870
}
59-
}
60-
catch (JsonReaderException)
61-
{
62-
return null;
63-
}
6471

72+
return result;
73+
}
6574

66-
return result;
75+
return null;
6776
}
6877

6978
private static DateTime? ParseInfinity(string input)
@@ -77,7 +86,7 @@ public override bool CanConvert(Type objectType)
7786
}
7887

7988
/// <inheritdoc />
80-
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
89+
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
8190
{
8291
throw new NotImplementedException();
8392
}

Postgrest/Converters/IntConverter.cs

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,53 @@
11
using System;
22
using System.Collections.Generic;
3-
using Newtonsoft.Json;
3+
using System.Text.Json;
4+
using System.Text.Json.Serialization;
45
namespace Supabase.Postgrest.Converters
56
{
67

78
/// <inheritdoc />
8-
public class IntArrayConverter : JsonConverter
9+
public class IntArrayConverter : JsonConverter<List<int>>
910
{
1011
/// <inheritdoc />
11-
public override bool CanConvert(Type objectType)
12+
public override bool CanConvert(Type typeToConvert)
1213
{
13-
throw new NotImplementedException();
14+
return typeToConvert == typeof(List<int>);
1415
}
1516

1617
/// <inheritdoc />
17-
public override bool CanRead => false;
18-
19-
/// <inheritdoc />
20-
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
18+
public override List<int>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
2119
{
22-
throw new NotImplementedException();
20+
if (reader.TokenType != JsonTokenType.StartArray)
21+
{
22+
throw new JsonException("Expected start of array.");
23+
}
24+
25+
var list = new List<int>();
26+
27+
while (reader.Read())
28+
{
29+
if (reader.TokenType == JsonTokenType.EndArray)
30+
{
31+
return list;
32+
}
33+
34+
if (reader.TokenType == JsonTokenType.Number)
35+
{
36+
list.Add(reader.GetInt32());
37+
}
38+
else
39+
{
40+
throw new JsonException($"Unexpected token type: {reader.TokenType}");
41+
}
42+
}
43+
44+
throw new JsonException("Unexpected end of JSON.");
2345
}
2446

2547
/// <inheritdoc />
26-
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
48+
public override void Write(Utf8JsonWriter writer, List<int> value, JsonSerializerOptions options)
2749
{
28-
if (value is List<int> list)
29-
{
30-
writer.WriteValue($"{{{string.Join(",", list)}}}");
31-
}
50+
writer.WriteStringValue($"{{{string.Join(",", value)}}}");
3251
}
3352
}
3453
}

Postgrest/Converters/RangeConverter.cs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,35 @@
11
using System;
22
using System.Text.RegularExpressions;
3-
using Newtonsoft.Json;
3+
using System.Text.Json;
4+
using System.Text.Json.Serialization;
45
using Supabase.Postgrest.Extensions;
56
using Supabase.Postgrest.Exceptions;
67

78
namespace Supabase.Postgrest.Converters
89
{
9-
1010
/// <summary>
11-
/// Used by Newtonsoft.Json to convert a C# range into a Postgrest range.
11+
/// Used by System.Text.Json to convert a C# range into a Postgrest range.
1212
/// </summary>
13-
internal class RangeConverter : JsonConverter
13+
internal class RangeConverter : JsonConverter<IntRange>
1414
{
15-
public override bool CanConvert(Type objectType)
15+
public override bool CanConvert(Type typeToConvert)
1616
{
17-
throw new NotImplementedException();
17+
return typeToConvert == typeof(IntRange);
1818
}
1919

20-
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
20+
public override IntRange? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
2121
{
22-
return reader.Value != null ? ParseIntRange(reader.Value.ToString()) : null;
22+
if (reader.TokenType == JsonTokenType.String)
23+
{
24+
string? value = reader.GetString();
25+
return value != null ? ParseIntRange(value) : null;
26+
}
27+
throw new JsonException("Expected string value for IntRange.");
2328
}
2429

25-
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
30+
public override void Write(Utf8JsonWriter writer, IntRange value, JsonSerializerOptions options)
2631
{
27-
if (value == null) return;
28-
29-
var val = (IntRange)value;
30-
writer.WriteValue(val.ToPostgresString());
32+
writer.WriteStringValue(value.ToPostgresString());
3133
}
3234

3335
public static IntRange ParseIntRange(string value)

0 commit comments

Comments
 (0)