Kanject.Core.SqlDatabase

Beta · Aurora DSQL provider

The relational sibling to Kanject.Core.NoSqlDatabase. Same [Repository] shape, same source generator, same testable interface — running on Amazon Aurora DSQL. Currently in beta: the public API is stable, but a small number of provider-level options will still land in the next minor release.

Install

bash
dotnet add package Kanject.Core.SqlDatabase

Register

csharp
using Kanject.Core.SqlDatabase.Provider.AuroraDsql.Extensions;

builder.Services.AddAuroraDsqlSqlDatabase(options =>
{
    options.ClusterEndpoint = appSettings.AuroraDsqlEndpoint;
    options.AwsRegion       = appSettings.AwsRegion;
    options.Namespace       = appSettings.DatabaseNamespace; // e.g. "prod"
});

Namespace prefixes every table at runtime (prod_Orders, staging_Orders) so multiple stages can share a single cluster safely.

Define a repository

csharp
using Kanject.Core.SqlDatabase.Abstractions;
using Kanject.Core.SqlDatabase.Abstractions.Attributes;

[Repository(table: "Orders")]
public partial interface IOrderRepository : IRepository<Order>
{
    [Query(by: nameof(Order.CustomerId))]
    Task<IReadOnlyList<Order>> ListByCustomerAsync(Guid customerId);

    [Query(by: nameof(Order.Status), index: "ByStatus")]
    Task<IReadOnlyList<Order>> ListByStatusAsync(OrderStatus status);
}

public record Order
{
    [PrimaryKey]                         public Guid   Id          { get; init; }
    [Indexed("ByCustomer")]              public Guid   CustomerId  { get; init; }
    [Indexed("ByStatus")]                public OrderStatus Status { get; init; }
    public decimal        Total     { get; init; }
    public DateTimeOffset PlacedAt  { get; init; }
}

The partial interface is filled in by the source generator. [Query] methods compile to parameterised SQL; [Indexed] declares the secondary indexes they rely on. The shape is identical to Kanject.Core.NoSqlDatabase — teams already on NoSqlDatabase adopt SqlDatabase without learning a new pattern.

Use it

csharp
public class OrderService(IOrderRepository orders)
{
    public Task<Order?> GetAsync(Guid id) => orders.FindAsync(id);

    public Task<IReadOnlyList<Order>> ListForCustomerAsync(Guid customerId)
        => orders.ListByCustomerAsync(customerId);

    public Task MarkPaidAsync(Guid id)
        => orders.UpdateAsync(id, o => o with { Status = OrderStatus.Paid });
}

What ships with it

  • Aurora DSQL provider — Amazon's serverless, multi-region-active SQL engine
  • Source-generated repository implementations — zero reflection at runtime
  • Strongly-typed indexed queries with compile-time validation
  • Automatic Namespace prefixing for multi-stage isolation
  • Optimistic concurrency via [Version] attribute
  • Mockable IRepository<T> interface for unit tests
Beta caveats
Public APIs are stable. Provider-level options (IAM auth flow, custom retry strategies, read-replica routing) may grow in the next minor. Please report any roughness via /contact — beta feedback shapes the v1 cut.