Skip to content
Merged
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
9 changes: 9 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project>

<PropertyGroup>
<!-- Select the appropriate Microsoft.Extensions version for the target framework -->
<MicrosoftExtensionsVersion Condition="'$(TargetFramework)' == 'net9.0'">9.0.15</MicrosoftExtensionsVersion>
<MicrosoftExtensionsVersion Condition="'$(TargetFramework)' == 'net10.0'">10.0.7</MicrosoftExtensionsVersion>
</PropertyGroup>

</Project>
60 changes: 60 additions & 0 deletions TaskTurnstile.SqlServer/SqlServerTableInitializerHostedService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Hosting;
using System.Data;

namespace TaskTurnstile.SqlServer;

internal sealed class SqlServerTableInitializerHostedService(
string connectionString,
string schemaName,
string tableName) : IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
var quotedTable = $"[{schemaName.Replace("]", "]]")}].[{tableName.Replace("]", "]]")}]";
var escapedSchema = schemaName.Replace("'", "''");
var escapedTable = tableName.Replace("'", "''");

var tableInfoSql =
$"SELECT 1 FROM INFORMATION_SCHEMA.TABLES " +
$"WHERE TABLE_SCHEMA = '{escapedSchema}' AND TABLE_NAME = '{escapedTable}'";

var createTableSql =
$"CREATE TABLE {quotedTable}(" +
"Id nvarchar(449) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL, " +
"Value varbinary(MAX) NOT NULL, " +
"ExpiresAtTime datetimeoffset NOT NULL, " +
"SlidingExpirationInSeconds bigint NULL, " +
"AbsoluteExpiration datetimeoffset NULL, " +
"PRIMARY KEY (Id))";

var createIndexSql =
$"CREATE NONCLUSTERED INDEX Index_ExpiresAtTime ON {quotedTable}(ExpiresAtTime)";

await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);

await using var checkCommand = new SqlCommand(tableInfoSql, connection);
await using var reader = await checkCommand.ExecuteReaderAsync(CommandBehavior.SingleRow, cancellationToken);
var exists = await reader.ReadAsync(cancellationToken);
await reader.CloseAsync();

if (exists)
return;

await using var transaction = (SqlTransaction)await connection.BeginTransactionAsync(cancellationToken);
try
{
await new SqlCommand(createTableSql, connection, transaction).ExecuteNonQueryAsync(cancellationToken);
await new SqlCommand(createIndexSql, connection, transaction).ExecuteNonQueryAsync(cancellationToken);
await transaction.CommitAsync(cancellationToken);
}
catch
{
await transaction.RollbackAsync(cancellationToken);
throw;
}
}

public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using TaskTurnstile.Stores;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace TaskTurnstile.DependencyInjection;

Expand Down
Loading