static async Task <(DynamoDbScoreDataV1 data, string hash)> GetAsync( IAmazonDynamoDB client, string tableName, Guid ownerId, Guid scoreId) { var partitionKey = ScoreDatabaseUtils.ConvertToPartitionKey(ownerId); var score = ScoreDatabaseUtils.ConvertToBase64(scoreId); var request = new GetItemRequest() { TableName = tableName, Key = new Dictionary <string, AttributeValue>() { [DynamoDbScorePropertyNames.PartitionKey] = new AttributeValue(partitionKey), [DynamoDbScorePropertyNames.SortKey] = new AttributeValue(ScoreDatabaseConstant.ScoreIdMainPrefix + score), }, }; var response = await client.GetItemAsync(request); var data = response.Item[DynamoDbScorePropertyNames.Data]; if (data is null) { throw new InvalidOperationException("not found."); } DynamoDbScoreDataV1.TryMapFromAttributeValue(data, out var result); var hash = response.Item[DynamoDbScorePropertyNames.DataHash].S; return(result, hash); }
static async Task <DynamoDbScore> GetAsync( IAmazonDynamoDB client, string tableName, Guid ownerId, Guid scoreId) { var partitionKey = ScoreDatabaseUtils.ConvertToPartitionKey(ownerId); var score = ScoreDatabaseUtils.ConvertToBase64(scoreId); var request = new GetItemRequest() { TableName = tableName, Key = new Dictionary <string, AttributeValue>() { [DynamoDbScorePropertyNames.PartitionKey] = new AttributeValue(partitionKey), [DynamoDbScorePropertyNames.SortKey] = new AttributeValue(ScoreDatabaseConstant.ScoreIdMainPrefix + score), }, }; var response = await client.GetItemAsync(request); if (!response.IsItemSet) { throw new NotFoundScoreException("Not found score."); } var dynamoDbScore = new DynamoDbScore(response.Item); return(dynamoDbScore); }
static async Task UpdateAsync( IAmazonDynamoDB client, string tableName, Guid ownerId, Guid scoreId, int[] removeIndices, string newHash, string oldHash, DateTimeOffset now ) { var partitionKey = ScoreDatabaseUtils.ConvertToPartitionKey(ownerId); var score = ScoreDatabaseUtils.ConvertToBase64(scoreId); var updateAt = ScoreDatabaseUtils.ConvertToUnixTimeMilli(now); var request = new UpdateItemRequest() { Key = new Dictionary <string, AttributeValue>() { [DynamoDbScorePropertyNames.PartitionKey] = new AttributeValue(partitionKey), [DynamoDbScorePropertyNames.SortKey] = new AttributeValue(ScoreDatabaseConstant.ScoreIdMainPrefix + score), }, ExpressionAttributeNames = new Dictionary <string, string>() { ["#updateAt"] = DynamoDbScorePropertyNames.UpdateAt, ["#hash"] = DynamoDbScorePropertyNames.DataHash, ["#data"] = DynamoDbScorePropertyNames.Data, ["#pages"] = DynamoDbScorePropertyNames.DataPropertyNames.Pages, }, ExpressionAttributeValues = new Dictionary <string, AttributeValue>() { [":newHash"] = new AttributeValue(newHash), [":oldHash"] = new AttributeValue(oldHash), [":updateAt"] = new AttributeValue(updateAt), }, ConditionExpression = "#hash = :oldHash", UpdateExpression = $"SET #updateAt = :updateAt, #hash = :newHash REMOVE {string.Join(", ", removeIndices.Select(i=>$"#data.#pages[{i}]"))}", TableName = tableName, }; try { await client.UpdateItemAsync(request); } catch (Exception ex) { Console.WriteLine(ex.Message); throw; } }
static async Task <ScoreSnapshotSummary[]> GetAsync(IAmazonDynamoDB client, string tableName, Guid ownerId, Guid scoreId) { var partitionKey = ScoreDatabaseUtils.ConvertToPartitionKey(ownerId); var score = ScoreDatabaseUtils.ConvertToBase64(scoreId); var request = new QueryRequest() { TableName = tableName, ExpressionAttributeNames = new Dictionary <string, string>() { ["#owner"] = DynamoDbScorePropertyNames.PartitionKey, ["#score"] = DynamoDbScorePropertyNames.SortKey, ["#snapshotName"] = DynamoDbScorePropertyNames.SnapshotName, ["#createAt"] = DynamoDbScorePropertyNames.CreateAt, }, ExpressionAttributeValues = new Dictionary <string, AttributeValue>() { [":owner"] = new AttributeValue(partitionKey), [":snapPrefix"] = new AttributeValue(ScoreDatabaseConstant.ScoreIdSnapPrefix + score), }, KeyConditionExpression = "#owner = :owner and begins_with(#score, :snapPrefix)", ProjectionExpression = "#score, #snapshotName, #createAt", }; try { var response = await client.QueryAsync(request); var subStartIndex = (ScoreDatabaseConstant.ScoreIdSnapPrefix + score).Length; return(response.Items .Select(x => ( score: x[DynamoDbScorePropertyNames.SortKey].S, name: x[DynamoDbScorePropertyNames.SnapshotName].S, createAt: x[DynamoDbScorePropertyNames.CreateAt].S) ) .Select(x => new ScoreSnapshotSummary() { Id = ScoreDatabaseUtils.ConvertToGuid(x.score.Substring(subStartIndex)), Name = x.name, CreateAt = ScoreDatabaseUtils.ConvertFromUnixTimeMilli(x.createAt), } ) .ToArray()); } catch (InternalServerErrorException ex) { Console.WriteLine(ex.Message); throw; } catch (ProvisionedThroughputExceededException ex) { Console.WriteLine(ex.Message); throw; } catch (RequestLimitExceededException ex) { Console.WriteLine(ex.Message); throw; } catch (ResourceNotFoundException ex) { Console.WriteLine(ex.Message); throw; } catch (Exception ex) { Console.WriteLine(ex.Message); throw; } }
static async Task DeleteItemAsync( IAmazonDynamoDB client, string tableName, Guid ownerId, Guid scoreId, Guid snapshotId ) { var partitionKey = ScoreDatabaseUtils.ConvertToPartitionKey(ownerId); var score = ScoreDatabaseUtils.ConvertToBase64(scoreId); var snapshot = ScoreDatabaseUtils.ConvertToBase64(snapshotId); var actions = new List <TransactWriteItem>() { new TransactWriteItem() { Delete = new Delete() { TableName = tableName, Key = new Dictionary <string, AttributeValue>() { [DynamoDbScorePropertyNames.PartitionKey] = new AttributeValue(partitionKey), [DynamoDbScorePropertyNames.SortKey] = new AttributeValue(ScoreDatabaseConstant.ScoreIdSnapPrefix + score + snapshot), }, ExpressionAttributeNames = new Dictionary <string, string>() { ["#score"] = DynamoDbScorePropertyNames.SortKey, }, ConditionExpression = "attribute_exists(#score)", }, }, new TransactWriteItem() { Update = new Update() { TableName = tableName, Key = new Dictionary <string, AttributeValue>() { [DynamoDbScorePropertyNames.PartitionKey] = new AttributeValue(partitionKey), [DynamoDbScorePropertyNames.SortKey] = new AttributeValue(ScoreDatabaseConstant.ScoreIdMainPrefix + score), }, ExpressionAttributeNames = new Dictionary <string, string>() { ["#snapshotCount"] = DynamoDbScorePropertyNames.SnapshotCount, }, ExpressionAttributeValues = new Dictionary <string, AttributeValue>() { [":increment"] = new AttributeValue() { N = "-1" }, }, UpdateExpression = "ADD #snapshotCount :increment", } }, }; try { await client.TransactWriteItemsAsync(new TransactWriteItemsRequest() { TransactItems = actions, ReturnConsumedCapacity = ReturnConsumedCapacity.TOTAL, }); } catch (TransactionCanceledException ex) { var deleteReason = ex.CancellationReasons[0]; if (deleteReason.Code == "ConditionalCheckFailed") { throw new NotFoundSnapshotException(ex); } throw; } catch (Exception ex) { Console.WriteLine(ex.Message); throw; } }
static async Task UpdateAsync( IAmazonDynamoDB client, string tableName, Guid ownerId, Guid scoreId, Guid snapshotId, string snapshotName, DateTimeOffset now, int maxSnapshotCount ) { var partitionKey = ScoreDatabaseUtils.ConvertToPartitionKey(ownerId); var score = ScoreDatabaseUtils.ConvertToBase64(scoreId); var snapshot = ScoreDatabaseUtils.ConvertToBase64(snapshotId); var at = ScoreDatabaseUtils.ConvertToUnixTimeMilli(now); var actions = new List <TransactWriteItem>() { new TransactWriteItem() { Update = new Update() { TableName = tableName, Key = new Dictionary <string, AttributeValue>() { [DynamoDbScorePropertyNames.PartitionKey] = new AttributeValue(partitionKey), [DynamoDbScorePropertyNames.SortKey] = new AttributeValue(ScoreDatabaseConstant.ScoreIdMainPrefix + score), }, ExpressionAttributeNames = new Dictionary <string, string>() { ["#snapshotCount"] = DynamoDbScorePropertyNames.SnapshotCount, }, ExpressionAttributeValues = new Dictionary <string, AttributeValue>() { [":increment"] = new AttributeValue() { N = "1" }, [":countMax"] = new AttributeValue() { N = maxSnapshotCount.ToString(), }, }, ConditionExpression = "#snapshotCount < :countMax", UpdateExpression = "ADD #snapshotCount :increment" } }, new TransactWriteItem() { Put = new Put() { TableName = tableName, Item = new Dictionary <string, AttributeValue>() { [DynamoDbScorePropertyNames.PartitionKey] = new AttributeValue(partitionKey), [DynamoDbScorePropertyNames.SortKey] = new AttributeValue(ScoreDatabaseConstant.ScoreIdSnapPrefix + score + snapshot), [DynamoDbScorePropertyNames.CreateAt] = new AttributeValue(at), [DynamoDbScorePropertyNames.UpdateAt] = new AttributeValue(at), [DynamoDbScorePropertyNames.SnapshotName] = new AttributeValue(snapshotName), }, ExpressionAttributeNames = new Dictionary <string, string>() { ["#score"] = DynamoDbScorePropertyNames.SortKey, }, ConditionExpression = "attribute_not_exists(#score)", } } }; try { await client.TransactWriteItemsAsync(new TransactWriteItemsRequest() { TransactItems = actions, ReturnConsumedCapacity = ReturnConsumedCapacity.TOTAL }); } catch (TransactionCanceledException ex) { var updateReason = ex.CancellationReasons[0]; if (updateReason.Code == "ConditionalCheckFailed") { throw new CreatedSnapshotException(CreatedSnapshotExceptionCodes.ExceededUpperLimit, ex); } throw; } catch (Exception ex) { Console.WriteLine(ex.Message); throw; } }