Skip to content

Commit a9d69c3

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

20 files changed

+463
-303
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 DateTimeConverter(),
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+
}
Lines changed: 82 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,75 @@
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(DateTime?) ||
16+
typeToConvert == typeof(List<DateTime>) || typeToConvert == typeof(List<DateTime?>);
1617
}
1718

1819
/// <inheritdoc />
19-
public override bool CanWrite => false;
20-
21-
/// <inheritdoc />
22-
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
20+
public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
2321
{
24-
if (reader.Value != null)
22+
if (reader.TokenType == JsonTokenType.Null)
2523
{
26-
var str = reader.Value.ToString();
27-
28-
var infinity = ParseInfinity(str);
24+
return null;
25+
}
2926

30-
if (infinity != null)
27+
if (reader.TokenType == JsonTokenType.String)
28+
{
29+
var str = reader.GetString();
30+
if (string.IsNullOrEmpty(str))
3131
{
32-
return (DateTime)infinity;
32+
return null;
3333
}
3434

35-
var date = DateTime.Parse(str);
36-
return date;
35+
var infinity = ParseInfinity(str);
36+
return infinity ?? 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.Null)
51+
{
52+
result.Add(null);
53+
}
54+
else if (reader.TokenType == JsonTokenType.String)
55+
{
56+
var inner = reader.GetString();
57+
if (string.IsNullOrEmpty(inner))
58+
{
59+
result.Add(null);
60+
}
61+
else
62+
{
63+
var infinity = ParseInfinity(inner);
64+
result.Add(infinity ?? DateTime.Parse(inner));
65+
}
66+
}
5867
}
59-
}
60-
catch (JsonReaderException)
61-
{
62-
return null;
63-
}
6468

69+
return result;
70+
}
6571

66-
return result;
72+
return null;
6773
}
6874

6975
private static DateTime? ParseInfinity(string input)
@@ -77,9 +83,47 @@ public override bool CanConvert(Type objectType)
7783
}
7884

7985
/// <inheritdoc />
80-
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
86+
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
8187
{
82-
throw new NotImplementedException();
88+
if (value is DateTime dateTime)
89+
{
90+
if (dateTime == DateTime.MinValue)
91+
{
92+
writer.WriteStringValue("-infinity");
93+
}
94+
else if (dateTime == DateTime.MaxValue)
95+
{
96+
writer.WriteStringValue("infinity");
97+
}
98+
else
99+
{
100+
writer.WriteStringValue(dateTime.ToString("O"));
101+
}
102+
}
103+
else if (value is List<DateTime> dateTimeList)
104+
{
105+
writer.WriteStartArray();
106+
foreach (var dt in dateTimeList)
107+
{
108+
if (dt == DateTime.MinValue)
109+
{
110+
writer.WriteStringValue("-infinity");
111+
}
112+
else if (dt == DateTime.MaxValue)
113+
{
114+
writer.WriteStringValue("infinity");
115+
}
116+
else
117+
{
118+
writer.WriteStringValue(dt.ToString("O"));
119+
}
120+
}
121+
writer.WriteEndArray();
122+
}
123+
else
124+
{
125+
throw new JsonException("Unsupported value type for DateTimeConverter.");
126+
}
83127
}
84128
}
85129
}

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
}

0 commit comments

Comments
 (0)