feat(etl): implement SqlScriptRunner

Add SqlScriptRunner class that implements IScriptRunner for executing
SQL scripts against the LotFinderDB cache database. Includes constructor
validation and configurable timeout support (default 1 hour).
This commit is contained in:
Joseph Doherty
2026-01-03 09:03:14 -05:00
parent 5a101a60b3
commit 82573df023
2 changed files with 81 additions and 0 deletions
@@ -0,0 +1,37 @@
using JdeScoping.DataAccess.Interfaces;
using JdeScoping.DataSync.Etl.Contracts;
namespace JdeScoping.DataSync.Etl.Scripts;
public class SqlScriptRunner : IScriptRunner
{
private readonly IDbConnectionFactory _connectionFactory;
private readonly string _sql;
private readonly int _timeoutSeconds;
public string ScriptName { get; }
public SqlScriptRunner(
IDbConnectionFactory connectionFactory,
string sql,
string? name = null,
int timeoutSeconds = 3600)
{
ArgumentNullException.ThrowIfNull(connectionFactory);
ArgumentException.ThrowIfNullOrWhiteSpace(sql);
_connectionFactory = connectionFactory;
_sql = sql;
_timeoutSeconds = timeoutSeconds;
ScriptName = name ?? "SqlScript";
}
public async Task ExecuteAsync(CancellationToken cancellationToken = default)
{
await using var connection = await _connectionFactory.CreateLotFinderConnectionAsync(cancellationToken);
await using var command = connection.CreateCommand();
command.CommandText = _sql;
command.CommandTimeout = _timeoutSeconds;
await command.ExecuteNonQueryAsync(cancellationToken);
}
}
@@ -0,0 +1,44 @@
using JdeScoping.DataAccess.Interfaces;
using JdeScoping.DataSync.Etl.Scripts;
using NSubstitute;
namespace JdeScoping.DataSync.Tests.Etl.Scripts;
public class SqlScriptRunnerTests
{
[Fact]
public void Constructor_SetsScriptName()
{
var factory = Substitute.For<IDbConnectionFactory>();
var runner = new SqlScriptRunner(factory, "SELECT 1", "TestScript");
Assert.Equal("TestScript", runner.ScriptName);
}
[Fact]
public void Constructor_WithNullName_DefaultsToSqlScript()
{
var factory = Substitute.For<IDbConnectionFactory>();
var runner = new SqlScriptRunner(factory, "SELECT 1");
Assert.Equal("SqlScript", runner.ScriptName);
}
[Fact]
public void Constructor_NullFactory_ThrowsArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => new SqlScriptRunner(null!, "SELECT 1"));
}
[Fact]
public void Constructor_NullSql_ThrowsArgumentNullException()
{
var factory = Substitute.For<IDbConnectionFactory>();
Assert.Throws<ArgumentNullException>(() => new SqlScriptRunner(factory, null!));
}
[Fact]
public void Constructor_EmptySql_ThrowsArgumentException()
{
var factory = Substitute.For<IDbConnectionFactory>();
Assert.Throws<ArgumentException>(() => new SqlScriptRunner(factory, ""));
}
}