diff --git a/Postgrest/Attributes/ColumnAttribute.cs b/Postgrest/Attributes/ColumnAttribute.cs
index 3cef106..1008f96 100644
--- a/Postgrest/Attributes/ColumnAttribute.cs
+++ b/Postgrest/Attributes/ColumnAttribute.cs
@@ -1,6 +1,6 @@
using System;
using System.Runtime.CompilerServices;
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace Supabase.Postgrest.Attributes
{
@@ -26,7 +26,7 @@ public class ColumnAttribute : Attribute
///
/// Specifies what should be serialized in the event this column's value is NULL
///
- public NullValueHandling NullValueHandling { get; set; }
+ public JsonIgnoreCondition NullValueHandling { get; set; }
///
/// If the performed query is an Insert or Upsert, should this value be ignored?
@@ -39,7 +39,7 @@ public class ColumnAttribute : Attribute
public bool IgnoreOnUpdate { get; }
///
- public ColumnAttribute([CallerMemberName] string? columnName = null, NullValueHandling nullValueHandling = NullValueHandling.Include, bool ignoreOnInsert = false, bool ignoreOnUpdate = false)
+ public ColumnAttribute([CallerMemberName] string? columnName = null, JsonIgnoreCondition nullValueHandling = JsonIgnoreCondition.Never, bool ignoreOnInsert = false, bool ignoreOnUpdate = false)
{
ColumnName = columnName!; // Will either be user specified or given by runtime compiler.
NullValueHandling = nullValueHandling;
diff --git a/Postgrest/Client.cs b/Postgrest/Client.cs
index e5ed0b3..380d59a 100644
--- a/Postgrest/Client.cs
+++ b/Postgrest/Client.cs
@@ -2,12 +2,15 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Converters;
+using System.Text.Json;
+using System.Text.Json.Serialization;
using Supabase.Core.Extensions;
using Supabase.Postgrest.Interfaces;
using Supabase.Postgrest.Models;
using Supabase.Postgrest.Responses;
+using System.Text.Json.Serialization.Metadata;
+using System.Reflection;
+using Supabase.Postgrest.Converters;
namespace Supabase.Postgrest
{
@@ -15,26 +18,23 @@ namespace Supabase.Postgrest
public class Client : IPostgrestClient
{
///
- /// Custom Serializer resolvers and converters that will be used for encoding and decoding Postgrest JSON responses.
+ /// Custom Serializer options that will be used for encoding and decoding Postgrest JSON responses.
///
- /// By default, Postgrest seems to use a date format that C# and Newtonsoft do not like, so this initial
+ /// By default, Postgrest seems to use a date format that C# does not like, so this initial
/// configuration handles that.
///
- public static JsonSerializerSettings SerializerSettings(ClientOptions? options = null)
+ public static JsonSerializerOptions SerializerOptions(ClientOptions? options = null)
{
options ??= new ClientOptions();
- return new JsonSerializerSettings
+ return new JsonSerializerOptions
{
- ContractResolver = new PostgrestContractResolver(),
+ PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
Converters =
{
- // 2020-08-28T12:01:54.763231
- new IsoDateTimeConverter
- {
- DateTimeStyles = options.DateTimeStyles,
- DateTimeFormat = ClientOptions.DATE_TIME_FORMAT
- }
+ new JsonStringEnumConverter(),
+ // new PostgrestDateTimeConverter(options.DateTimeStyles, ClientOptions.DATE_TIME_FORMAT)
+ new RangeConverter()
}
};
}
@@ -70,7 +70,7 @@ public void RemoveDebugHandler(IPostgrestDebugger.DebugEventHandler handler) =>
///
/// Function that can be set to return dynamic headers.
- ///
+ ///
/// Headers specified in the constructor options will ALWAYS take precedence over headers returned by this function.
///
public Func>? GetHeaders { get; set; }
@@ -87,10 +87,9 @@ public Client(string baseUrl, ClientOptions? options = null)
Options = options ?? new ClientOptions();
}
-
///
public IPostgrestTable Table() where T : BaseModel, new() =>
- new Table(BaseUrl, SerializerSettings(Options), Options)
+ new Table(BaseUrl, SerializerOptions(Options), Options)
{
GetHeaders = GetHeaders
};
@@ -98,18 +97,17 @@ public Client(string baseUrl, ClientOptions? options = null)
///
public IPostgrestTableWithCache Table(IPostgrestCacheProvider cacheProvider)
where T : BaseModel, new() =>
- new TableWithCache(BaseUrl, cacheProvider, SerializerSettings(Options), Options)
+ new TableWithCache(BaseUrl, cacheProvider, SerializerOptions(Options), Options)
{
GetHeaders = GetHeaders
};
-
///
public async Task Rpc(string procedureName, object? parameters = null)
{
var response = await Rpc(procedureName, parameters);
- return string.IsNullOrEmpty(response.Content) ? default : JsonConvert.DeserializeObject(response.Content!);
+ return string.IsNullOrEmpty(response.Content) ? default : JsonSerializer.Deserialize(response.Content!, SerializerOptions(Options));
}
///
@@ -120,13 +118,13 @@ public Task Rpc(string procedureName, object? parameters = null)
var canonicalUri = builder.Uri.ToString();
- var serializerSettings = SerializerSettings(Options);
+ var serializerOptions = SerializerOptions(Options);
// Prepare parameters
Dictionary? data = null;
if (parameters != null)
- data = JsonConvert.DeserializeObject>(
- JsonConvert.SerializeObject(parameters, serializerSettings));
+ data = JsonSerializer.Deserialize>(
+ JsonSerializer.Serialize(parameters, serializerOptions));
// Prepare headers
var headers = Helpers.PrepareRequestHeaders(HttpMethod.Post,
@@ -137,8 +135,8 @@ public Task Rpc(string procedureName, object? parameters = null)
// Send request
var request =
- Helpers.MakeRequest(Options, HttpMethod.Post, canonicalUri, serializerSettings, data, headers);
+ Helpers.MakeRequest(Options, HttpMethod.Post, canonicalUri, serializerOptions, data, headers);
return request;
}
}
-}
\ No newline at end of file
+}
diff --git a/Postgrest/Converters/DateTimeConverter.cs b/Postgrest/Converters/DateTimeConverter.cs
index 28aa3da..ea9a6d1 100644
--- a/Postgrest/Converters/DateTimeConverter.cs
+++ b/Postgrest/Converters/DateTimeConverter.cs
@@ -1,29 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
+using System.Text.Json;
+using System.Text.Json.Serialization;
namespace Supabase.Postgrest.Converters
{
///
- public class DateTimeConverter : JsonConverter
+ public class DateTimeConverter : JsonConverter
/// Api Endpoint (ex: "http://localhost:8000"), no trailing slash required.
- ///
+ ///
/// Optional client configuration.
- public Table(string baseUrl, JsonSerializerSettings serializerSettings, ClientOptions? options = null)
+ public Table(string baseUrl, JsonSerializerOptions serializerOptions, ClientOptions? options = null)
{
BaseUrl = baseUrl;
_options = options ?? new ClientOptions();
- _serializerSettings = serializerSettings;
+ _serializerOptions = serializerOptions;
foreach (var property in typeof(TModel).GetProperties())
{
@@ -134,7 +135,7 @@ public IPostgrestTable Filter(string columnName, Operator op
default:
throw new PostgrestException(
"NOT filters must use the `Equals`, `Is`, `Not` or `NotEqual` operators")
- { Reason = FailureHint.Reason.InvalidArgument };
+ { Reason = FailureHint.Reason.InvalidArgument };
}
return this;
@@ -518,8 +519,8 @@ public Task> Update(QueryOptions? options = null,
throw new ArgumentException("No data has been set to update, was `Set` called?");
_method = new HttpMethod("PATCH");
-
- var request = Send(_method, _setData, options.ToHeaders(), cancellationToken, isUpdate: true);
+ var data = (TModel)Convert.ChangeType(_setData, typeof(TModel));
+ var request = Send(_method, data, options.ToHeaders(), cancellationToken, isUpdate: true);
Clear();
@@ -552,7 +553,7 @@ public Task Delete(QueryOptions? options = null, CancellationToken cancellationT
_method = HttpMethod.Delete;
- var request = Send(_method, null, options.ToHeaders(), cancellationToken);
+ var request = Send(_method, null, options.ToHeaders(), cancellationToken);
Clear();
@@ -588,7 +589,7 @@ public async Task Count(CountType type, CancellationToken cancellationToken
{ "Prefer", $"count={attr?.Mapping}" }
};
- var request = Send(_method, null, headers, cancellationToken);
+ var request = Send(_method, null, headers, cancellationToken);
Clear();
var response = await request;
@@ -673,7 +674,7 @@ public string GenerateUrl()
var selector = !string.IsNullOrEmpty(orderer.ForeignTable)
? orderer.ForeignTable + "(" + orderer.Column + ")"
: orderer.Column;
-
+
order.Append($"{selector}.{orderingAttr.Mapping}.{nullPosAttr.Mapping}");
}
@@ -732,32 +733,30 @@ public string GenerateUrl()
}
///
- /// Transforms an object into a string mapped list/dictionary using `JsonSerializerSettings`.
+ /// Transforms an object into a string mapped list/dictionary using `JsonSerializerOptions`.
///
///
///
///
///
///
- private object? PrepareRequestData(object? data, bool isInsert = false, bool isUpdate = false,
+ private object? PrepareRequestData(T? data, bool isInsert = false, bool isUpdate = false,
bool isUpsert = false)
{
if (data == null) return new Dictionary();
+ var postgrestContractResolver = new PostgrestContractResolver();
+ postgrestContractResolver.SetState(isInsert, isUpdate, isUpsert);
+ var options = new JsonSerializerOptions(_serializerOptions);
+ options.Converters.Add(postgrestContractResolver);
- // Specified in constructor;
- var resolver = (PostgrestContractResolver)_serializerSettings.ContractResolver!;
-
- resolver.SetState(isInsert, isUpdate, isUpsert);
- var serialized = JsonConvert.SerializeObject(data, _serializerSettings);
-
- resolver.SetState();
+ var serialized = JsonSerializer.Serialize(data, options);
// Check if data is a Collection for the Insert Bulk case
if (data is ICollection)
- return JsonConvert.DeserializeObject>(serialized, _serializerSettings);
-
- return JsonConvert.DeserializeObject>(serialized, _serializerSettings);
+ return JsonSerializer.Deserialize>(serialized, options);
+ // TODO: resolve options causing test failures
+ return JsonSerializer.Deserialize>(serialized);
}
///
@@ -823,7 +822,7 @@ internal KeyValuePair PrepareFilter(IPostgrestQueryFilter filter
if (filter is { Criteria: IDictionary inDictCriteria, Property: not null })
{
return new KeyValuePair(filter.Property,
- $"{asAttribute.Mapping}.{JsonConvert.SerializeObject(inDictCriteria)}");
+ $"{asAttribute.Mapping}.{JsonSerializer.Serialize(inDictCriteria, _serializerOptions)}");
}
break;
@@ -833,16 +832,16 @@ internal KeyValuePair PrepareFilter(IPostgrestQueryFilter filter
switch (filter.Criteria)
{
case IList listCriteria when filter.Property != null:
- {
- foreach (var item in listCriteria)
- strBuilder.Append($"{item},");
+ {
+ foreach (var item in listCriteria)
+ strBuilder.Append($"{item},");
- return new KeyValuePair(filter.Property,
- $"{asAttribute.Mapping}.{{{strBuilder.ToString().Trim(',')}}}");
- }
+ return new KeyValuePair(filter.Property,
+ $"{asAttribute.Mapping}.{{{strBuilder.ToString().Trim(',')}}}");
+ }
case IDictionary dictCriteria when filter.Property != null:
return new KeyValuePair(filter.Property,
- $"{asAttribute.Mapping}.{JsonConvert.SerializeObject(dictCriteria)}");
+ $"{asAttribute.Mapping}.{JsonSerializer.Serialize(dictCriteria, _serializerOptions)}");
case IntRange rangeCriteria when filter.Property != null:
return new KeyValuePair(filter.Property,
$"{asAttribute.Mapping}.{rangeCriteria.ToPostgresString()}");
@@ -919,8 +918,9 @@ private Task> PerformInsert(object data, QueryOptions? o
if (!string.IsNullOrEmpty(options.OnConflict))
OnConflict(options.OnConflict!);
+ var castData = (TModel)Convert.ChangeType(data, typeof(TModel));
- var request = Send(_method, data, options.ToHeaders(), cancellationToken, isInsert: true,
+ var request = Send(_method, castData, options.ToHeaders(), cancellationToken, isInsert: true,
isUpsert: options.Upsert);
Clear();
@@ -928,33 +928,33 @@ private Task> PerformInsert(object data, QueryOptions? o
return request;
}
- private Task Send(HttpMethod method, object? data, Dictionary? headers = null,
- CancellationToken cancellationToken = default, bool isInsert = false,
- bool isUpdate = false, bool isUpsert = false)
- {
- var requestHeaders = Helpers.PrepareRequestHeaders(method, headers, _options, _rangeFrom, _rangeTo);
+ // private Task Send(HttpMethod method, T? data, Dictionary? headers = null,
+ // CancellationToken cancellationToken = default, bool isInsert = false,
+ // bool isUpdate = false, bool isUpsert = false)
+ // {
+ // var requestHeaders = Helpers.PrepareRequestHeaders(method, headers, _options, _rangeFrom, _rangeTo);
- if (GetHeaders != null)
- {
- requestHeaders = GetHeaders().MergeLeft(requestHeaders);
- }
+ // if (GetHeaders != null)
+ // {
+ // requestHeaders = GetHeaders().MergeLeft(requestHeaders);
+ // }
- var url = GenerateUrl();
- var preparedData = PrepareRequestData(data, isInsert, isUpdate, isUpsert);
+ // var url = GenerateUrl();
+ // var preparedData = PrepareRequestData(data, isInsert, isUpdate, isUpsert);
- Hooks.Instance.NotifyOnRequestPreparedHandlers(this, _options, method, url, _serializerSettings,
- preparedData, requestHeaders);
+ // Hooks.Instance.NotifyOnRequestPreparedHandlers(this, _options, method, url, _serializerOptions,
+ // preparedData, requestHeaders);
- Debugger.Instance.Log(this,
- $"Request [{method}] at {DateTime.Now.ToLocalTime()}\n" +
- $"Headers:\n\t{JsonConvert.SerializeObject(requestHeaders)}\n" +
- $"Data:\n\t{JsonConvert.SerializeObject(preparedData)}");
+ // Debugger.Instance.Log(this,
+ // $"Request [{method}] at {DateTime.Now.ToLocalTime()}\n" +
+ // $"Headers:\n\t{JsonSerializer.Serialize(requestHeaders, _serializerOptions)}\n" +
+ // $"Data:\n\t{JsonSerializer.Serialize(preparedData, _serializerOptions)}");
- return Helpers.MakeRequest(_options, method, url, _serializerSettings, preparedData, requestHeaders,
- cancellationToken);
- }
+ // return Helpers.MakeRequest(_options, method, url, _serializerOptions, preparedData, requestHeaders,
+ // cancellationToken);
+ // }
- private Task> Send(HttpMethod method, object? data,
+ private Task> Send(HttpMethod method, TU? data,
Dictionary? headers = null, CancellationToken cancellationToken = default,
bool isInsert = false,
bool isUpdate = false, bool isUpsert = false) where TU : BaseModel, new()
@@ -965,17 +965,17 @@ private Task> Send(HttpMethod method, object? data,
requestHeaders = GetHeaders().MergeLeft(requestHeaders);
var url = GenerateUrl();
- var preparedData = PrepareRequestData(data, isInsert, isUpdate, isUpsert);
-
- Hooks.Instance.NotifyOnRequestPreparedHandlers(this, _options, method, url, _serializerSettings,
+ var preparedData = PrepareRequestData(data, isInsert, isUpdate, isUpsert);
+ // var preparedData = data;
+ Hooks.Instance.NotifyOnRequestPreparedHandlers(this, _options, method, url, _serializerOptions,
preparedData, requestHeaders);
Debugger.Instance.Log(this,
$"Request [{method}] at {DateTime.Now.ToLocalTime()}\n" +
- $"Headers:\n\t{JsonConvert.SerializeObject(requestHeaders)}\n" +
- $"Data:\n\t{JsonConvert.SerializeObject(preparedData)}");
+ $"Headers:\n\t{JsonSerializer.Serialize(requestHeaders, _serializerOptions)}\n" +
+ $"Data:\n\t{JsonSerializer.Serialize(preparedData, _serializerOptions)}");
- return Helpers.MakeRequest(_options, method, url, _serializerSettings, preparedData, requestHeaders,
+ return Helpers.MakeRequest(_options, method, url, _serializerOptions, preparedData, requestHeaders,
GetHeaders, cancellationToken);
}
@@ -992,4 +992,4 @@ private static string FindTableName(object? obj = null)
return type.Name;
}
}
-}
\ No newline at end of file
+}
diff --git a/Postgrest/TableWithCache.cs b/Postgrest/TableWithCache.cs
index 284f741..41885cc 100644
--- a/Postgrest/TableWithCache.cs
+++ b/Postgrest/TableWithCache.cs
@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
-using Newtonsoft.Json;
+using System.Text.Json;
using Supabase.Postgrest.Interfaces;
using Supabase.Postgrest.Models;
using Supabase.Postgrest.Requests;
@@ -22,14 +22,14 @@ namespace Supabase.Postgrest
///
public TableWithCache(string baseUrl, IPostgrestCacheProvider cacheProvider,
- JsonSerializerSettings serializerSettings, ClientOptions? options = null)
- : base(baseUrl, serializerSettings, options)
+ JsonSerializerOptions serializerOptions, ClientOptions? options = null)
+ : base(baseUrl, serializerOptions, options)
{
CacheProvider = cacheProvider;
}
///
- ///
+ ///
///
///
///
@@ -45,4 +45,4 @@ public TableWithCache(string baseUrl, IPostgrestCacheProvider cacheProvider,
return cacheModel;
}
}
-}
\ No newline at end of file
+}
diff --git a/PostgrestTests/ClientTests.cs b/PostgrestTests/ClientTests.cs
index 47bd4c6..283a353 100644
--- a/PostgrestTests/ClientTests.cs
+++ b/PostgrestTests/ClientTests.cs
@@ -13,6 +13,7 @@
using Supabase.Postgrest.Responses;
using PostgrestTests.Models;
using static Supabase.Postgrest.Constants;
+using System.Text.Json;
namespace PostgrestTests
{
@@ -1051,7 +1052,10 @@ public async Task TestSupportIntArraysAsLists()
.Insert(
new User
{
- Username = "WALRUS", Status = "ONLINE", Catchphrase = "I'm a walrus", FavoriteNumbers = numbers,
+ Username = "WALRUS",
+ Status = "ONLINE",
+ Catchphrase = "I'm a walrus",
+ FavoriteNumbers = numbers,
AgeRange = new IntRange(15, 25)
}, new QueryOptions { Upsert = true });
@@ -1061,17 +1065,17 @@ public async Task TestSupportIntArraysAsLists()
[TestMethod("stored procedure")]
public async Task TestStoredProcedure()
{
- //Arrange
+ //Arrange
var client = new Client(BaseUrl);
- //Act
+ //Act
var parameters = new Dictionary
{
{ "name_param", "supabot" }
};
var response = await client.Rpc("get_status", parameters);
- //Assert
+ //Assert
Assert.AreEqual(true, response.ResponseMessage?.IsSuccessStatusCode);
Assert.AreEqual(true, response.Content?.Contains("OFFLINE"));
}
@@ -1079,10 +1083,10 @@ public async Task TestStoredProcedure()
[TestMethod("stored procedure with row param")]
public async Task TestStoredProcedureWithRowParam()
{
- //Arrange
+ //Arrange
var client = new Client(BaseUrl);
- //Act
+ //Act
var parameters = new Dictionary
{
{
@@ -1095,7 +1099,7 @@ public async Task TestStoredProcedureWithRowParam()
};
var response = await client.Rpc("get_data", parameters);
- //Assert
+ //Assert
Assert.AreEqual(true, response.ResponseMessage?.IsSuccessStatusCode);
Assert.AreEqual("null", response.Content);
}
@@ -1111,10 +1115,10 @@ public async Task TestSwitchSchema()
};
var client = new Client(BaseUrl, options);
- //Act
+ //Act
var response = await client.Table().Filter(x => x.Username!, Operator.Equals, "leroyjenkins").Get();
- //Assert
+ //Assert
Assert.AreEqual(1, response.Models.Count);
Assert.AreEqual("leroyjenkins", response.Models.FirstOrDefault()?.Username);
}
@@ -1195,4 +1199,4 @@ public async Task TestOnRequestPreparedEvent()
Assert.IsTrue(timer1.ElapsedTicks < timer2.ElapsedTicks);
}
}
-}
\ No newline at end of file
+}
diff --git a/PostgrestTests/LinqTests.cs b/PostgrestTests/LinqTests.cs
index d65eba8..c8e8f1d 100644
--- a/PostgrestTests/LinqTests.cs
+++ b/PostgrestTests/LinqTests.cs
@@ -407,4 +407,4 @@ public async Task TestLinqQueryFilter()
}
}
}
-}
\ No newline at end of file
+}
diff --git a/PostgrestTests/Models/KitchenSink.cs b/PostgrestTests/Models/KitchenSink.cs
index e3031bb..805ddd4 100644
--- a/PostgrestTests/Models/KitchenSink.cs
+++ b/PostgrestTests/Models/KitchenSink.cs
@@ -1,7 +1,7 @@
#nullable enable
using System;
using System.Collections.Generic;
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
using Supabase.Postgrest;
using Supabase.Postgrest.Attributes;
using Supabase.Postgrest.Models;
@@ -27,18 +27,22 @@ public class KitchenSink : BaseModel
[Column("datetime_value")] public DateTime? DateTimeValue { get; set; }
- [Column("datetime_value_1", NullValueHandling = NullValueHandling.Ignore)]
+ [Column("datetime_value_1")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public DateTime? DateTimeValue1 { get; set; }
- [Column("datetime_pos_infinite_value", NullValueHandling = NullValueHandling.Ignore)]
+ [Column("datetime_pos_infinite_value")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public DateTime? DateTimePosInfinity { get; set; }
- [Column("datetime_neg_infinite_value", NullValueHandling = NullValueHandling.Ignore)]
+ [Column("datetime_neg_infinite_value")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public DateTime? DateTimeNegInfinity { get; set; }
[Column("list_of_strings")] public List? ListOfStrings { get; set; }
- [Column("list_of_datetimes", NullValueHandling = NullValueHandling.Ignore)]
+ [Column("list_of_datetimes")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List? ListOfDateTimes { get; set; }
[Column("list_of_ints")] public List? ListOfInts { get; set; }
@@ -49,4 +53,4 @@ public class KitchenSink : BaseModel
[Column("uuidv4")] public Guid? Uuidv4 { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/PostgrestTests/Models/User.cs b/PostgrestTests/Models/User.cs
index e61a1c6..58ca509 100644
--- a/PostgrestTests/Models/User.cs
+++ b/PostgrestTests/Models/User.cs
@@ -17,7 +17,7 @@ public class User : BaseModel
[Column("favorite_numbers")]
public List? FavoriteNumbers { get; set; }
-
+
[Column("favorite_name")]
public string? FavoriteName { get; set; }