using Dapper;
using JdeScoping.Core.Models.Enums;
using JdeScoping.Core.Models.Search;
using JdeScoping.DataAccess.Interfaces;
using JdeScoping.DataSync.Contracts;
using Microsoft.Extensions.Logging;
namespace JdeScoping.DataSync.Services;
///
/// Repository for Search table operations.
///
public class SearchRepository : ISearchRepository
{
private readonly IDbConnectionFactory _connectionFactory;
private readonly ILogger _logger;
///
/// Initializes a new instance of the class.
///
/// The database connection factory.
/// The logger instance.
public SearchRepository(
IDbConnectionFactory connectionFactory,
ILogger logger)
{
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
///
public async Task GetNextQueuedSearchAsync(CancellationToken ct = default)
{
await using var connection = await _connectionFactory.CreateLotFinderConnectionAsync(ct);
const string sql = """
SELECT TOP 1
Id, UserName, Name, Status, SubmitDT as SubmitDt,
StartDT as StartDt, EndDT as EndDt, CriteriaJSON as CriteriaJson
FROM dbo.Search
WHERE Status = @Status
ORDER BY SubmitDT ASC
""";
var search = await connection.QueryFirstOrDefaultAsync(
sql,
new { Status = (int)SearchStatus.Queued },
commandTimeout: 30);
if (search != null)
{
_logger.LogDebug("Found queued search {SearchId}", search.Id);
}
return search;
}
///
public async Task ResetPartialSearchesAsync(CancellationToken ct = default)
{
await using var connection = await _connectionFactory.CreateLotFinderConnectionAsync(ct);
const string sql = """
UPDATE dbo.Search
SET Status = @QueuedStatus, StartDT = NULL
WHERE Status = @RunningStatus AND EndDT IS NULL
""";
var count = await connection.ExecuteAsync(
sql,
new
{
QueuedStatus = (int)SearchStatus.Queued,
RunningStatus = (int)SearchStatus.Running
},
commandTimeout: 30);
if (count > 0)
{
_logger.LogWarning("Reset {Count} partial searches to Queued status", count);
}
return count;
}
///
public async Task StartSearchAsync(int searchId, CancellationToken ct = default)
{
await using var connection = await _connectionFactory.CreateLotFinderConnectionAsync(ct);
const string sql = """
UPDATE dbo.Search
SET Status = @Status, StartDT = @StartDt
WHERE Id = @SearchId
""";
await connection.ExecuteAsync(
sql,
new
{
SearchId = searchId,
Status = (int)SearchStatus.Running,
StartDt = DateTime.UtcNow
},
commandTimeout: 30);
_logger.LogDebug("Started search {SearchId}", searchId);
}
///
public async Task CompleteSearchAsync(int searchId, bool success, byte[]? results, CancellationToken ct = default)
{
await using var connection = await _connectionFactory.CreateLotFinderConnectionAsync(ct);
const string sql = """
UPDATE dbo.Search
SET Status = @Status, EndDT = @EndDt, Results = @Results
WHERE Id = @SearchId
""";
var status = success ? SearchStatus.Ended : SearchStatus.Error;
await connection.ExecuteAsync(
sql,
new
{
SearchId = searchId,
Status = (int)status,
EndDt = DateTime.UtcNow,
Results = results
},
commandTimeout: 30);
_logger.LogDebug("Completed search {SearchId} with status {Status}", searchId, status);
}
}