Skip to content

Commit 73be31d

Browse files
authored
Added support for LocalDate/LocalDateTime/LocalTime to Strawberry Shake (#8007)
1 parent fbfa821 commit 73be31d

File tree

141 files changed

+1574
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

141 files changed

+1574
-0
lines changed

src/StrawberryShake/Client/src/Core/Serialization/BuiltInScalarNames.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ public static class BuiltInScalarNames
2121
public const string Any = nameof(Any);
2222
public const string DateTime = nameof(DateTime);
2323
public const string Date = nameof(Date);
24+
public const string LocalDate = nameof(LocalDate);
25+
public const string LocalDateTime = nameof(LocalDateTime);
26+
public const string LocalTime = nameof(LocalTime);
2427
public const string TimeSpan = nameof(TimeSpan);
2528
public const string Name = nameof(Name);
2629
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using System.Globalization;
3+
4+
namespace StrawberryShake.Serialization;
5+
6+
/// <summary>
7+
/// This serializer handles <c>LocalDate</c> scalars.
8+
/// </summary>
9+
public class LocalDateSerializer : ScalarSerializer<string, DateOnly>
10+
{
11+
private const string _localFormat = "yyyy-MM-dd";
12+
13+
public LocalDateSerializer(string typeName = BuiltInScalarNames.LocalDate)
14+
: base(typeName)
15+
{
16+
}
17+
18+
public override DateOnly Parse(string serializedValue)
19+
{
20+
if (TryDeserializeFromString(serializedValue, out var date))
21+
{
22+
return date.Value;
23+
}
24+
25+
throw ThrowHelper.LocalDateSerializer_InvalidFormat(serializedValue);
26+
}
27+
28+
protected override string Format(DateOnly runtimeValue)
29+
{
30+
return runtimeValue.ToString(
31+
_localFormat,
32+
CultureInfo.InvariantCulture);
33+
}
34+
35+
private static bool TryDeserializeFromString(
36+
string? serialized,
37+
[NotNullWhen(true)] out DateOnly? value)
38+
{
39+
if (serialized is not null
40+
&& DateOnly.TryParseExact(
41+
serialized,
42+
_localFormat,
43+
CultureInfo.InvariantCulture,
44+
DateTimeStyles.None,
45+
out var date))
46+
{
47+
value = date;
48+
return true;
49+
}
50+
51+
value = null;
52+
return false;
53+
}
54+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using System.Globalization;
3+
4+
namespace StrawberryShake.Serialization;
5+
6+
/// <summary>
7+
/// This serializer handles <c>LocalDateTime</c> scalars.
8+
/// </summary>
9+
public class LocalDateTimeSerializer : ScalarSerializer<string, DateTime>
10+
{
11+
private const string _localFormat = "yyyy-MM-ddTHH\\:mm\\:ss";
12+
13+
public LocalDateTimeSerializer(string typeName = BuiltInScalarNames.LocalDateTime)
14+
: base(typeName)
15+
{
16+
}
17+
18+
public override DateTime Parse(string serializedValue)
19+
{
20+
if (TryDeserializeFromString(serializedValue, out var dateTime))
21+
{
22+
return dateTime.Value;
23+
}
24+
25+
throw ThrowHelper.LocalDateTimeSerializer_InvalidFormat(serializedValue);
26+
}
27+
28+
protected override string Format(DateTime runtimeValue)
29+
{
30+
return runtimeValue.ToString(
31+
_localFormat,
32+
CultureInfo.InvariantCulture);
33+
}
34+
35+
private static bool TryDeserializeFromString(
36+
string? serialized,
37+
[NotNullWhen(true)] out DateTime? value)
38+
{
39+
if (serialized is not null
40+
&& DateTime.TryParseExact(
41+
serialized,
42+
_localFormat,
43+
CultureInfo.InvariantCulture,
44+
DateTimeStyles.None,
45+
out var dt))
46+
{
47+
value = dt;
48+
return true;
49+
}
50+
51+
value = null;
52+
return false;
53+
}
54+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using System.Globalization;
3+
4+
namespace StrawberryShake.Serialization;
5+
6+
/// <summary>
7+
/// This serializer handles <c>LocalTime</c> scalars.
8+
/// </summary>
9+
public class LocalTimeSerializer : ScalarSerializer<string, TimeOnly>
10+
{
11+
private const string _localFormat = "HH:mm:ss";
12+
13+
public LocalTimeSerializer(string typeName = BuiltInScalarNames.LocalTime)
14+
: base(typeName)
15+
{
16+
}
17+
18+
public override TimeOnly Parse(string serializedValue)
19+
{
20+
if (TryDeserializeFromString(serializedValue, out var time))
21+
{
22+
return time.Value;
23+
}
24+
25+
throw ThrowHelper.LocalTimeSerializer_InvalidFormat(serializedValue);
26+
}
27+
28+
protected override string Format(TimeOnly runtimeValue)
29+
{
30+
return runtimeValue.ToString(
31+
_localFormat,
32+
CultureInfo.InvariantCulture);
33+
}
34+
35+
private static bool TryDeserializeFromString(
36+
string? serialized,
37+
[NotNullWhen(true)] out TimeOnly? value)
38+
{
39+
if (serialized is not null
40+
&& TimeOnly.TryParseExact(
41+
serialized,
42+
_localFormat,
43+
CultureInfo.InvariantCulture,
44+
DateTimeStyles.None,
45+
out var time))
46+
{
47+
value = time;
48+
return true;
49+
}
50+
51+
value = null;
52+
return false;
53+
}
54+
}

src/StrawberryShake/Client/src/Core/ThrowHelper.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,33 @@ internal static GraphQLClientException DateSerializer_InvalidFormat(
3434
{ "serializedValue", serializedValue },
3535
}));
3636

37+
internal static GraphQLClientException LocalDateSerializer_InvalidFormat(
38+
string serializedValue) =>
39+
new(new ClientError(
40+
"The serialized format for LocalDate must be `yyyy-MM-dd`.",
41+
extensions: new Dictionary<string, object?>
42+
{
43+
{ "serializedValue", serializedValue },
44+
}));
45+
46+
internal static GraphQLClientException LocalDateTimeSerializer_InvalidFormat(
47+
string serializedValue) =>
48+
new(new ClientError(
49+
"The serialized format for LocalDateTime must be `yyyy-MM-ddTHH:mm:ss`.",
50+
extensions: new Dictionary<string, object?>
51+
{
52+
{ "serializedValue", serializedValue },
53+
}));
54+
55+
internal static GraphQLClientException LocalTimeSerializer_InvalidFormat(
56+
string serializedValue) =>
57+
new(new ClientError(
58+
"The serialized format for LocalTime must be `HH:mm:ss`.",
59+
extensions: new Dictionary<string, object?>
60+
{
61+
{ "serializedValue", serializedValue },
62+
}));
63+
3764
internal static GraphQLClientException UrlFormatter_CouldNotParseUri(string value) =>
3865
new(new ClientError(
3966
$"The URL serializer could not parse value{value}. Invalid format. "));
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
namespace StrawberryShake.Serialization;
2+
3+
public class LocalDateSerializerTests
4+
{
5+
private LocalDateSerializer Serializer { get; } = new();
6+
7+
private LocalDateSerializer CustomSerializer { get; } = new("Abc");
8+
9+
[Fact]
10+
public void Parse()
11+
{
12+
// arrange
13+
var value = "2011-08-30";
14+
15+
// act
16+
var result = Serializer.Parse(value);
17+
18+
// assert
19+
Assert.Equal(2011, result.Year);
20+
Assert.Equal(8, result.Month);
21+
Assert.Equal(30, result.Day);
22+
}
23+
24+
[Fact]
25+
public void Format_Null()
26+
{
27+
// arrange
28+
29+
// act
30+
var result = Serializer.Format(null);
31+
32+
// assert
33+
Assert.Null(result);
34+
}
35+
36+
[Fact]
37+
public void Format_Value()
38+
{
39+
// arrange
40+
var value = new DateOnly(2011, 8, 30);
41+
42+
// act
43+
var result = Serializer.Format(value);
44+
45+
// assert
46+
Assert.Equal("2011-08-30", result);
47+
}
48+
49+
[Fact]
50+
public void Format_Exception()
51+
{
52+
// arrange
53+
var value = 1;
54+
55+
// act
56+
void Action() => Serializer.Format(value);
57+
58+
// assert
59+
Assert.Equal(
60+
"SS0007",
61+
Assert.Throws<GraphQLClientException>(Action).Errors.Single().Code);
62+
}
63+
64+
[Fact]
65+
public void TypeName_Default()
66+
{
67+
// arrange
68+
69+
// act
70+
var typeName = Serializer.TypeName;
71+
72+
// assert
73+
Assert.Equal("LocalDate", typeName);
74+
}
75+
76+
[Fact]
77+
public void TypeName_Custom()
78+
{
79+
// arrange
80+
81+
// act
82+
var typeName = CustomSerializer.TypeName;
83+
84+
// assert
85+
Assert.Equal("Abc", typeName);
86+
}
87+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
namespace StrawberryShake.Serialization;
2+
3+
public class LocalDateTimeSerializerTests
4+
{
5+
private LocalDateTimeSerializer Serializer { get; } = new();
6+
7+
private LocalDateTimeSerializer CustomSerializer { get; } = new("Abc");
8+
9+
[Fact]
10+
public void Parse()
11+
{
12+
// arrange
13+
var value = "2011-08-30T13:22:53";
14+
15+
// act
16+
var result = Serializer.Parse(value);
17+
18+
// assert
19+
Assert.Equal(2011, result.Year);
20+
Assert.Equal(8, result.Month);
21+
Assert.Equal(30, result.Day);
22+
Assert.Equal(13, result.Hour);
23+
Assert.Equal(22, result.Minute);
24+
Assert.Equal(53, result.Second);
25+
}
26+
27+
[Fact]
28+
public void Format_Null()
29+
{
30+
// arrange
31+
32+
// act
33+
var result = Serializer.Format(null);
34+
35+
// assert
36+
Assert.Null(result);
37+
}
38+
39+
[Fact]
40+
public void Format_Value()
41+
{
42+
// arrange
43+
var value = new DateTime(2011, 8, 30, 13, 22, 53, 108);
44+
45+
// act
46+
var result = Serializer.Format(value);
47+
48+
// assert
49+
Assert.Equal("2011-08-30T13:22:53", result);
50+
}
51+
52+
[Fact]
53+
public void Format_Exception()
54+
{
55+
// arrange
56+
var value = 1;
57+
58+
// act
59+
void Action() => Serializer.Format(value);
60+
61+
// assert
62+
Assert.Equal(
63+
"SS0007",
64+
Assert.Throws<GraphQLClientException>(Action).Errors.Single().Code);
65+
}
66+
67+
[Fact]
68+
public void TypeName_Default()
69+
{
70+
// arrange
71+
72+
// act
73+
var typeName = Serializer.TypeName;
74+
75+
// assert
76+
Assert.Equal("LocalDateTime", typeName);
77+
}
78+
79+
[Fact]
80+
public void TypeName_Custom()
81+
{
82+
// arrange
83+
84+
// act
85+
var typeName = CustomSerializer.TypeName;
86+
87+
// assert
88+
Assert.Equal("Abc", typeName);
89+
}
90+
}

0 commit comments

Comments
 (0)