Sql 
PM> Install-Package Shuttle.Recall.Sql.StorageA Sql implementation of the Shuttle.Recall event sourcing EventStore.
Configuration 
This package makes use of the Data Access components, which would also need to be registered.
DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", SqlClientFactory.Instance);
services
    .AddDataAccess(builder =>
    {
        // will get the connection string with name 'EventStore'
        builder.AddConnectionString("EventStore", "Microsoft.Data.SqlClient");
    })
    .AddSqlEventStorage(builder => 
    {
        builder.Options.ConnectionStringName = "EventStore";
        // defaults
        builder.Options.Schema = "dbo";
        builder.Options.ConfigureDatabase = true;
        builder.Options.UncommittedTolerance = TimeSpan.FromSeconds(15);
        builder.UseSqlServer();
    });Options 
The SqlStorageOptions contains the following options:
| Option | Default | Description | 
|---|---|---|
ConnectionStringName | "" | The connecting string name representing the event store. | 
Schema | dbo | The schema that the database structure belong to. | 
ConfigureDatabase | true | If true the EventStoreHostedService will create the database structures if they do not exist. | 
UncommittedTolerance | 00:00:15 | Any uncommitted events will be set to committed. This will prevent edge cases from leaving events uncommitted when they have been committed within a transaction. The edge case can come about since setting the committed date on an event is invoked in the Completed stage of the SaveEventStreamPipeline, so it is handled in a separate transaction. | 
Database 
The package contains an implementation of an IHostedService called EventStoreHostedService which will create the required database structures if ConfigureDatabase is set to true (which is the default).
Supported providers 
Microsoft.Data.SqlClient
If you'd like support for another SQL-based provider you are welcome to create an issue and assistance will be provided where possible; else a pull request would be appreciated.
IdKeyRepository 
You are bound to run into situations where you have a business or other key that is required to be unique. Given that the IEventStore makes use of only surrogate keys the IdKeyRepository is used to create a unique list of keys associated with a given aggregate identifier.
Since the keys used in the associated IdKey table have to be unique, you should ensure that they contain enough information to be unique and have the intended meaning.
A key could be something such as [order-number]:ord-001/2016, [customer-onboarding]:id-number=0000005555089, or [system-name/profile]:672cda1c-c3ec-4f81-a577-e64f9f14e141.
Contains 
ValueTask<bool> ContainsAsync(string key, CancellationToken cancellationToken = default);Returns true if the given key has an associated aggregate identifier.
ValueTask<bool> ContainsAsync(Guid id, CancellationToken cancellationToken = default);Returns true if the given id is present in the key store.
Find 
ValueTask<Guid?> FindAsync(string key, CancellationToken cancellationToken = default);Returns the Guid associated with the given key; else null.
Remove 
Task RemoveAsync(string key, CancellationToken cancellationToken = default);
Task RemoveAsync(Guid id, CancellationToken cancellationToken = default);When specifying the key the assocation with the identifier will be removed. When specifying the id all keys associated with the given id will be removed.
Add 
Task AddAsync(Guid id, string key, CancellationToken cancellationToken = default);Creates an association between the id and the key.
Add 
Task RekeyAsync(string key, string rekey, CancellationToken cancellationToken = default);Changes key to a new key specified by rekey.