Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support DateOnly / TimeOnly in DynamoDBContext #3677

Merged
merged 4 commits into from
Mar 5, 2025
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add support for DateOnly / TimeOnly in DynamoDbContext
  • Loading branch information
Dreamescaper committed Feb 27, 2025
commit da0ecafa93e8da87d838c024cda63433aec9777e
Original file line number Diff line number Diff line change
@@ -322,7 +322,7 @@ public bool TryConvertFromEntry([DynamicallyAccessedMembers(DynamicallyAccessedM
return converter.TryFromEntry(entry, outputType, out value);
}

#endregion
#endregion

#region Internal members

@@ -378,7 +378,7 @@ internal PrimitiveList ItemsToPrimitiveList(IEnumerable items)
return pl;
}

#endregion
#endregion

#region Private members

@@ -413,6 +413,10 @@ private void SetV1Converters()
AddConverter(new BoolConverterV1());
AddConverter(new PrimitiveCollectionConverterV1());
AddConverter(new DictionaryConverterV1());
#if NET8_0_OR_GREATER
AddConverter(new DateOnlyConverterV1());
AddConverter(new TimeOnlyConverterV1());
#endif
}

private void SetV2Converters()
@@ -438,6 +442,10 @@ private void SetV2Converters()
AddConverter(new EnumConverterV2());
AddConverter(new BoolConverterV2());
AddConverter(new CollectionConverterV2());
#if NET8_0_OR_GREATER
AddConverter(new DateOnlyConverterV2());
AddConverter(new TimeOnlyConverterV2());
#endif
}

// Converts items to Primitives.
50 changes: 47 additions & 3 deletions sdk/src/Services/DynamoDBv2/Custom/Conversion/SchemaV1.cs
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ internal class ByteConverterV1 : Converter<byte>
{
public override IEnumerable<Type> GetTargetTypes()
{
return new[] { typeof(byte), typeof(Nullable<byte>) };
return new[] { typeof(byte), typeof(Nullable<byte>) };
}

protected override bool TryTo(byte value, out Primitive p)
@@ -444,7 +444,51 @@ private static Enum ConvertEnum(string s, Type targetType)
}
}

#endregion
#if NET8_0_OR_GREATER
internal class DateOnlyConverterV1 : Converter<DateOnly>
{
private const string DateOnlyFormat = "yyyy-MM-dd";

public override IEnumerable<Type> GetTargetTypes()
{
return new[] { typeof(DateOnly), typeof(DateOnly?) };
}

protected override bool TryTo(DateOnly value, out Primitive p)
{
p = new Primitive(value.ToString(DateOnlyFormat, CultureInfo.InvariantCulture), DynamoDBEntryType.String);
return true;
}

protected override bool TryFrom(Primitive p, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors)] Type targetType, out DateOnly result)
{
return DateOnly.TryParseExact(p.StringValue, DateOnlyFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out result);
}
}

internal class TimeOnlyConverterV1 : Converter<TimeOnly>
{
private const string TimeOnlyFormat = "HH:mm:ss.fff";

public override IEnumerable<Type> GetTargetTypes()
{
return new[] { typeof(TimeOnly), typeof(TimeOnly?) };
}

protected override bool TryTo(TimeOnly value, out Primitive p)
{
p = new Primitive(value.ToString(TimeOnlyFormat, CultureInfo.InvariantCulture), DynamoDBEntryType.String);
return true;
}

protected override bool TryFrom(Primitive p, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors)] Type targetType, out TimeOnly result)
{
return TimeOnly.TryParseExact(p.StringValue, TimeOnlyFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out result);
}
}
#endif

#endregion

#region Converters supporting reading V2 DDB items, but writing V1 items

@@ -569,5 +613,5 @@ public override bool TryTo(object value, out Document d)
}
}

#endregion
#endregion
}
8 changes: 8 additions & 0 deletions sdk/src/Services/DynamoDBv2/Custom/Conversion/SchemaV2.cs
Original file line number Diff line number Diff line change
@@ -86,6 +86,14 @@ internal class DictionaryConverterV2 : DictionaryConverterV1
internal class EnumConverterV2 : EnumConverterV1
{ }

#if NET8_0_OR_GREATER
internal class DateOnlyConverterV2 : DateOnlyConverterV1
{ }

internal class TimeOnlyConverterV2 : TimeOnlyConverterV1
{ }
#endif

#endregion

/// <summary>
Original file line number Diff line number Diff line change
@@ -244,6 +244,46 @@ public void V2_ConvertToEntry_HashSet()
Assert.AreEqual(expectedList, entry);
}

#if NET8_0_OR_GREATER
[DataTestMethod]
[DynamicData((nameof(DynamoDBEntryConversions)))]
public void ConvertToEntry_DateOnly(DynamoDBEntryConversion conversion)
{
var dateTime = new DateOnly(2024, 07, 03);
var entry = conversion.ConvertToEntry(dateTime);
Assert.AreEqual(new Primitive("2024-07-03", false), entry);
}

[DataTestMethod]
[DynamicData((nameof(DynamoDBEntryConversions)))]
public void ConvertFromEntry_DateOnly(DynamoDBEntryConversion conversion)
{
var entry = new Primitive("2024-07-03", false);
var actualDateTime = conversion.ConvertFromEntry<DateOnly>(entry);
var expectedDateTime = new DateOnly(2024, 07, 03);
Assert.AreEqual(expectedDateTime, actualDateTime);
}

[DataTestMethod]
[DynamicData((nameof(DynamoDBEntryConversions)))]
public void ConvertToEntry_TimeOnly(DynamoDBEntryConversion conversion)
{
var dateTime = new TimeOnly(18, 31, 56, 123);
var entry = conversion.ConvertToEntry(dateTime);
Assert.AreEqual(new Primitive("18:31:56.123", false), entry);
}

[DataTestMethod]
[DynamicData((nameof(DynamoDBEntryConversions)))]
public void ConvertFromEntry_TimeOnly(DynamoDBEntryConversion conversion)
{
var entry = new Primitive("18:31:56.123", false);
var actualDateTime = conversion.ConvertFromEntry<TimeOnly>(entry);
var expectedDateTime = new TimeOnly(18, 31, 56, 123);
Assert.AreEqual(expectedDateTime, actualDateTime);
}
#endif

private void AssertAllConvertersAreRegistered(DynamoDBEntryConversion conversion, string suffix)
{
var converters = GetConverters(suffix);