Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion src/Benchmarks/Benchmarks/SignerBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public async Task SetupAsync()
ReturnConsumedCapacity = ReturnConsumedCapacity.Total
};

var httpContent = new GetItemHttpContent(request, request.TableName, request.Key.PartitionKeyName!, request.Key.SortKeyName);
var httpContent = new GetItemHttpContent(request, null, request.Key.PartitionKeyName!, request.Key.SortKeyName);
_httpRequest = new HttpRequestMessage(HttpMethod.Post, RegionEndpoint.USEast1.RequestUri)
{
Content = httpContent
Expand Down
19 changes: 19 additions & 0 deletions src/EfficientDynamoDb/Configs/ITableNameFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;

namespace EfficientDynamoDb.Configs
{
public readonly struct TableNameFormatterContext
{
public TableNameFormatterContext(string tableName) {
TableName = tableName;
}

public string TableName { get; }
}

public interface ITableNameFormatter
{
int CalculateLength(ref TableNameFormatterContext context);
bool TryFormat(Span<char> buffer, ref TableNameFormatterContext context, out int length);
}
}
27 changes: 27 additions & 0 deletions src/EfficientDynamoDb/Configs/PrefixTableNameFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Runtime.CompilerServices;

namespace EfficientDynamoDb.Configs
{
public class PrefixTableNameFormatter : ITableNameFormatter
{
public string Prefix { get; }

public PrefixTableNameFormatter(string prefix) {
Prefix = prefix;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int CalculateLength(ref TableNameFormatterContext context) => Prefix.Length + context.TableName.Length;

public bool TryFormat(Span<char> buffer, ref TableNameFormatterContext context, out int length) {
length = CalculateLength(ref context);
if( buffer.Length < length ) {
return false;
}
Prefix.AsSpan().CopyTo(buffer);
context.TableName.AsSpan().CopyTo(buffer[Prefix.Length..]);
return true;
}
}
}
39 changes: 39 additions & 0 deletions src/EfficientDynamoDb/Configs/TableNameFormatterExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using EfficientDynamoDb.Exceptions;
using EfficientDynamoDb.Internal.Core;

namespace EfficientDynamoDb.Configs
{
internal static class TableNameFormatterExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteTableName<TState>(this ITableNameFormatter tableNameFormatter, string tableName, TState state, SpanAction<char,TState> writer) {
var tableNameContext = new TableNameFormatterContext(tableName);
var length = tableNameFormatter.CalculateLength(ref tableNameContext);

char[]? pooledArray = null;
var arr = length < NoAllocStringBuilder.MaxStackAllocSize
? stackalloc char[length]
: pooledArray = ArrayPool<char>.Shared.Rent(length);

try
{
if( !tableNameFormatter.TryFormat(arr, ref tableNameContext, out length) ) {
throw new DdbException($"Couldn't format table name '{tableName}' using the provided formatter");
}

writer(arr[..length], state);
}
finally
{
if (pooledArray != null)
{
pooledArray.AsSpan(0, length).Clear();
ArrayPool<char>.Shared.Return(pooledArray);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public partial class DynamoDbContext

internal async Task BatchWriteItemAsync(BuilderNode node, CancellationToken cancellationToken = default)
{
using var httpContent = new BatchWriteItemHighLevelHttpContent(this, node, Config.TableNamePrefix);
using var httpContent = new BatchWriteItemHighLevelHttpContent(this, node, Config.TableNameFormatter);

using var response = await Api.SendAsync(Config, httpContent, cancellationToken).ConfigureAwait(false);
var documentResult = await DynamoDbLowLevelContext.ReadDocumentAsync(response, BatchWriteItemParsingOptions.Instance, cancellationToken).ConfigureAwait(false);
Expand All @@ -47,7 +47,7 @@ internal async Task BatchWriteItemAsync(BuilderNode node, CancellationToken canc

internal async Task<BatchWriteItemResponse> BatchWriteItemResponseAsync(BuilderNode node, CancellationToken cancellationToken = default)
{
using var httpContent = new BatchWriteItemHighLevelHttpContent(this, node, Config.TableNamePrefix);
using var httpContent = new BatchWriteItemHighLevelHttpContent(this, node, Config.TableNameFormatter);

using var response = await Api.SendAsync(Config, httpContent, cancellationToken).ConfigureAwait(false);
var documentResult = await DynamoDbLowLevelContext.ReadDocumentAsync(response, BatchWriteItemParsingOptions.Instance, cancellationToken).ConfigureAwait(false);
Expand Down
26 changes: 13 additions & 13 deletions src/EfficientDynamoDb/DynamoDbContext/DynamoDbLowLevelContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public async Task<GetItemResponse> GetItemAsync(GetItemRequest request, Cancella

public async Task<BatchGetItemResponse> BatchGetItemAsync(BatchGetItemRequest request, CancellationToken cancellationToken = default)
{
using var httpContent = new BatchGetItemHttpContent(request, Config.TableNamePrefix);
using var httpContent = new BatchGetItemHttpContent(request, Config.TableNameFormatter);

using var response = await Api.SendAsync(Config, httpContent, cancellationToken).ConfigureAwait(false);
var result = await ReadDocumentAsync(response, BatchGetItemParsingOptions.Instance, cancellationToken).ConfigureAwait(false);
Expand All @@ -67,7 +67,7 @@ public async Task<BatchGetItemResponse> BatchGetItemAsync(BatchGetItemRequest re

public async Task<BatchWriteItemResponse> BatchWriteItemAsync(BatchWriteItemRequest request, CancellationToken cancellationToken = default)
{
using var httpContent = new BatchWriteItemHttpContent(request, Config.TableNamePrefix);
using var httpContent = new BatchWriteItemHttpContent(request, Config.TableNameFormatter);

using var response = await Api.SendAsync(Config, httpContent, cancellationToken).ConfigureAwait(false);
var result = await ReadDocumentAsync(response, BatchWriteItemParsingOptions.Instance, cancellationToken).ConfigureAwait(false);
Expand All @@ -77,7 +77,7 @@ public async Task<BatchWriteItemResponse> BatchWriteItemAsync(BatchWriteItemRequ

public async Task<QueryResponse> QueryAsync(QueryRequest request, CancellationToken cancellationToken = default)
{
using var httpContent = new QueryHttpContent(request, Config.TableNamePrefix);
using var httpContent = new QueryHttpContent(request, Config.TableNameFormatter);

using var response = await Api.SendAsync(Config, httpContent, cancellationToken).ConfigureAwait(false);
var result = await ReadDocumentAsync(response, QueryParsingOptions.Instance, cancellationToken).ConfigureAwait(false);
Expand All @@ -87,7 +87,7 @@ public async Task<QueryResponse> QueryAsync(QueryRequest request, CancellationTo

public async Task<ScanResponse> ScanAsync(ScanRequest request, CancellationToken cancellationToken = default)
{
using var httpContent = new ScanHttpContent(request, Config.TableNamePrefix);
using var httpContent = new ScanHttpContent(request, Config.TableNameFormatter);

using var response = await Api.SendAsync(Config, httpContent, cancellationToken).ConfigureAwait(false);
var result = await ReadDocumentAsync(response, QueryParsingOptions.Instance, cancellationToken).ConfigureAwait(false);
Expand All @@ -97,7 +97,7 @@ public async Task<ScanResponse> ScanAsync(ScanRequest request, CancellationToken

public async Task<TransactGetItemsResponse> TransactGetItemsAsync(TransactGetItemsRequest request, CancellationToken cancellationToken = default)
{
using var httpContent = new TransactGetItemsHttpContent(request, Config.TableNamePrefix);
using var httpContent = new TransactGetItemsHttpContent(request, Config.TableNameFormatter);

using var response = await Api.SendAsync(Config, httpContent, cancellationToken).ConfigureAwait(false);
var result = await ReadDocumentAsync(response, TransactGetItemsParsingOptions.Instance, cancellationToken).ConfigureAwait(false);
Expand All @@ -107,7 +107,7 @@ public async Task<TransactGetItemsResponse> TransactGetItemsAsync(TransactGetIte

public async Task<PutItemResponse> PutItemAsync(PutItemRequest request, CancellationToken cancellationToken = default)
{
using var httpContent = new PutItemHttpContent(request, Config.TableNamePrefix);
using var httpContent = new PutItemHttpContent(request, Config.TableNameFormatter);

using var response = await Api.SendAsync(Config, httpContent, cancellationToken).ConfigureAwait(false);
var result = await ReadDocumentAsync(response, PutItemParsingOptions.Instance, cancellationToken).ConfigureAwait(false);
Expand All @@ -131,7 +131,7 @@ public async Task<DeleteItemResponse> DeleteItemAsync(DeleteItemRequest request,
? (request.Key.PartitionKeyName!, request.Key.SortKeyName)
: await GetKeyNamesAsync(request.TableName).ConfigureAwait(false);

using var httpContent = new DeleteItemHttpContent(request, pkName, skName, Config.TableNamePrefix);
using var httpContent = new DeleteItemHttpContent(request, pkName, skName, Config.TableNameFormatter);

using var response = await Api.SendAsync(Config, httpContent, cancellationToken).ConfigureAwait(false);
var result = await ReadDocumentAsync(response, PutItemParsingOptions.Instance, cancellationToken).ConfigureAwait(false);
Expand All @@ -141,7 +141,7 @@ public async Task<DeleteItemResponse> DeleteItemAsync(DeleteItemRequest request,

public async Task<TransactWriteItemsResponse> TransactWriteItemsAsync(TransactWriteItemsRequest request, CancellationToken cancellationToken = default)
{
using var httpContent = new TransactWriteItemsHttpContent(request, Config.TableNamePrefix);
using var httpContent = new TransactWriteItemsHttpContent(request, Config.TableNameFormatter);

using var response = await Api.SendAsync(Config, httpContent, cancellationToken).ConfigureAwait(false);
var result = await ReadDocumentAsync(response, TransactWriteItemsParsingOptions.Instance, cancellationToken).ConfigureAwait(false);
Expand All @@ -165,19 +165,19 @@ private async ValueTask<GetItemResponse> GetItemInternalAsync(HttpContent httpCo
private async ValueTask<HttpContent> BuildHttpContentAsync(GetItemRequest request)
{
if (request.Key!.HasKeyNames)
return new GetItemHttpContent(request, Config.TableNamePrefix, request.Key.PartitionKeyName!, request.Key.SortKeyName!);
return new GetItemHttpContent(request, Config.TableNameFormatter, request.Key.PartitionKeyName!, request.Key.SortKeyName!);

var (remotePkName, remoteSkName) = await GetKeyNamesAsync(request.TableName);
return new GetItemHttpContent(request, Config.TableNamePrefix, remotePkName, remoteSkName!);
return new GetItemHttpContent(request, Config.TableNameFormatter, remotePkName, remoteSkName!);
}

private async ValueTask<HttpContent> BuildHttpContentAsync(UpdateItemRequest request)
{
if (request.Key!.HasKeyNames)
return new UpdateItemHttpContent(request, Config.TableNamePrefix, request.Key.PartitionKeyName!, request.Key.SortKeyName!);
return new UpdateItemHttpContent(request, Config.TableNameFormatter, request.Key.PartitionKeyName!, request.Key.SortKeyName!);

var (remotePkName, remoteSkName) = await GetKeyNamesAsync(request.TableName);
return new UpdateItemHttpContent(request, Config.TableNamePrefix, remotePkName, remoteSkName!);
return new UpdateItemHttpContent(request, Config.TableNameFormatter, remotePkName, remoteSkName!);
}

private async ValueTask<(string Pk, string? Sk)> GetKeyNamesAsync(string tableName)
Expand All @@ -192,7 +192,7 @@ private async ValueTask<HttpContent> BuildHttpContentAsync(UpdateItemRequest req

async Task<(string Pk, string? Sk)> CreateKeyNamesTaskAsync(string table)
{
var response = await Api.SendAsync<DescribeTableResponse>(Config, new DescribeTableRequestHttpContent(Config.TableNamePrefix, tableName))
var response = await Api.SendAsync<DescribeTableResponse>(Config, new DescribeTableRequestHttpContent(Config.TableNameFormatter, tableName))
.ConfigureAwait(false);

var keySchema = response.Table.KeySchema;
Expand Down
8 changes: 7 additions & 1 deletion src/EfficientDynamoDb/DynamoDbContextConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ public class DynamoDbContextConfig

internal DynamoDbContextMetadata Metadata { get; private set; }

public string? TableNamePrefix { get; set; }
[Obsolete("Use TableNameFormatter property instead")]
public string? TableNamePrefix {
get => TableNameFormatter is PrefixTableNameFormatter f ? f.Prefix : null;
set => TableNameFormatter = value == null ? null : new PrefixTableNameFormatter(value);
}

public ITableNameFormatter? TableNameFormatter { get; set; }

public RetryStrategies RetryStrategies { get; } = new RetryStrategies();

Expand Down
2 changes: 1 addition & 1 deletion src/EfficientDynamoDb/DynamoDbManagementContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public DynamoDbManagementContext(DynamoDbContextConfig config)

public async Task<DescribeTableResponse> DescribeTableAsync(string tableName, CancellationToken cancellationToken = default)
{
var httpContent = new DescribeTableRequestHttpContent(_config.TableNamePrefix, tableName);
var httpContent = new DescribeTableRequestHttpContent(_config.TableNameFormatter, tableName);

var response = await _api.SendAsync<DescribeTableResponse>(_config, httpContent, cancellationToken).ConfigureAwait(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static void WriteUpdateItem(this in DdbWriter ddbWriter, DynamoDbContextC
break;
}
case BuilderNodeType.TableName:
((TableNameNode) currentNode).WriteTableName(in ddbWriter, ref writeState, config.TableNamePrefix);
((TableNameNode) currentNode).WriteTableName(in ddbWriter, ref writeState, config.TableNameFormatter);
break;
default:
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Threading.Tasks;
using EfficientDynamoDb.Configs;
using EfficientDynamoDb.Converters;
using EfficientDynamoDb.DocumentModel;
using EfficientDynamoDb.Exceptions;
using EfficientDynamoDb.FluentCondition.Core;
using EfficientDynamoDb.FluentCondition.Factories;
using EfficientDynamoDb.Internal.Core;
Expand Down Expand Up @@ -43,36 +45,16 @@ public static void WriteAttributesDictionary(this Utf8JsonWriter writer, IReadOn
writer.WriteEndObject();
}

public static void WriteTableName(this Utf8JsonWriter writer, string? prefix, string tableName)
public static void WriteTableName(this Utf8JsonWriter writer, ITableNameFormatter? tableNameFormatter, string tableName)
{
const string tableNameKey = "TableName";
if (prefix == null)
if (tableNameFormatter == null)
{
writer.WriteString(tableNameKey, tableName);
return;
}

var fullLength = prefix.Length + tableName.Length;

char[]? pooledArray = null;
var arr = fullLength < NoAllocStringBuilder.MaxStackAllocSize
? stackalloc char[fullLength]
: pooledArray = ArrayPool<char>.Shared.Rent(fullLength);

try
{
prefix.AsSpan().CopyTo(arr);
tableName.AsSpan().CopyTo(arr.Slice(prefix.Length));
writer.WriteString(tableNameKey, arr);
}
finally
{
if (pooledArray != null)
{
pooledArray.AsSpan(0, fullLength).Clear();
ArrayPool<char>.Shared.Return(pooledArray);
}
}
tableNameFormatter.WriteTableName(tableName, writer, (arr, w) => w.WriteString(tableNameKey, arr));
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ private async Task WriteItems(DdbWriter ddbWriter, BatchItemsNode<IBatchGetItemB
writer.WriteEndObject();
}

WriteTableNameAsKey(writer, _context.Config.TableNamePrefix, tableName!);
WriteTableNameAsKey(writer, _context.Config.TableNameFormatter, tableName!);
writer.WriteStartObject();

writer.WritePropertyName("Keys");
Expand Down Expand Up @@ -133,7 +133,7 @@ private async Task WriteTables(DdbWriter ddbWriter, BatchItemsNode<IBatchGetTabl

foreach (var tableBuilder in tablesNode.Value)
{
WriteTableNameAsKey(writer, _context.Config.TableNamePrefix, GetTableName(tableBuilder));
WriteTableNameAsKey(writer, _context.Config.TableNameFormatter, GetTableName(tableBuilder));
writer.WriteStartObject();

var hasProjections = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using EfficientDynamoDb.Configs;
using EfficientDynamoDb.Converters;
using EfficientDynamoDb.Internal.Extensions;
using EfficientDynamoDb.Internal.Operations.Shared;
Expand All @@ -10,12 +11,12 @@ namespace EfficientDynamoDb.Internal.Operations.BatchGetItem
internal sealed class BatchGetItemHttpContent : BatchItemHttpContent
{
private readonly BatchGetItemRequest _request;
private readonly string? _tableNamePrefix;
private readonly ITableNameFormatter? _tableNameFormatter;

public BatchGetItemHttpContent(BatchGetItemRequest request, string? tableNamePrefix) : base("DynamoDB_20120810.BatchGetItem")
public BatchGetItemHttpContent(BatchGetItemRequest request, ITableNameFormatter? tableNameFormatter) : base("DynamoDB_20120810.BatchGetItem")
{
_request = request;
_tableNamePrefix = tableNamePrefix;
_tableNameFormatter = tableNameFormatter;
}

protected override async ValueTask WriteDataAsync(DdbWriter ddbWriter)
Expand All @@ -28,7 +29,7 @@ protected override async ValueTask WriteDataAsync(DdbWriter ddbWriter)

foreach (var item in _request.RequestItems!)
{
WriteTableNameAsKey(writer, _tableNamePrefix, item.Key);
WriteTableNameAsKey(writer, _tableNameFormatter, item.Key);
writer.WriteStartObject();

writer.WritePropertyName("Keys");
Expand Down
Loading