//--- Methods --- private void PrepareRequest(bool fetchAllAttributes) { // inherit the expected types from the query select construct foreach (var expectedType in _queryClause.TypeFilters) { _converter.AddExpectedType(expectedType); } // initialize request _request.IndexName = _queryClause.IndexName; _request.KeyConditionExpression = _queryClause.GetKeyConditionExpression(_converter); _request.FilterExpression = _converter.ConvertConditions(_table.Options); _request.ProjectionExpression = _converter.ConvertProjections(); // NOTE (2021-06-23, bjorg): the following logic matches the default behavior, but makes it explicit // if `ProjectionExpression` is set, only return specified attributes; otherwise, for an index, return projected attributes only; for tables, return all attributes from each row if (_request.ProjectionExpression is null) { if ((_request.IndexName is null) || fetchAllAttributes) { _request.Select = Select.ALL_ATTRIBUTES; } else { _request.Select = Select.ALL_PROJECTED_ATTRIBUTES; } }
public async Task <TRecord?> ExecuteAsync(CancellationToken cancellationToken) { _request.ProjectionExpression = _converter.ConvertProjections(); var response = await _table.DynamoClient.GetItemAsync(_request, cancellationToken); return(response.IsItemSet ? _table.DeserializeItem <TRecord>(response.Item) : null); }
public async Task <IEnumerable <TRecord> > ExecuteAsync(int maxAttempts, CancellationToken cancellationToken = default) { var requestTableAndKeys = _request.RequestItems.First(); requestTableAndKeys.Value.ProjectionExpression = _converter.ConvertProjections(); // NOTE (2021-06-30, bjorg): batch operations may run out of capacity/bandwidth and may have to be completed in batches themselves var result = new List <TRecord>(); var attempts = 1; do { try { var response = await _table.DynamoClient.BatchGetItemAsync(_request, cancellationToken); if (response.Responses.Any()) { foreach (var item in response.Responses.Single().Value) { var record = _table.DeserializeItem <TRecord>(item); if (!(record is null)) { result.Add(record); } } } // check if all requested primary keys were processed if (!response.UnprocessedKeys.Any()) { break; } // repeat request with unprocessed primary keys requestTableAndKeys.Value.Keys = response.UnprocessedKeys.First().Value.Keys; } catch (ProvisionedThroughputExceededException) { // NOTE (2021-06-30, bjorg): not a single item could be returned due to insufficient read capacity } // use exponential backoff before attempting next operation if (attempts >= maxAttempts) { throw new DynamoTableBatchGetItemsMaxAttemptsExceededException(result); } await Task.Delay(TimeSpan.FromMilliseconds(MILLISECOND_BACKOFF << (attempts++ - 1))); } while(true); return(result); }