Skip to content

Commit 6a79434

Browse files
authored
fix: Delay the cast from IAmazonDynamoDB to AmazonDynamoDBClient in the DocumentModel (#3388)
1 parent 0ca2250 commit 6a79434

File tree

10 files changed

+551
-80
lines changed

10 files changed

+551
-80
lines changed

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

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -427,15 +427,22 @@ private Results GetAttributeItems()
427427
return results;
428428
}
429429

430+
private static void CallUntilCompletion(IAmazonDynamoDB client, BatchGetItemRequest request, Results allResults)
431+
{
430432
#if NETSTANDARD
431-
private static void CallUntilCompletion(AmazonDynamoDBClient client, BatchGetItemRequest request, Results allResults)
433+
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
434+
var internalClient = client as AmazonDynamoDBClient;
435+
if (internalClient == null)
436+
{
437+
throw new InvalidOperationException("Calling the synchronous DocumentBatchGet.Execute() from .NET or .NET Core requires initializing the Table " +
438+
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when calling ExecuteAsync instead.");
439+
}
432440
#else
433-
private static void CallUntilCompletion(IAmazonDynamoDB client, BatchGetItemRequest request, Results allResults)
441+
var internalClient = client;
434442
#endif
435-
{
436443
do
437444
{
438-
var serviceResponse = client.BatchGetItem(request);
445+
var serviceResponse = internalClient.BatchGetItem(request);
439446

440447
foreach (var kvp in serviceResponse.Responses)
441448
{
@@ -448,12 +455,8 @@ private static void CallUntilCompletion(IAmazonDynamoDB client, BatchGetItemRequ
448455
} while (request.RequestItems.Count > 0);
449456
}
450457

451-
#if AWS_ASYNC_API
452-
#if NETSTANDARD
453-
private static async Task CallUntilCompletionAsync(AmazonDynamoDBClient client, BatchGetItemRequest request, Results allResults, CancellationToken cancellationToken)
454-
#else
458+
#if AWS_ASYNC_API
455459
private static async Task CallUntilCompletionAsync(IAmazonDynamoDB client, BatchGetItemRequest request, Results allResults, CancellationToken cancellationToken)
456-
#endif
457460
{
458461
do
459462
{

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -469,15 +469,22 @@ private static Dictionary<string, QuickList<WriteRequestDocument>> GetNextWriteI
469469
return nextItems;
470470
}
471471

472+
private void CallUntilCompletion(BatchWriteItemRequest request, Dictionary<string, Dictionary<Key, Document>> documentMap, IAmazonDynamoDB client)
473+
{
472474
#if NETSTANDARD
473-
private void CallUntilCompletion(BatchWriteItemRequest request, Dictionary<string, Dictionary<Key, Document>> documentMap, AmazonDynamoDBClient client)
475+
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
476+
var internalClient = client as AmazonDynamoDBClient;
477+
if (internalClient == null)
478+
{
479+
throw new InvalidOperationException("Calling the synchronous DocumentBatchWrite.Execute() from .NET or .NET Core requires initializing the Table " +
480+
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when calling ExecuteAsync instead.");
481+
}
474482
#else
475-
private void CallUntilCompletion(BatchWriteItemRequest request, Dictionary<string, Dictionary<Key, Document>> documentMap, IAmazonDynamoDB client)
483+
var internalClient = client;
476484
#endif
477-
{
478485
do
479486
{
480-
var result = client.BatchWriteItem(request);
487+
var result = internalClient.BatchWriteItem(request);
481488
request.RequestItems = result.UnprocessedItems;
482489

483490
Dictionary<Key, Document> unprocessedDocuments = new Dictionary<Key, Document>(keyComparer);
@@ -529,11 +536,7 @@ private void CallUntilCompletion(BatchWriteItemRequest request, Dictionary<strin
529536
}
530537

531538
#if AWS_ASYNC_API
532-
#if NETSTANDARD
533-
private async Task CallUntilCompletionAsync(BatchWriteItemRequest request, Dictionary<string, Dictionary<Key, Document>> documentMap, AmazonDynamoDBClient client, CancellationToken cancellationToken)
534-
#else
535539
private async Task CallUntilCompletionAsync(BatchWriteItemRequest request, Dictionary<string, Dictionary<Key, Document>> documentMap, IAmazonDynamoDB client, CancellationToken cancellationToken)
536-
#endif
537540
{
538541
do
539542
{

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,18 @@ private Dictionary<DocumentTransactGet, List<Document>> GetItemsHelper()
307307
if (Items == null || !Items.Any()) return new Dictionary<DocumentTransactGet, List<Document>>();
308308

309309
var request = ConstructRequest(isAsync: false);
310-
var dynamoDbClient = Items[0].TransactionPart.TargetTable.DDBClient;
311-
var response = dynamoDbClient.TransactGetItems(request);
310+
#if NETSTANDARD
311+
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
312+
var internalClient = Items[0].TransactionPart.TargetTable.DDBClient as AmazonDynamoDBClient;
313+
if (internalClient == null)
314+
{
315+
throw new InvalidOperationException("Calling the synchronous DocumentBatchGet.Execute() from .NET or .NET Core requires initializing the Table " +
316+
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when calling ExecuteAsync instead.");
317+
}
318+
#else
319+
var internalClient = Items[0].TransactionPart.TargetTable.DDBClient;
320+
#endif
321+
var response = internalClient.TransactGetItems(request);
312322
return GetDocuments(response.Responses);
313323
}
314324

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -598,8 +598,19 @@ private void WriteItemsHelper()
598598

599599
try
600600
{
601-
var dynamoDbClient = Items[0].TransactionPart.TargetTable.DDBClient;
602-
dynamoDbClient.TransactWriteItems(request);
601+
#if NETSTANDARD
602+
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
603+
var internalClient = Items[0].TransactionPart.TargetTable.DDBClient as AmazonDynamoDBClient;
604+
if (internalClient == null)
605+
{
606+
throw new InvalidOperationException("Calling the synchronous DocumentTransactWrite.Execute() from .NET or .NET Core requires initializing the Table " +
607+
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when calling ExecuteAsync instead.");
608+
}
609+
#else
610+
var internalClient = Items[0].TransactionPart.TargetTable.DDBClient;
611+
#endif
612+
613+
internalClient.TransactWriteItems(request);
603614
}
604615
catch (TransactionCanceledException ex)
605616
{

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

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,18 @@ internal List<Document> GetNextSetHelper()
212212
{
213213
List<Document> ret = new List<Document>();
214214

215+
#if NETSTANDARD
216+
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
217+
var internalClient = SourceTable.DDBClient as AmazonDynamoDBClient;
218+
if (internalClient == null)
219+
{
220+
throw new InvalidOperationException("Calling the synchronous GetNextSet() from .NET or .NET Core requires initializing the Table " +
221+
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when calling GetNextSetAsync instead.");
222+
}
223+
#else
224+
var internalClient = SourceTable.DDBClient;
225+
#endif
226+
215227
if (!IsDone)
216228
{
217229
switch (SearchMethod)
@@ -253,7 +265,7 @@ internal List<Document> GetNextSetHelper()
253265

254266
SourceTable.AddRequestHandler(scanReq, isAsync: false);
255267

256-
var scanResult = SourceTable.DDBClient.Scan(scanReq);
268+
var scanResult = internalClient.Scan(scanReq);
257269
foreach (var item in scanResult.Items)
258270
{
259271
Document doc = SourceTable.FromAttributeMap(item);
@@ -303,7 +315,7 @@ internal List<Document> GetNextSetHelper()
303315

304316
SourceTable.AddRequestHandler(queryReq, isAsync: false);
305317

306-
var queryResult = SourceTable.DDBClient.Query(queryReq);
318+
var queryResult = internalClient.Query(queryReq);
307319
foreach (var item in queryResult.Items)
308320
{
309321
Document doc = SourceTable.FromAttributeMap(item);
@@ -532,6 +544,17 @@ private int GetCount()
532544
}
533545
else
534546
{
547+
#if NETSTANDARD
548+
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
549+
var internalClient = SourceTable.DDBClient as AmazonDynamoDBClient;
550+
if (internalClient == null)
551+
{
552+
throw new InvalidOperationException("Accessing the synchronous Count from .NET or .NET Core requires " +
553+
"initializing the Table with an actual AmazonDynamoDBClient.");
554+
}
555+
#else
556+
var internalClient = SourceTable.DDBClient;
557+
#endif
535558
switch (SearchMethod)
536559
{
537560
case SearchType.Scan:
@@ -558,7 +581,7 @@ private int GetCount()
558581

559582
SourceTable.AddRequestHandler(scanReq, isAsync: false);
560583

561-
var scanResult = SourceTable.DDBClient.Scan(scanReq);
584+
var scanResult = internalClient.Scan(scanReq);
562585
count = Matches.Count + scanResult.Count.GetValueOrDefault();
563586
return count;
564587
case SearchType.Query:
@@ -583,7 +606,7 @@ private int GetCount()
583606

584607
SourceTable.AddRequestHandler(queryReq, isAsync: false);
585608

586-
var queryResult = SourceTable.DDBClient.Query(queryReq);
609+
var queryResult = internalClient.Query(queryReq);
587610
count = Matches.Count + queryResult.Count.GetValueOrDefault();
588611
return count;
589612
default:

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

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,7 @@ internal enum DynamoDBConsumer
5454
internal bool IsEmptyStringValueEnabled { get { return Config.IsEmptyStringValueEnabled; } }
5555
internal IEnumerable<string> StoreAsEpoch { get { return Config.AttributesToStoreAsEpoch; } }
5656
internal IEnumerable<string> KeyNames { get { return Keys.Keys; } }
57-
58-
#if NETSTANDARD
59-
internal AmazonDynamoDBClient DDBClient { get; private set; }
60-
#else
6157
internal IAmazonDynamoDB DDBClient { get; private set; }
62-
#endif
6358

6459
#endregion
6560

@@ -366,7 +361,19 @@ private TableDescription DescribeTable(string tableName)
366361
};
367362
this.AddRequestHandler(req, isAsync: false);
368363

369-
var info = this.DDBClient.DescribeTable(req);
364+
#if NETSTANDARD
365+
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
366+
var client = DDBClient as AmazonDynamoDBClient;
367+
if (client == null)
368+
{
369+
throw new InvalidOperationException("Calling the synchronous LoadTable from .NET or .NET Core requires initializing the Table " +
370+
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when creating a Table via TableBuilder instead.");
371+
}
372+
#else
373+
var client = DDBClient;
374+
#endif
375+
376+
var info = client.DescribeTable(req);
370377

371378
if (info.Table == null)
372379
{
@@ -413,11 +420,7 @@ internal Table(IAmazonDynamoDB ddbClient, TableConfig config)
413420
if (ddbClient == null)
414421
throw new ArgumentNullException("ddbClient");
415422

416-
#if NETSTANDARD
417-
DDBClient = ddbClient as AmazonDynamoDBClient;
418-
#else
419423
DDBClient = ddbClient;
420-
#endif
421424
Config = config;
422425
}
423426

@@ -938,7 +941,19 @@ internal Document PutItemHelper(Document doc, PutItemOperationConfig config)
938941
currentConfig.ConditionalExpression.ApplyExpression(req, this);
939942
}
940943

941-
var resp = DDBClient.PutItem(req);
944+
#if NETSTANDARD
945+
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
946+
var client = DDBClient as AmazonDynamoDBClient;
947+
if (client == null)
948+
{
949+
throw new InvalidOperationException("Calling the synchronous PutItem from .NET or .NET Core requires initializing the Table " +
950+
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when creating a Table via PutItemAsync instead.");
951+
}
952+
#else
953+
var client = DDBClient;
954+
#endif
955+
956+
var resp = client.PutItem(req);
942957
doc.CommitChanges();
943958

944959
Document ret = null;
@@ -1013,10 +1028,22 @@ internal Document GetItemHelper(Key key, GetItemOperationConfig config)
10131028

10141029
this.AddRequestHandler(request, isAsync: false);
10151030

1031+
#if NETSTANDARD
1032+
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
1033+
var client = DDBClient as AmazonDynamoDBClient;
1034+
if (client == null)
1035+
{
1036+
throw new InvalidOperationException("Calling the synchronous GetItem from .NET or .NET Core requires initializing the Table " +
1037+
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when creating a Table via GetItemAsync instead.");
1038+
}
1039+
#else
1040+
var client = DDBClient;
1041+
#endif
1042+
10161043
if (currentConfig.AttributesToGet != null)
10171044
request.AttributesToGet = currentConfig.AttributesToGet;
10181045

1019-
var result = DDBClient.GetItem(request);
1046+
var result = client.GetItem(request);
10201047
var attributeMap = result.Item;
10211048
if (attributeMap == null || attributeMap.Count == 0)
10221049
return null;
@@ -1047,7 +1074,7 @@ internal async Task<Document> GetItemHelperAsync(Key key, GetItemOperationConfig
10471074
}
10481075
#endif
10491076

1050-
#endregion
1077+
#endregion
10511078

10521079

10531080
#region UpdateItem
@@ -1058,7 +1085,7 @@ internal Document UpdateHelper(Document doc, Primitive hashKey, Primitive rangeK
10581085
return UpdateHelper(doc, key, config);
10591086
}
10601087

1061-
#if AWS_ASYNC_API
1088+
#if AWS_ASYNC_API
10621089
internal Task<Document> UpdateHelperAsync(Document doc, Primitive hashKey, Primitive rangeKey, UpdateItemOperationConfig config, CancellationToken cancellationToken)
10631090
{
10641091
Key key = (hashKey != null || rangeKey != null) ? MakeKey(hashKey, rangeKey) : MakeKey(doc);
@@ -1132,8 +1159,19 @@ internal Document UpdateHelper(Document doc, Key key, UpdateItemOperationConfig
11321159
req.ExpressionAttributeNames.Add(kvp.Key, kvp.Value);
11331160
}
11341161
}
1162+
#if NETSTANDARD
1163+
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
1164+
var client = DDBClient as AmazonDynamoDBClient;
1165+
if (client == null)
1166+
{
1167+
throw new InvalidOperationException("Calling the synchronous UpdateItem from .NET or .NET Core requires initializing the Table " +
1168+
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when creating a Table via UpdateItemAsync instead.");
1169+
}
1170+
#else
1171+
var client = DDBClient;
1172+
#endif
11351173

1136-
var resp = DDBClient.UpdateItem(req);
1174+
var resp = client.UpdateItem(req);
11371175
var returnedAttributes = resp.Attributes;
11381176
doc.CommitChanges();
11391177

@@ -1145,7 +1183,7 @@ internal Document UpdateHelper(Document doc, Key key, UpdateItemOperationConfig
11451183
return ret;
11461184
}
11471185

1148-
#if AWS_ASYNC_API
1186+
#if AWS_ASYNC_API
11491187
internal async Task<Document> UpdateHelperAsync(Document doc, Key key, UpdateItemOperationConfig config, CancellationToken cancellationToken)
11501188
{
11511189
var currentConfig = config ?? new UpdateItemOperationConfig();
@@ -1275,7 +1313,19 @@ internal Document DeleteHelper(Key key, DeleteItemOperationConfig config)
12751313
currentConfig.ConditionalExpression.ApplyExpression(req, this);
12761314
}
12771315

1278-
var attributes = DDBClient.DeleteItem(req).Attributes;
1316+
#if NETSTANDARD
1317+
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
1318+
var client = DDBClient as AmazonDynamoDBClient;
1319+
if (client == null)
1320+
{
1321+
throw new InvalidOperationException("Calling the synchronous DeleteItem from .NET or .NET Core requires initializing the Table " +
1322+
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when calling DeleteItemAsync instead.");
1323+
}
1324+
#else
1325+
var client = DDBClient;
1326+
#endif
1327+
1328+
var attributes = client.DeleteItem(req).Attributes;
12791329

12801330
Document ret = null;
12811331
if (currentConfig.ReturnValues == ReturnValues.AllOldAttributes)

0 commit comments

Comments
 (0)