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

fix: Delay the cast from IAmazonDynamoDB to AmazonDynamoDBClient in the DocumentModel #3388

Merged
merged 4 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -427,15 +427,22 @@ private Results GetAttributeItems()
return results;
}

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

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

#if AWS_ASYNC_API
#if NETSTANDARD
private static async Task CallUntilCompletionAsync(AmazonDynamoDBClient client, BatchGetItemRequest request, Results allResults, CancellationToken cancellationToken)
#else
#if AWS_ASYNC_API
private static async Task CallUntilCompletionAsync(IAmazonDynamoDB client, BatchGetItemRequest request, Results allResults, CancellationToken cancellationToken)
#endif
{
do
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,15 +469,22 @@ private static Dictionary<string, QuickList<WriteRequestDocument>> GetNextWriteI
return nextItems;
}

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

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

#if AWS_ASYNC_API
#if NETSTANDARD
private async Task CallUntilCompletionAsync(BatchWriteItemRequest request, Dictionary<string, Dictionary<Key, Document>> documentMap, AmazonDynamoDBClient client, CancellationToken cancellationToken)
#else
private async Task CallUntilCompletionAsync(BatchWriteItemRequest request, Dictionary<string, Dictionary<Key, Document>> documentMap, IAmazonDynamoDB client, CancellationToken cancellationToken)
#endif
{
do
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,18 @@ private Dictionary<DocumentTransactGet, List<Document>> GetItemsHelper()
if (Items == null || !Items.Any()) return new Dictionary<DocumentTransactGet, List<Document>>();

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,19 @@ private void WriteItemsHelper()

try
{
var dynamoDbClient = Items[0].TransactionPart.TargetTable.DDBClient;
dynamoDbClient.TransactWriteItems(request);
#if NETSTANDARD
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
var internalClient = Items[0].TransactionPart.TargetTable.DDBClient as AmazonDynamoDBClient;
if (internalClient == null)
{
throw new InvalidOperationException("Calling the synchronous DocumentTransactWrite.Execute() from .NET or .NET Core requires initializing the Table " +
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when calling ExecuteAsync instead.");
}
#else
var internalClient = Items[0].TransactionPart.TargetTable.DDBClient;
#endif

internalClient.TransactWriteItems(request);
}
catch (TransactionCanceledException ex)
{
Expand Down
31 changes: 27 additions & 4 deletions sdk/src/Services/DynamoDBv2/Custom/DocumentModel/Search.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,18 @@ internal List<Document> GetNextSetHelper()
{
List<Document> ret = new List<Document>();

#if NETSTANDARD
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
var internalClient = SourceTable.DDBClient as AmazonDynamoDBClient;
if (internalClient == null)
{
throw new InvalidOperationException("Calling the synchronous GetNextSet() from .NET or .NET Core requires initializing the Table " +
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when calling GetNextSetAsync instead.");
}
#else
var internalClient = SourceTable.DDBClient;
#endif

if (!IsDone)
{
switch (SearchMethod)
Expand Down Expand Up @@ -253,7 +265,7 @@ internal List<Document> GetNextSetHelper()

SourceTable.AddRequestHandler(scanReq, isAsync: false);

var scanResult = SourceTable.DDBClient.Scan(scanReq);
var scanResult = internalClient.Scan(scanReq);
foreach (var item in scanResult.Items)
{
Document doc = SourceTable.FromAttributeMap(item);
Expand Down Expand Up @@ -303,7 +315,7 @@ internal List<Document> GetNextSetHelper()

SourceTable.AddRequestHandler(queryReq, isAsync: false);

var queryResult = SourceTable.DDBClient.Query(queryReq);
var queryResult = internalClient.Query(queryReq);
foreach (var item in queryResult.Items)
{
Document doc = SourceTable.FromAttributeMap(item);
Expand Down Expand Up @@ -532,6 +544,17 @@ private int GetCount()
}
else
{
#if NETSTANDARD
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
var internalClient = SourceTable.DDBClient as AmazonDynamoDBClient;
if (internalClient == null)
{
throw new InvalidOperationException("Accessing the synchronous Count from .NET or .NET Core requires " +
"initializing the Table with an actual AmazonDynamoDBClient.");
}
#else
var internalClient = SourceTable.DDBClient;
#endif
switch (SearchMethod)
{
case SearchType.Scan:
Expand All @@ -558,7 +581,7 @@ private int GetCount()

SourceTable.AddRequestHandler(scanReq, isAsync: false);

var scanResult = SourceTable.DDBClient.Scan(scanReq);
var scanResult = internalClient.Scan(scanReq);
count = Matches.Count + scanResult.Count.GetValueOrDefault();
return count;
case SearchType.Query:
Expand All @@ -583,7 +606,7 @@ private int GetCount()

SourceTable.AddRequestHandler(queryReq, isAsync: false);

var queryResult = SourceTable.DDBClient.Query(queryReq);
var queryResult = internalClient.Query(queryReq);
count = Matches.Count + queryResult.Count.GetValueOrDefault();
return count;
default:
Expand Down
84 changes: 67 additions & 17 deletions sdk/src/Services/DynamoDBv2/Custom/DocumentModel/Table.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,7 @@ internal enum DynamoDBConsumer
internal bool IsEmptyStringValueEnabled { get { return Config.IsEmptyStringValueEnabled; } }
internal IEnumerable<string> StoreAsEpoch { get { return Config.AttributesToStoreAsEpoch; } }
internal IEnumerable<string> KeyNames { get { return Keys.Keys; } }

#if NETSTANDARD
internal AmazonDynamoDBClient DDBClient { get; private set; }
#else
internal IAmazonDynamoDB DDBClient { get; private set; }
#endif

#endregion

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

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

var info = client.DescribeTable(req);

if (info.Table == null)
{
Expand Down Expand Up @@ -413,11 +420,7 @@ internal Table(IAmazonDynamoDB ddbClient, TableConfig config)
if (ddbClient == null)
throw new ArgumentNullException("ddbClient");

#if NETSTANDARD
DDBClient = ddbClient as AmazonDynamoDBClient;
#else
DDBClient = ddbClient;
#endif
Config = config;
}

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

var resp = DDBClient.PutItem(req);
#if NETSTANDARD
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
var client = DDBClient as AmazonDynamoDBClient;
if (client == null)
{
throw new InvalidOperationException("Calling the synchronous PutItem from .NET or .NET Core requires initializing the Table " +
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when creating a Table via PutItemAsync instead.");
}
#else
var client = DDBClient;
#endif

var resp = client.PutItem(req);
doc.CommitChanges();

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

this.AddRequestHandler(request, isAsync: false);

#if NETSTANDARD
// Cast the IAmazonDynamoDB to the concrete client instead, so we can access the internal sync-over-async methods
var client = DDBClient as AmazonDynamoDBClient;
if (client == null)
{
throw new InvalidOperationException("Calling the synchronous GetItem from .NET or .NET Core requires initializing the Table " +
"with an actual AmazonDynamoDBClient. You can use a mocked or substitute IAmazonDynamoDB when creating a Table via GetItemAsync instead.");
}
#else
var client = DDBClient;
#endif

if (currentConfig.AttributesToGet != null)
request.AttributesToGet = currentConfig.AttributesToGet;

var result = DDBClient.GetItem(request);
var result = client.GetItem(request);
var attributeMap = result.Item;
if (attributeMap == null || attributeMap.Count == 0)
return null;
Expand Down Expand Up @@ -1047,7 +1074,7 @@ internal async Task<Document> GetItemHelperAsync(Key key, GetItemOperationConfig
}
#endif

#endregion
#endregion


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

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

var resp = DDBClient.UpdateItem(req);
var resp = client.UpdateItem(req);
var returnedAttributes = resp.Attributes;
doc.CommitChanges();

Expand All @@ -1145,7 +1183,7 @@ internal Document UpdateHelper(Document doc, Key key, UpdateItemOperationConfig
return ret;
}

#if AWS_ASYNC_API
#if AWS_ASYNC_API
internal async Task<Document> UpdateHelperAsync(Document doc, Key key, UpdateItemOperationConfig config, CancellationToken cancellationToken)
{
var currentConfig = config ?? new UpdateItemOperationConfig();
Expand Down Expand Up @@ -1275,7 +1313,19 @@ internal Document DeleteHelper(Key key, DeleteItemOperationConfig config)
currentConfig.ConditionalExpression.ApplyExpression(req, this);
}

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

var attributes = client.DeleteItem(req).Attributes;

Document ret = null;
if (currentConfig.ReturnValues == ReturnValues.AllOldAttributes)
Expand Down
Loading