Skip to content

Commit c4121b1

Browse files
Merge remote-tracking branch 'origin/main-staging' into local-staged-release
2 parents 0e694ff + 8776c2a commit c4121b1

File tree

4 files changed

+75
-2
lines changed

4 files changed

+75
-2
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"services": [
3+
{
4+
"serviceName": "DynamoDBv2",
5+
"type": "patch",
6+
"changeLogMessages": [
7+
"Added check in DateTimeToEpochSeconds to inspect null value for Nullable DateTime property decorated with StoreAsEpoch attribute, where it was incorrectly relying on exception to return the entry."
8+
]
9+
}
10+
]
11+
}

sdk/src/Services/DynamoDBv2/Custom/DocumentModel/Document.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,13 @@ internal static DynamoDBEntry DateTimeToEpochSeconds(DynamoDBEntry entry, string
290290
int? epochSeconds = null;
291291
try
292292
{
293+
var primitiveValue = entry.AsPrimitive();
294+
295+
// entry.AsPrimitive() could return null for UnconvertedDynamoDBEntry. UnconvertedDynamoDBEntry will always have a value due to check in it's constructor. Hence, we can process it further for epoch conversion.
296+
if (primitiveValue != null
297+
&& primitiveValue.Value == null)
298+
return entry;
299+
293300
var dateTime = entry.AsDateTime();
294301
epochSeconds = AWSSDKUtils.ConvertToUnixEpochSeconds(dateTime);
295302
}

sdk/test/Services/DynamoDBv2/IntegrationTests/DataModelTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ public void TestContext_DisableFetchingTableMetadata_DateTimeAsHashKey()
144144
EpochDate2 = EpochDate,
145145
NonEpochDate1 = EpochDate,
146146
NonEpochDate2 = EpochDate,
147+
NullableEpochDate1 = null,
148+
NullableEpochDate2 = EpochDate,
147149
LongEpochDate1 = LongEpochDate,
148150
LongEpochDate2 = LongEpochDate.AddDays(12),
149151
NullableLongEpochDate1 = null,
@@ -157,6 +159,8 @@ public void TestContext_DisableFetchingTableMetadata_DateTimeAsHashKey()
157159
ApproximatelyEqual(EpochDate, storedEmployee.EpochDate2);
158160
ApproximatelyEqual(EpochDate, storedEmployee.NonEpochDate1);
159161
ApproximatelyEqual(EpochDate, storedEmployee.NonEpochDate2);
162+
Assert.IsNull(storedEmployee.NullableEpochDate1);
163+
ApproximatelyEqual(EpochDate, storedEmployee.NullableEpochDate2.Value);
160164
ApproximatelyEqual(LongEpochDate, storedEmployee.LongEpochDate1);
161165
ApproximatelyEqual(LongEpochDate.AddDays(12), storedEmployee.LongEpochDate2);
162166
Assert.IsNull(storedEmployee.NullableLongEpochDate1);
@@ -293,6 +297,8 @@ public void TestContext_RetrieveDateTimeInUtc(bool retrieveDateTimeInUtc)
293297
EpochDate2 = currTime,
294298
NonEpochDate1 = currTime,
295299
NonEpochDate2 = currTime,
300+
NullableEpochDate1 = null,
301+
NullableEpochDate2 = currTime,
296302
LongEpochDate1 = longEpochTime,
297303
LongEpochDate2 = longEpochTimeBefore1970,
298304
NullableLongEpochDate1 = longEpochTime,
@@ -311,6 +317,8 @@ public void TestContext_RetrieveDateTimeInUtc(bool retrieveDateTimeInUtc)
311317
ApproximatelyEqual(expectedCurrTime, storedEmployee.EpochDate2);
312318
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate1);
313319
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate2);
320+
Assert.IsNull(storedEmployee.NullableEpochDate1);
321+
ApproximatelyEqual(expectedCurrTime, storedEmployee.NullableEpochDate2.Value);
314322
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.LongEpochDate1);
315323
ApproximatelyEqual(expectedLongEpochTimeBefore1970, storedEmployee.LongEpochDate2);
316324
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.NullableLongEpochDate1.Value);
@@ -327,6 +335,8 @@ public void TestContext_RetrieveDateTimeInUtc(bool retrieveDateTimeInUtc)
327335
ApproximatelyEqual(expectedCurrTime, storedEmployee.EpochDate2);
328336
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate1);
329337
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate2);
338+
Assert.IsNull(storedEmployee.NullableEpochDate1);
339+
ApproximatelyEqual(expectedCurrTime, storedEmployee.NullableEpochDate2.Value);
330340
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.LongEpochDate1);
331341
ApproximatelyEqual(expectedLongEpochTimeBefore1970, storedEmployee.LongEpochDate2);
332342
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.NullableLongEpochDate1.Value);
@@ -341,6 +351,8 @@ public void TestContext_RetrieveDateTimeInUtc(bool retrieveDateTimeInUtc)
341351
ApproximatelyEqual(expectedCurrTime, storedEmployee.EpochDate2);
342352
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate1);
343353
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate2);
354+
Assert.IsNull(storedEmployee.NullableEpochDate1);
355+
ApproximatelyEqual(expectedCurrTime, storedEmployee.NullableEpochDate2.Value);
344356
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.LongEpochDate1);
345357
ApproximatelyEqual(expectedLongEpochTimeBefore1970, storedEmployee.LongEpochDate2);
346358
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.NullableLongEpochDate1.Value);
@@ -386,6 +398,8 @@ public void TestContext_CustomDateTimeConverter(bool retrieveDateTimeInUtc)
386398
EpochDate2 = currTime,
387399
NonEpochDate1 = currTime,
388400
NonEpochDate2 = currTime,
401+
NullableEpochDate1 = null,
402+
NullableEpochDate2 = currTime,
389403
LongEpochDate1 = longEpochTime,
390404
LongEpochDate2 = longEpochTimeBefore1970,
391405
NullableLongEpochDate1 = longEpochTime,
@@ -406,6 +420,8 @@ public void TestContext_CustomDateTimeConverter(bool retrieveDateTimeInUtc)
406420
ApproximatelyEqual(expectedCurrTime, storedEmployee.EpochDate2);
407421
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate1);
408422
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate2);
423+
Assert.IsNull(storedEmployee.NullableEpochDate1);
424+
ApproximatelyEqual(expectedCurrTime, storedEmployee.NullableEpochDate2.Value);
409425
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.LongEpochDate1);
410426
ApproximatelyEqual(expectedLongEpochTimeBefore1970, storedEmployee.LongEpochDate2);
411427
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.NullableLongEpochDate1.Value);
@@ -422,6 +438,8 @@ public void TestContext_CustomDateTimeConverter(bool retrieveDateTimeInUtc)
422438
ApproximatelyEqual(expectedCurrTime, storedEmployee.EpochDate2);
423439
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate1);
424440
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate2);
441+
Assert.IsNull(storedEmployee.NullableEpochDate1);
442+
ApproximatelyEqual(expectedCurrTime, storedEmployee.NullableEpochDate2.Value);
425443
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.LongEpochDate1);
426444
ApproximatelyEqual(expectedLongEpochTimeBefore1970, storedEmployee.LongEpochDate2);
427445
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.NullableLongEpochDate1.Value);
@@ -436,6 +454,8 @@ public void TestContext_CustomDateTimeConverter(bool retrieveDateTimeInUtc)
436454
ApproximatelyEqual(expectedCurrTime, storedEmployee.EpochDate2);
437455
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate1);
438456
ApproximatelyEqual(expectedCurrTime, storedEmployee.NonEpochDate2);
457+
Assert.IsNull(storedEmployee.NullableEpochDate1);
458+
ApproximatelyEqual(expectedCurrTime, storedEmployee.NullableEpochDate2.Value);
439459
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.LongEpochDate1);
440460
ApproximatelyEqual(expectedLongEpochTimeBefore1970, storedEmployee.LongEpochDate2);
441461
ApproximatelyEqual(expectedLongEpochTime, storedEmployee.NullableLongEpochDate1.Value);
@@ -2133,6 +2153,12 @@ public class EpochEmployee : Employee
21332153

21342154
public DateTime NonEpochDate2 { get; set; }
21352155

2156+
[DynamoDBProperty(StoreAsEpoch = true)]
2157+
public DateTime? NullableEpochDate1 { get; set; }
2158+
2159+
[DynamoDBProperty(StoreAsEpoch = true)]
2160+
public DateTime? NullableEpochDate2 { get; set; }
2161+
21362162
[DynamoDBProperty(StoreAsEpochLong = true)]
21372163
public DateTime LongEpochDate1 { get; set; }
21382164

sdk/test/Services/DynamoDBv2/IntegrationTests/TTLTests.cs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public void TestStoreAsEpoch()
4040
EpochDate2 = EpochDate,
4141
NonEpochDate1 = EpochDate,
4242
NonEpochDate2 = EpochDate,
43+
NullableEpochDate2 = EpochDate,
4344
LongEpochDate1 = LongEpochDate,
4445
LongEpochDate2 = LongEpochDate.AddMonths(3),
4546
NullableLongEpochDate2 = LongEpochDate.AddMonths(-3)
@@ -50,13 +51,17 @@ public void TestStoreAsEpoch()
5051
var storedEmployee = Context.Load<EpochEmployee>(employee.Name, employee.Age);
5152
Assert.IsNotNull(storedEmployee);
5253
ApproximatelyEqual(EpochDate, storedEmployee.CreationTime);
54+
Assert.IsNull(storedEmployee.NullableEpochDate1);
55+
ApproximatelyEqual(EpochDate, storedEmployee.NullableEpochDate2.Value);
5356
ApproximatelyEqual(LongEpochDate, storedEmployee.LongEpochDate1);
5457
ApproximatelyEqual(LongEpochDate.AddMonths(3), storedEmployee.LongEpochDate2);
5558
Assert.IsNull(storedEmployee.NullableLongEpochDate1);
5659
ApproximatelyEqual(LongEpochDate.AddMonths(-3), storedEmployee.NullableLongEpochDate2.Value);
5760
storedEmployee = Context.Load<EpochEmployee>(employee);
5861
Assert.IsNotNull(storedEmployee);
5962
ApproximatelyEqual(EpochDate, storedEmployee.CreationTime);
63+
Assert.IsNull(storedEmployee.NullableEpochDate1);
64+
ApproximatelyEqual(EpochDate, storedEmployee.NullableEpochDate2.Value);
6065
ApproximatelyEqual(LongEpochDate, storedEmployee.LongEpochDate1);
6166
ApproximatelyEqual(LongEpochDate.AddMonths(3), storedEmployee.LongEpochDate2);
6267
Assert.IsNull(storedEmployee.NullableLongEpochDate1);
@@ -66,6 +71,8 @@ public void TestStoreAsEpoch()
6671
var storedNumericEmployee = Context.Load<NumericEpochEmployee>(employee.CreationTime, employee.Name);
6772
Assert.IsNotNull(storedNumericEmployee);
6873
ApproximatelyEqual(EpochDate, storedNumericEmployee.CreationTime);
74+
Assert.IsNull(storedNumericEmployee.NullableEpochDate1);
75+
ApproximatelyEqual(EpochDate, storedNumericEmployee.NullableEpochDate2.Value);
6976
ApproximatelyEqual(LongEpochDate, storedNumericEmployee.LongEpochDate1);
7077
ApproximatelyEqual(LongEpochDate.AddMonths(3), storedNumericEmployee.LongEpochDate2);
7178
Assert.IsNull(storedEmployee.NullableLongEpochDate1);
@@ -74,6 +81,8 @@ public void TestStoreAsEpoch()
7481
storedNumericEmployee = Context.Load<NumericEpochEmployee>(numericEmployee);
7582
Assert.IsNotNull(storedNumericEmployee);
7683
ApproximatelyEqual(EpochDate, storedNumericEmployee.CreationTime);
84+
Assert.IsNull(storedNumericEmployee.NullableEpochDate1);
85+
ApproximatelyEqual(EpochDate, storedNumericEmployee.NullableEpochDate2.Value);
7786
ApproximatelyEqual(LongEpochDate, storedNumericEmployee.LongEpochDate1);
7887
ApproximatelyEqual(LongEpochDate.AddMonths(3), storedNumericEmployee.LongEpochDate2);
7988
Assert.IsNull(storedEmployee.NullableLongEpochDate1);
@@ -82,6 +91,8 @@ public void TestStoreAsEpoch()
8291
var doc = Context.ToDocument(employee);
8392
ApproximatelyEqual(EpochDate, doc["CreationTime"].AsDateTime());
8493
ApproximatelyEqual(EpochDate, doc["EpochDate2"].AsDateTime());
94+
Assert.IsNull(doc["NullableEpochDate1"].AsPrimitive().Value);
95+
ApproximatelyEqual(EpochDate, doc["NullableEpochDate2"].AsDateTime());
8596
ApproximatelyEqual(EpochDate, doc["NonEpochDate1"].AsDateTime());
8697
ApproximatelyEqual(EpochDate, doc["NonEpochDate1"].AsDateTime());
8798
ApproximatelyEqual(LongEpochDate, doc["LongEpochDate1"].AsDateTime());
@@ -92,6 +103,8 @@ public void TestStoreAsEpoch()
92103
var docV1 = doc.ForceConversion(DynamoDBEntryConversion.V1);
93104
ApproximatelyEqual(EpochDate, docV1["CreationTime"].AsDateTime());
94105
ApproximatelyEqual(EpochDate, docV1["EpochDate2"].AsDateTime());
106+
Assert.IsNull(docV1["NullableEpochDate1"].AsPrimitive().Value);
107+
ApproximatelyEqual(EpochDate, docV1["NullableEpochDate2"].AsDateTime());
95108
ApproximatelyEqual(EpochDate, docV1["NonEpochDate1"].AsDateTime());
96109
ApproximatelyEqual(EpochDate, docV1["NonEpochDate1"].AsDateTime());
97110
ApproximatelyEqual(LongEpochDate, docV1["LongEpochDate1"].AsDateTime());
@@ -102,6 +115,8 @@ public void TestStoreAsEpoch()
102115
var docV2 = doc.ForceConversion(DynamoDBEntryConversion.V2);
103116
ApproximatelyEqual(EpochDate, docV2["CreationTime"].AsDateTime());
104117
ApproximatelyEqual(EpochDate, docV2["EpochDate2"].AsDateTime());
118+
Assert.IsNull(docV2["NullableEpochDate1"].AsPrimitive().Value);
119+
ApproximatelyEqual(EpochDate, docV2["NullableEpochDate2"].AsDateTime());
105120
ApproximatelyEqual(EpochDate, docV2["NonEpochDate1"].AsDateTime());
106121
ApproximatelyEqual(EpochDate, docV2["NonEpochDate1"].AsDateTime());
107122
ApproximatelyEqual(LongEpochDate, docV2["LongEpochDate1"].AsDateTime());
@@ -118,6 +133,8 @@ public void TestStoreAsEpoch()
118133
var epochMap = epochTable.ToAttributeMap(doc);
119134
Assert.IsNotNull(epochMap["CreationTime"].N);
120135
Assert.IsNotNull(epochMap["EpochDate2"].N);
136+
Assert.IsFalse(epochMap.ContainsKey("NullableEpochDate1"));
137+
Assert.IsNotNull(epochMap["NullableEpochDate2"].N);
121138
Assert.IsNotNull(epochMap["NonEpochDate1"].S);
122139
Assert.IsNotNull(epochMap["NonEpochDate2"].S);
123140
Assert.IsNotNull(epochMap["LongEpochDate1"].N);
@@ -172,7 +189,7 @@ public void TestStoreAsEpoch(Table hashRangeTable, Table numericHashRangeTable)
172189
// construct tables with StoreAsEpoch and StoreAsEpochLong
173190
var config = new TableConfig(hashRangeTable.TableName)
174191
{
175-
AttributesToStoreAsEpoch = new List<string> { "CreationTime", "EpochDate2" },
192+
AttributesToStoreAsEpoch = new List<string> { "CreationTime", "EpochDate2", "NullableEpochDate1", "NullableEpochDate2" },
176193
AttributesToStoreAsEpochLong = new List<string> { "LongEpochDate", "NullableLongEpochDate1", "NullableLongEpochDate2" }
177194
};
178195
var epochTable = Table.LoadTable(Client, config);
@@ -181,7 +198,7 @@ public void TestStoreAsEpoch(Table hashRangeTable, Table numericHashRangeTable)
181198

182199
config = new TableConfig(numericHashRangeTable.TableName)
183200
{
184-
AttributesToStoreAsEpoch = new List<string> { "CreationTime", "EpochDate2" },
201+
AttributesToStoreAsEpoch = new List<string> { "CreationTime", "EpochDate2", "NullableEpochDate1", "NullableEpochDate2" },
185202
AttributesToStoreAsEpochLong = new List<string> { "LongEpochDate", "NullableLongEpochDate1", "NullableLongEpochDate2" }
186203
};
187204
var numericEpochTable = Table.LoadTable(Client, config);
@@ -193,6 +210,8 @@ public void TestStoreAsEpoch(Table hashRangeTable, Table numericHashRangeTable)
193210
Assert.IsNotNull(map["CreationTime"].S);
194211
Assert.IsNotNull(map["EpochDate2"].S);
195212
Assert.IsNotNull(map["NonEpochDate"].S);
213+
Assert.IsNotNull(map["NullableEpochDate1"].S);
214+
Assert.IsFalse(map.ContainsKey("NullableEpochDate2"));
196215
Assert.IsNotNull(map["LongEpochDate"].S);
197216
Assert.IsNotNull(map["NullableLongEpochDate1"].S);
198217
Assert.IsFalse(map.ContainsKey("NullableLongEpochDate2"));
@@ -201,7 +220,9 @@ public void TestStoreAsEpoch(Table hashRangeTable, Table numericHashRangeTable)
201220
Assert.IsNotNull(epochMap["CreationTime"].N);
202221
Assert.IsNotNull(epochMap["EpochDate2"].N);
203222
Assert.IsNotNull(epochMap["NonEpochDate"].S);
223+
Assert.IsNotNull(epochMap["NullableEpochDate1"].N);
204224
Assert.IsNotNull(epochMap["LongEpochDate"].N);
225+
Assert.IsNotNull(epochMap["NullableLongEpochDate1"].N);
205226

206227
// put
207228
epochTable.PutItem(CreateTestDocument());
@@ -241,6 +262,8 @@ public void TestStoreAsEpoch(Table hashRangeTable, Table numericHashRangeTable)
241262
doc2["CreationTime"] = EpochDate;
242263
doc2["EpochDate2"] = EpochDate;
243264
doc2["NonEpochDate"] = EpochDate;
265+
doc2["NullableEpochDate1"] = (DateTime?) EpochDate;
266+
doc2["NullableEpochDate2"] = (DateTime?) null;
244267
doc2["LongEpochDate"] = LongEpochDate;
245268
doc2["NullableLongEpochDate1"] = (DateTime?) LongEpochDate;
246269
doc2["NullableLongEpochDate2"] = (DateTime?) null;
@@ -335,6 +358,8 @@ private static Document CreateTestDocument()
335358
doc["CreationTime"] = EpochDate;
336359
doc["EpochDate2"] = EpochDate;
337360
doc["NonEpochDate"] = EpochDate;
361+
doc["NullableEpochDate1"] = (DateTime?) EpochDate;
362+
doc["NullableEpochDate2"] = (DateTime?) null;
338363
doc["LongEpochDate"] = LongEpochDate;
339364
doc["NullableLongEpochDate1"] = (DateTime?) LongEpochDate;
340365
doc["NullableLongEpochDate2"] = (DateTime?) null;
@@ -348,6 +373,7 @@ private static void TestWrittenData(Primitive hash, Primitive range, Table hashR
348373
Assert.AreEqual(EpochSeconds, nonEpochDoc["CreationTime"].AsInt());
349374
Assert.AreEqual(EpochSeconds, nonEpochDoc["EpochDate2"].AsInt());
350375
ApproximatelyEqual(EpochDate, nonEpochDoc["NonEpochDate"].AsDateTime());
376+
Assert.AreEqual(EpochSeconds, nonEpochDoc["NullableEpochDate1"].AsInt());
351377
Assert.AreEqual(LongEpochSeconds, nonEpochDoc["LongEpochDate"].AsLong());
352378
Assert.AreEqual(LongEpochSeconds, nonEpochDoc["NullableLongEpochDate1"].AsLong());
353379
Assert.IsFalse(nonEpochDoc.ContainsKey("NullableLongEpochDate2"));
@@ -359,6 +385,7 @@ private static void TestWrittenData(Primitive hash, Primitive range, Table hashR
359385
ApproximatelyEqual(EpochDate, epochDoc["CreationTime"].AsDateTime());
360386
ApproximatelyEqual(EpochDate, epochDoc["EpochDate2"].AsDateTime());
361387
ApproximatelyEqual(EpochDate, epochDoc["NonEpochDate"].AsDateTime());
388+
ApproximatelyEqual(EpochDate, epochDoc["NullableEpochDate1"].AsDateTime());
362389
ApproximatelyEqual(LongEpochDate, epochDoc["LongEpochDate"].AsDateTime());
363390
ApproximatelyEqual(LongEpochDate, epochDoc["NullableLongEpochDate1"].AsDateTime());
364391
if (checkForConditionalUpdate)
@@ -374,6 +401,7 @@ private static void TestForInts(List<Document> nonEpochDocs)
374401
Assert.AreEqual(EpochSeconds, ed["CreationTime"].AsInt());
375402
Assert.AreEqual(EpochSeconds, ed["EpochDate2"].AsInt());
376403
ApproximatelyEqual(EpochDate, ed["NonEpochDate"].AsDateTime());
404+
Assert.AreEqual(EpochSeconds, ed["NullableEpochDate1"].AsInt());
377405
Assert.AreEqual(LongEpochSeconds, ed["LongEpochDate"].AsLong());
378406
Assert.AreEqual(LongEpochSeconds, ed["NullableLongEpochDate1"].AsLong());
379407
}
@@ -386,6 +414,7 @@ private static void TestForDateTime(List<Document> epochDocs)
386414
ApproximatelyEqual(EpochDate, ed["CreationTime"].AsDateTime());
387415
ApproximatelyEqual(EpochDate, ed["EpochDate2"].AsDateTime());
388416
ApproximatelyEqual(EpochDate, ed["NonEpochDate"].AsDateTime());
417+
ApproximatelyEqual(EpochDate, ed["NullableEpochDate1"].AsDateTime());
389418
ApproximatelyEqual(LongEpochDate, ed["LongEpochDate"].AsDateTime());
390419
ApproximatelyEqual(LongEpochDate, ed["NullableLongEpochDate1"].AsDateTime());
391420
}

0 commit comments

Comments
 (0)