Skip to content

Commit

Permalink
Merge pull request #131 from fauna/all-the-typed-deserializers
Browse files Browse the repository at this point in the history
All the typed deserializers
  • Loading branch information
pnwpedro authored Jul 5, 2024
2 parents cfdacb6 + 7e9331e commit 5bfb383
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 30 deletions.
8 changes: 8 additions & 0 deletions Fauna.Test/Serialization/Deserializer.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Fauna.Test.Serialization;
public class DeserializerTests
{
private readonly MappingContext ctx;
private const string DocumentWithShortWire = @"{""@doc"":{""id"":""123"",""coll"":{""@mod"":""MyColl""},""ts"":{""@time"":""2023-12-15T01:01:01.0010010Z""},""a_short"":{""@int"":""42""}}}";

public DeserializerTests()
{
Expand Down Expand Up @@ -317,6 +318,13 @@ public void DeserializeDocumentGeneric()
Assert.AreEqual("name_value", actual["name"]);
}

[Test]
public void DeserializeDocumentAsClassWithShort()
{
var actual = Deserialize<ClassWithShort>(DocumentWithShortWire);
Assert.AreEqual((short)42, actual.AShort);
}

[Test]
public void DeserializeNonNullDocumentGeneric()
{
Expand Down
54 changes: 54 additions & 0 deletions Fauna.Test/Serialization/RoundTrip.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,18 @@ public class RoundTripTests
private const string LongWire = @"{""@long"":""42""}";
private const string DoubleWire = @"{""@double"":""42""}";
private const string DoubleWithDecimalWire = @"{""@double"":""42.2""}";
private const string TrueWire = "true";
private const string FalseWire = "false";
private const string DateTimeWire = @"{""@time"":""2023-12-15T01:01:01.0010011Z""}";
private const string DateWire = @"{""@date"":""2023-12-15""}";
private const string ModuleWire = @"{""@mod"":""Foo""}";
private const string DocumentWire = @"{""@doc"":{""id"":""123"",""coll"":{""@mod"":""MyColl""},""ts"":{""@time"":""2023-12-15T01:01:01.0010010Z""},""user_field"":""user_value""}}";
private const string DocumentRefWire = @"{""@ref"":{""id"":""123"",""coll"":{""@mod"":""MyColl""}}}";
private const string NullDocumentWire = @"{""@ref"":{""id"":""123"",""coll"":{""@mod"":""MyColl""},""exists"":false,""cause"":""not found""}}";
private const string NamedDocumentWire = @"{""@doc"":{""name"":""Foo"",""coll"":{""@mod"":""MyColl""},""ts"":{""@time"":""2023-12-15T01:01:01.0010010Z""},""user_field"":""user_value""}}";
private const string NullNamedDocumentWire = @"{""@ref"":{""name"":""Foo"",""coll"":{""@mod"":""MyColl""},""exists"":false,""cause"":""not found""}}";
private const string NamedDocumentRefWire = @"{""@ref"":{""name"":""Foo"",""coll"":{""@mod"":""MyColl""}}}";
private const string ObjectWithShortWire = @"{""a_short"":{""@int"":""42""}}";

public static string Serialize(object? obj)
{
Expand Down Expand Up @@ -115,6 +121,54 @@ public void RoundTripDouble()
Assert.AreEqual(DoubleWithDecimalWire, serialized);
}

[Test]
public void RoundTripTrue()
{
var deserialized = Deserialize<bool>(TrueWire);
var serialized = Serialize(deserialized);
Assert.AreEqual(TrueWire, serialized);
}

[Test]
public void RoundTripFalse()
{
var deserialized = Deserialize<bool>(FalseWire);
var serialized = Serialize(deserialized);
Assert.AreEqual(FalseWire, serialized);
}

[Test]
public void RoundTripDateTime()
{
var deserialized = Deserialize<DateTime>(DateTimeWire);
var serialized = Serialize(deserialized);
Assert.AreEqual(DateTimeWire, serialized);
}

[Test]
public void RoundTripDateOnly()
{
var deserialized = Deserialize<DateOnly>(DateWire);
var serialized = Serialize(deserialized);
Assert.AreEqual(DateWire, serialized);
}

[Test]
public void RoundTripModule()
{
var deserialized = Deserialize<Module>(ModuleWire);
var serialized = Serialize(deserialized);
Assert.AreEqual(ModuleWire, serialized);
}

[Test]
public void RoundTripClassWithShort()
{
var deserialized = Deserialize<ClassWithShort>(ObjectWithShortWire);
var serialized = Serialize(deserialized);
Assert.AreEqual(ObjectWithShortWire, serialized);
}

[Test]
public void RoundTripClassAsDocumentIsNotSupported()
{
Expand Down
6 changes: 6 additions & 0 deletions Fauna.Test/Serialization/TestClasses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ class ClassForDocument
[Field("user_field")] public string? UserField { get; set; }
}

[Object]
class ClassWithShort
{
[Field("a_short")] public short AShort { get; set; }
}

[Object]
class ClassForDocumentWithIdString
{
Expand Down
4 changes: 2 additions & 2 deletions Fauna/Linq/Deserializers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ public ProjectionDeserializer(IEnumerable<IDeserializer> fields)
return values;
}

private SerializationException UnexpectedToken(TokenType tokenType) =>
new SerializationException($"Unexpected token while deserializing LINQ element: {tokenType}");
private new static SerializationException UnexpectedToken(TokenType tokenType) =>
new($"Unexpected token while deserializing LINQ element: {tokenType}");
}
5 changes: 4 additions & 1 deletion Fauna/Mapping/FieldInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ internal IDeserializer Deserializer
if (_deserializer is null)
{
_deserializer = Fauna.Serialization.Deserializer.Generate(_ctx, Type);
if (IsNullable && _deserializer.GetType().GetGenericTypeDefinition() != typeof(NullableStructDeserializer<>))
if (IsNullable && (!_deserializer.GetType().IsGenericType ||
(_deserializer.GetType().IsGenericType &&
_deserializer.GetType().GetGenericTypeDefinition() !=
typeof(NullableStructDeserializer<>))))
{
var deserType = typeof(NullableDeserializer<>).MakeGenericType(new[] { Type });
var deser = Activator.CreateInstance(deserType, new[] { _deserializer });
Expand Down
5 changes: 2 additions & 3 deletions Fauna/Serialization/ClassDeserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ private void TrySetName(object instance, string name)
}
}

private SerializationException UnexpectedToken(TokenType tokenType) =>
new SerializationException(
$"Unexpected token while deserializing into class {_info.Type.Name}: {tokenType}");
private new SerializationException UnexpectedToken(TokenType tokenType) =>
new($"Unexpected token while deserializing into class {_info.Type.Name}: {tokenType}");
}
12 changes: 6 additions & 6 deletions Fauna/Serialization/Deserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ public static class Deserializer
/// <summary>
/// The dynamic data deserializer.
/// </summary>
public static IDeserializer<object?> Dynamic { get; } = DynamicDeserializer.Singleton;
public static IDeserializer<object?> Dynamic => DynamicDeserializer.Singleton;

private static readonly CheckedDeserializer<object> _object = new();
private static readonly CheckedDeserializer<string> _string = new();
private static readonly StringDeserializer _string = new();
private static readonly ByteDeserializer _byte = new();
private static readonly SByteDeserializer _sbyte = new();
private static readonly ShortDeserializer _short = new();
Expand All @@ -24,10 +24,10 @@ public static class Deserializer
private static readonly LongDeserializer _long = new();
private static readonly FloatDeserializer _float = new();
private static readonly DoubleDeserializer _double = new();
private static readonly CheckedDeserializer<DateOnly> _dateOnly = new();
private static readonly CheckedDeserializer<DateTime> _dateTime = new();
private static readonly CheckedDeserializer<bool> _bool = new();
private static readonly CheckedDeserializer<Module> _module = new();
private static readonly DateOnlyDeserializer _dateOnly = new();
private static readonly DateTimeDeserializer _dateTime = new();
private static readonly BooleanDeserializer _bool = new();
private static readonly ModuleDeserializer _module = new();
private static readonly DocumentDeserializer<Document> _doc = new();
private static readonly DocumentDeserializer<NamedDocument> _namedDoc = new();
private static readonly DocumentDeserializer<DocumentRef> _docRef = new();
Expand Down
3 changes: 3 additions & 0 deletions Fauna/Serialization/IDeserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ public abstract class BaseDeserializer<T> : IDeserializer<T>
Deserialize(context, ref reader);

public abstract T Deserialize(MappingContext context, ref Utf8FaunaReader reader);

protected static SerializationException UnexpectedToken(TokenType token) =>
new($"Unexpected token while deserializing: {token}");
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
using Fauna.Mapping;
using Fauna.Types;

namespace Fauna.Serialization;


internal class StringDeserializer : BaseDeserializer<string?>
{
public override string? Deserialize(MappingContext ctx, ref Utf8FaunaReader reader) =>
reader.CurrentTokenType switch
{
TokenType.String => reader.GetString(),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

internal class ByteDeserializer : BaseDeserializer<byte>
{
public override byte Deserialize(MappingContext context, ref Utf8FaunaReader reader) =>
reader.CurrentTokenType switch
{
TokenType.Int => reader.GetByte(),
_ => throw new SerializationException(
$"Unexpected token while deserializing: {reader.CurrentTokenType}"),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

Expand All @@ -20,8 +30,7 @@ public override sbyte Deserialize(MappingContext context, ref Utf8FaunaReader re
reader.CurrentTokenType switch
{
TokenType.Int => reader.GetUnsignedByte(),
_ => throw new SerializationException(
$"Unexpected token while deserializing: {reader.CurrentTokenType}"),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

Expand All @@ -32,8 +41,7 @@ public override short Deserialize(MappingContext context, ref Utf8FaunaReader re
reader.CurrentTokenType switch
{
TokenType.Int or TokenType.Long => reader.GetShort(),
_ => throw new SerializationException(
$"Unexpected token while deserializing: {reader.CurrentTokenType}"),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

Expand All @@ -43,8 +51,7 @@ public override ushort Deserialize(MappingContext context, ref Utf8FaunaReader r
reader.CurrentTokenType switch
{
TokenType.Int or TokenType.Long => reader.GetUnsignedShort(),
_ => throw new SerializationException(
$"Unexpected token while deserializing: {reader.CurrentTokenType}"),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

Expand All @@ -54,8 +61,7 @@ public override int Deserialize(MappingContext context, ref Utf8FaunaReader read
reader.CurrentTokenType switch
{
TokenType.Int or TokenType.Long => reader.GetInt(),
_ => throw new SerializationException(
$"Unexpected token while deserializing: {reader.CurrentTokenType}"),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

Expand All @@ -65,8 +71,7 @@ public override uint Deserialize(MappingContext context, ref Utf8FaunaReader rea
reader.CurrentTokenType switch
{
TokenType.Int or TokenType.Long => reader.GetUnsignedInt(),
_ => throw new SerializationException(
$"Unexpected token while deserializing: {reader.CurrentTokenType}"),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

Expand All @@ -76,8 +81,7 @@ public override long Deserialize(MappingContext context, ref Utf8FaunaReader rea
reader.CurrentTokenType switch
{
TokenType.Int or TokenType.Long => reader.GetLong(),
_ => throw new SerializationException(
$"Unexpected token while deserializing: {reader.CurrentTokenType}"),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

Expand All @@ -87,8 +91,7 @@ public override float Deserialize(MappingContext context, ref Utf8FaunaReader re
reader.CurrentTokenType switch
{
TokenType.Int or TokenType.Long or TokenType.Double => reader.GetFloat(),
_ => throw new SerializationException(
$"Unexpected token while deserializing: {reader.CurrentTokenType}"),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

Expand All @@ -98,7 +101,46 @@ public override double Deserialize(MappingContext context, ref Utf8FaunaReader r
reader.CurrentTokenType switch
{
TokenType.Int or TokenType.Long or TokenType.Double => reader.GetDouble(),
_ => throw new SerializationException(
$"Unexpected token while deserializing: {reader.CurrentTokenType}"),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

internal class BooleanDeserializer : BaseDeserializer<bool>
{
public override bool Deserialize(MappingContext context, ref Utf8FaunaReader reader) =>
reader.CurrentTokenType switch
{
TokenType.True or TokenType.False => reader.GetBoolean(),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

internal class DateOnlyDeserializer : BaseDeserializer<DateOnly>
{
public override DateOnly Deserialize(MappingContext context, ref Utf8FaunaReader reader) =>
reader.CurrentTokenType switch
{
TokenType.Date => reader.GetDate(),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

internal class DateTimeDeserializer : BaseDeserializer<DateTime>
{
public override DateTime Deserialize(MappingContext context, ref Utf8FaunaReader reader) =>
reader.CurrentTokenType switch
{
TokenType.Time => reader.GetTime(),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

internal class ModuleDeserializer : BaseDeserializer<Module>
{
public override Module Deserialize(MappingContext context, ref Utf8FaunaReader reader) =>
reader.CurrentTokenType switch
{
TokenType.Module => reader.GetModule(),
_ => throw UnexpectedToken(reader.CurrentTokenType)
};
}

0 comments on commit 5bfb383

Please sign in to comment.