refactor: address code review findings across all projects

Apply comprehensive fixes from code reviews including:
- Extract shared utilities (SqlFormatHelper, CellValueConverter, DbDestinationBase)
- Add interface abstractions (IAuthenticationService, IDatabaseMigrator, IMisQueryBuilder)
- Implement SecureStore for encrypted secrets storage
- Fix error handling with proper HTTP status codes and logging
- Optimize double enumeration in DevEtlRegistry
- Add DataSync.Dev README for developer onboarding
- Extract filter panel base classes to reduce duplication
- Update code review docs to mark all issues as fixed
This commit is contained in:
Joseph Doherty
2026-01-19 11:05:36 -05:00
parent 08f5aa1447
commit 604bfe919c
148 changed files with 8696 additions and 1538 deletions
@@ -15,141 +15,99 @@ public partial class LotFinderRepository
/// <inheritdoc/>
public async Task<List<Search>> GetUserSearchesAsync(string userName, CancellationToken ct = default)
{
const string operation = nameof(GetUserSearchesAsync);
try
{
await using var connection = await _connectionFactory.CreateLotFinderConnectionAsync(ct);
var result = await connection.QueryAsync<Search>(
ArgumentException.ThrowIfNullOrWhiteSpace(userName);
return await ExecuteQueryAsync(
nameof(GetUserSearchesAsync),
"SQL_GET_USER_SEARCHES",
async connection => (await connection.QueryAsync<Search>(
LotFinderQueries.SqlGetUserSearches,
new { userName },
commandTimeout: _options.Value.DefaultTimeoutSeconds);
return result.ToList();
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
LogAndThrow(ex, operation, "SQL_GET_USER_SEARCHES");
throw; // Unreachable but satisfies compiler
}
commandTimeout: _options.Value.DefaultTimeoutSeconds)).ToList(),
ct);
}
/// <inheritdoc/>
public async Task<List<Search>> GetQueuedSearchesAsync(CancellationToken ct = default)
{
const string operation = nameof(GetQueuedSearchesAsync);
try
{
await using var connection = await _connectionFactory.CreateLotFinderConnectionAsync(ct);
var result = await connection.QueryAsync<Search>(
return await ExecuteQueryAsync(
nameof(GetQueuedSearchesAsync),
"SQL_GET_QUEUED_SEARCHES",
async connection => (await connection.QueryAsync<Search>(
LotFinderQueries.SqlGetQueuedSearches,
commandTimeout: _options.Value.DefaultTimeoutSeconds);
return result.ToList();
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
LogAndThrow(ex, operation, "SQL_GET_QUEUED_SEARCHES");
throw;
}
commandTimeout: _options.Value.DefaultTimeoutSeconds)).ToList(),
ct);
}
/// <inheritdoc/>
public async Task<Search?> GetSearchAsync(int id, CancellationToken ct = default)
{
const string operation = nameof(GetSearchAsync);
try
{
await using var connection = await _connectionFactory.CreateLotFinderConnectionAsync(ct);
var result = await connection.QueryFirstOrDefaultAsync<Search>(
LotFinderQueries.SqlGetSearch,
new { id },
commandTimeout: _options.Value.DefaultTimeoutSeconds);
if (result != null)
return await ExecuteQueryAsync(
nameof(GetSearchAsync),
"SQL_GET_SEARCH",
async connection =>
{
result.Id = id;
}
var result = await connection.QueryFirstOrDefaultAsync<Search>(
LotFinderQueries.SqlGetSearch,
new { id },
commandTimeout: _options.Value.DefaultTimeoutSeconds);
return result;
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
LogAndThrow(ex, operation, "SQL_GET_SEARCH");
throw;
}
if (result != null)
{
result.Id = id;
}
return result;
},
ct);
}
/// <inheritdoc/>
public async Task<byte[]?> GetSearchResultsAsync(int id, CancellationToken ct = default)
{
const string operation = nameof(GetSearchResultsAsync);
try
{
await using var connection = await _connectionFactory.CreateLotFinderConnectionAsync(ct);
return await connection.QueryFirstOrDefaultAsync<byte[]>(
return await ExecuteQueryAsync(
nameof(GetSearchResultsAsync),
"SQL_GET_SEARCH_RESULTS",
connection => connection.QueryFirstOrDefaultAsync<byte[]>(
LotFinderQueries.SqlGetSearchResults,
new { id },
commandTimeout: _options.Value.DefaultTimeoutSeconds);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
LogAndThrow(ex, operation, "SQL_GET_SEARCH_RESULTS");
throw;
}
commandTimeout: _options.Value.DefaultTimeoutSeconds),
ct);
}
/// <inheritdoc/>
public async Task<int> SubmitSearchAsync(Search search, CancellationToken ct = default)
{
const string operation = nameof(SubmitSearchAsync);
try
{
search.Status = SearchStatus.Queued;
search.SubmitDt = DateTime.UtcNow;
ArgumentNullException.ThrowIfNull(search);
await using var connection = await _connectionFactory.CreateLotFinderConnectionAsync(ct);
await using var command = new SqlCommand(SqlObjects.SubmitSearch, connection)
search.Status = SearchStatus.Queued;
search.SubmitDt = DateTime.UtcNow;
return await ExecuteQueryAsync(
nameof(SubmitSearchAsync),
SqlObjects.SubmitSearch,
async connection =>
{
CommandType = CommandType.StoredProcedure,
CommandTimeout = _options.Value.DefaultTimeoutSeconds
};
await using var command = new SqlCommand(SqlObjects.SubmitSearch, connection)
{
CommandType = CommandType.StoredProcedure,
CommandTimeout = _options.Value.DefaultTimeoutSeconds
};
command.Parameters.AddWithValue("p_UserName", search.UserName);
command.Parameters.AddWithValue("p_Name", search.Name);
command.Parameters.AddWithValue("p_Criteria", search.CriteriaJson);
command.Parameters.AddWithValue("p_UserName", search.UserName);
command.Parameters.AddWithValue("p_Name", search.Name);
command.Parameters.AddWithValue("p_Criteria", search.CriteriaJson);
var searchIdParam = new SqlParameter("o_SearchID", SqlDbType.Int)
{
Direction = ParameterDirection.Output
};
command.Parameters.Add(searchIdParam);
var searchIdParam = new SqlParameter("o_SearchID", SqlDbType.Int)
{
Direction = ParameterDirection.Output
};
command.Parameters.Add(searchIdParam);
await command.ExecuteNonQueryAsync(ct);
return Convert.ToInt32(searchIdParam.Value);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
LogAndThrow(ex, operation, SqlObjects.SubmitSearch);
throw;
}
await command.ExecuteNonQueryAsync(ct);
return Convert.ToInt32(searchIdParam.Value);
},
ct);
}
}