Skip to content
This repository has been archived by the owner on Dec 18, 2023. It is now read-only.

Commit

Permalink
Merge pull request #52 from Du-z/ConversionTests
Browse files Browse the repository at this point in the history
  • Loading branch information
ProphetLamb authored Sep 22, 2022
2 parents 08fd347 + 96f9f64 commit 050cc65
Show file tree
Hide file tree
Showing 22 changed files with 854 additions and 331 deletions.
4 changes: 2 additions & 2 deletions src/Abstractions/Database.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace SurrealDB.Abstractions;
public interface IDatabase<TResponse>
: IDatabase
where TResponse : IResponse {

/// <summary>
/// Retrieves the current session information.
/// </summary>
Expand Down Expand Up @@ -154,7 +154,7 @@ public interface IDatabase {
/// Configures the client with all applicable settings.
/// </summary>
public Task Open(Config config, CancellationToken ct = default);

/// <summary>
/// Opens the connection to a Surreal database instance using the preconfigured configuration.
/// Configures the client with all applicable settings.
Expand Down
54 changes: 54 additions & 0 deletions src/Common/TimeZoneHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
namespace SurrealDB.Json;

public static class TimeZoneHelper {
private static Dictionary<TimeSpan, TimeZoneInfo>? s_cacheTz;
private static readonly object s_cacheTzLock = new();

private static IReadOnlyDictionary<TimeSpan, TimeZoneInfo> GetTimeZones() {
Dictionary<TimeSpan, TimeZoneInfo> cache;
lock (s_cacheTzLock) {
cache = EnsureTzCacheUnchecked();
}

return cache;
}

private static Dictionary<TimeSpan, TimeZoneInfo> EnsureTzCacheUnchecked() {
Dictionary<TimeSpan, TimeZoneInfo>? cache = s_cacheTz;
if (cache is null || cache.Count <= 0) {
cache = TimeZoneInfo.GetSystemTimeZones().ToDictionary(static tz => tz.BaseUtcOffset);
s_cacheTz = cache;
}

return cache;
}

private static TimeZoneInfo AddTimeZone(string name, in TimeSpan off) {
lock (s_cacheTzLock) {
Dictionary<TimeSpan, TimeZoneInfo> cache = EnsureTzCacheUnchecked();
if (cache.TryGetValue(off, out TimeZoneInfo? tz)) {
return tz;
}
tz = TimeZoneInfo.CreateCustomTimeZone(name, off, null, null, null, null, false);
cache[off] = tz;
return tz;
}
}

public static TimeZoneInfo FromOffset(in TimeSpan offset) {
return GetTimeZones().TryGetValue(offset, out TimeZoneInfo? tz) ? tz : AddTimeZone(offset.ToString(), in offset);
}

/// <summary>
/// Converts the <see cref="DateTime"/> to a <see cref="DateTimeOffset"/> by adding a offset.
/// </summary>
/// <remarks>
/// This method ignores the <see cref="DateTimeKind"/> property and assumes UTC time by setting <see cref="DateTimeKind.Unspecified"/>!
/// </remarks>
public static DateTimeOffset WithOffset(in this DateTime dt, in TimeSpan offset) {
if (dt.Kind != DateTimeKind.Unspecified) {
return new(new DateTime(dt.Ticks), offset);
}
return new(dt, offset);
}
}
3 changes: 3 additions & 0 deletions src/Json/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
using System.Text.Json;
using System.Text.Json.Serialization;

using SurrealDB.Json.Numbers;
using SurrealDB.Json.Time;

namespace SurrealDB.Json;

/// <summary>
Expand Down
5 changes: 5 additions & 0 deletions src/Json/Json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Superpower" Version="3.0.0" />
<PackageReference Include="Rustic.Common" Version="0.5.80" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Common\Common.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace SurrealDB.Json;
namespace SurrealDB.Json.Numbers;

public sealed class DecimalConv : JsonConverter<decimal> {
public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
Expand Down
2 changes: 1 addition & 1 deletion src/Json/DoubleConv.cs → src/Json/Numbers/DoubleConv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace SurrealDB.Json;
namespace SurrealDB.Json.Numbers;

public sealed class DoubleConv : JsonConverter<double> {
public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
Expand Down
92 changes: 92 additions & 0 deletions src/Json/Numbers/NumberParsers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System.Globalization;

namespace SurrealDB.Json.Numbers;

internal static class SpecialNumbers {
public static string NaN { get; } = NumberFormatInfo.InvariantInfo.NaNSymbol;
public static string PosinfInv { get; } = NumberFormatInfo.InvariantInfo.PositiveInfinitySymbol;
public static string NeginfInv { get; } = NumberFormatInfo.InvariantInfo.NegativeInfinitySymbol;
public static string PosinfCur { get; } = NumberFormatInfo.CurrentInfo.PositiveInfinitySymbol;
public static string NeginfCur { get; } = NumberFormatInfo.CurrentInfo.NegativeInfinitySymbol;
public static string Posinf => "∞"; // &infin;
public static string Neginf => "−∞"; // &minus;&infin;

private static bool IsNegInf(string special) {
return special.Equals(Neginf, StringComparison.OrdinalIgnoreCase) || special.Equals(NeginfCur, StringComparison.OrdinalIgnoreCase) || special.Equals(NeginfInv, StringComparison.OrdinalIgnoreCase);
}

private static bool IsPosInf(string special) {
return special.Equals(Posinf, StringComparison.OrdinalIgnoreCase) || special.Equals(PosinfCur, StringComparison.OrdinalIgnoreCase) || special.Equals(PosinfInv, StringComparison.OrdinalIgnoreCase);
}

public static float ToSingle(string special) {
if (special.Equals(NaN, StringComparison.OrdinalIgnoreCase)) {
return Single.NaN;
}

if (IsPosInf(special)) {
return Single.PositiveInfinity;
}

if (IsNegInf(special)) {
return Single.NegativeInfinity;
}

return default;
}

public static string? ToSpecial(in float value) {
if (Single.IsNaN(value)) {
return NaN;
}

if (Single.IsPositiveInfinity(value)) {
return Posinf;
}

if (Single.IsNegativeInfinity(value)) {
return Neginf;
}

return null;
}

public static double ToDouble(string special) {
if (special.Equals(NaN, StringComparison.OrdinalIgnoreCase)) {
return Double.NaN;
}

if (IsPosInf(special)) {
return Double.PositiveInfinity;
}

if (IsNegInf(special)) {
return Double.NegativeInfinity;
}

return default;
}

public static string? ToSpecial(in double value) {
if (Double.IsNaN(value)) {
return NaN;
}

if (Double.IsPositiveInfinity(value)) {
return Posinf;
}

if (Double.IsNegativeInfinity(value)) {
return Neginf;
}

return null;
}

public static decimal ToDecimal(string str) {
return default;
}
public static string? ToSpecial(in decimal value) {
return null;
}
}
2 changes: 1 addition & 1 deletion src/Json/SingleConv.cs → src/Json/Numbers/SingleConv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace SurrealDB.Json;
namespace SurrealDB.Json.Numbers;

public sealed class SingleConv : JsonConverter<float> {
public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
Expand Down
68 changes: 0 additions & 68 deletions src/Json/SpecialNumbers.cs

This file was deleted.

45 changes: 19 additions & 26 deletions src/Json/DateOnlyConv.cs → src/Json/Time/DateOnlyConv.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

using Rustic;
using Superpower;
using Superpower.Model;

namespace SurrealDB.Json;
namespace SurrealDB.Json.Time;

public sealed class DateOnlyConv : JsonConverter<DateOnly> {
public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
Expand All @@ -28,34 +28,27 @@ public override void WriteAsPropertyName(Utf8JsonWriter writer, DateOnly value,
writer.WritePropertyName(ToString(in value));
}

public static DateOnly Parse(in ReadOnlySpan<char> str) {
ReadOnlySpan<char> slc, rem = str;
slc = rem.Slice(0, 4);
rem = rem.Slice(4);
int y = Int32.Parse(slc, NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
slc = rem.Slice(1, 2);
rem = rem.Slice(3);
int m = Int32.Parse(slc, NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
slc = rem.Slice(1, 2);
int d = Int32.Parse(slc, NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
return new(y, m , d);
public static DateOnly Parse(string? s) {
return TryParse(s, out DateOnly value) ? value : ThrowParseInvalid(s);
}

// Needs 10 chars
public static void ToString(ref StrBuilder builder, in DateOnly dt) {
dt.Year.TryFormat(builder.AppendSpan(4), out _, "0000", NumberFormatInfo.InvariantInfo);
builder.Append('-');
dt.Month.TryFormat(builder.AppendSpan(2), out _, "00", NumberFormatInfo.InvariantInfo);
builder.Append('-');
dt.Day.TryFormat(builder.AppendSpan(2), out _, "00", NumberFormatInfo.InvariantInfo);
public static bool TryParse(string? s, out DateOnly value) {
if (String.IsNullOrEmpty(s)) {
return false;
}
Result<DateOnly> res = TimeParsers.IsoDate(new TextSpan(s));
value = res.HasValue ? res.Value : default;
return res.HasValue;
}

public static string ToString(in DateOnly dt) {
StrBuilder builder = new(stackalloc char[11]);
ToString(ref builder, dt);
return builder.ToString();
public static string ToString(in DateOnly value) {
return $"{value.Year.ToString("D4")}-{value.Month.ToString("D2")}-{value.Day.ToString("D2")}";
}

[DoesNotReturn]
private static DateOnly ThrowParseInvalid(string? s) {
throw new ParseException($"Unable to parse DateOnly from `{s}`");
}

[DoesNotReturn]
private DateOnly ThrowJsonTokenTypeInvalid() {
throw new JsonException("Cannot deserialize a non string token as a DateOnly.");
Expand Down
Loading

0 comments on commit 050cc65

Please sign in to comment.