refactor(ExcelIO): migrate ExcelExportService to Core models and FluentTableWriter

- Replace AttributeTableWriter with FluentTableWriter in ExcelExportService
- Inject ExcelMapRegistry for fluent map lookups
- Use registry.GetMap<T>().TabName instead of reflection-based attribute reading
- Update ExcelIO SearchModel to reference Core result types via aliases
- Remove System.Reflection import (no longer needed)
- Add JdeScoping.Core.Models.SearchResults import for result types
This commit is contained in:
Joseph Doherty
2026-01-06 23:38:30 -05:00
parent a6b7f646b1
commit 8883fb2680
2 changed files with 28 additions and 18 deletions
@@ -1,14 +1,16 @@
using System.Reflection;
using ClosedXML.Excel;
using JdeScoping.Core.Interfaces;
using JdeScoping.ExcelIO.Attributes;
using JdeScoping.Core.Models.SearchResults;
using JdeScoping.ExcelIO.Options;
using JdeScoping.ExcelIO.Formatting;
using JdeScoping.ExcelIO.Generators;
using JdeScoping.ExcelIO.Models.Reporting;
using JdeScoping.ExcelIO.Mapping;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
// Use ExcelIO's SearchModel which contains criteria filter properties for CriteriaSheetGenerator
using ExcelSearchModel = JdeScoping.ExcelIO.Models.Reporting.SearchModel;
namespace JdeScoping.ExcelIO;
/// <summary>
@@ -19,7 +21,8 @@ public class ExcelExportService : IExcelExportService
private readonly ILogger<ExcelExportService> _logger;
private readonly IOptions<ExcelExportOptions> _options;
private readonly CriteriaSheetGenerator _criteriaGenerator;
private readonly AttributeTableWriter _tableWriter;
private readonly FluentTableWriter _tableWriter;
private readonly ExcelMapRegistry _registry;
/// <summary>
/// Initializes a new instance of the ExcelExportService class.
@@ -27,25 +30,28 @@ public class ExcelExportService : IExcelExportService
/// <param name="logger">Logger instance.</param>
/// <param name="options">Excel export options.</param>
/// <param name="criteriaGenerator">Criteria sheet generator.</param>
/// <param name="tableWriter">Attribute table writer.</param>
/// <param name="tableWriter">Fluent table writer.</param>
/// <param name="registry">Excel map registry.</param>
public ExcelExportService(
ILogger<ExcelExportService> logger,
IOptions<ExcelExportOptions> options,
CriteriaSheetGenerator criteriaGenerator,
AttributeTableWriter tableWriter)
FluentTableWriter tableWriter,
ExcelMapRegistry registry)
{
_logger = logger;
_options = options;
_criteriaGenerator = criteriaGenerator;
_tableWriter = tableWriter;
_registry = registry;
}
/// <inheritdoc />
public async Task<byte[]> GenerateAsync(object search, CancellationToken cancellationToken = default)
{
if (search is not SearchModel searchModel)
if (search is not ExcelSearchModel searchModel)
{
throw new ArgumentException($"Expected {nameof(SearchModel)} but received {search.GetType().Name}", nameof(search));
throw new ArgumentException($"Expected {nameof(ExcelSearchModel)} but received {search.GetType().Name}", nameof(search));
}
return await GenerateAsync(searchModel, cancellationToken);
@@ -57,7 +63,7 @@ public class ExcelExportService : IExcelExportService
/// <param name="search">Search model with criteria and results.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Excel file as byte array.</returns>
public async Task<byte[]> GenerateAsync(SearchModel search, CancellationToken cancellationToken = default)
public async Task<byte[]> GenerateAsync(ExcelSearchModel search, CancellationToken cancellationToken = default)
{
using var scope = _logger.BeginScope(new Dictionary<string, object>
{
@@ -128,8 +134,8 @@ public class ExcelExportService : IExcelExportService
private void GenerateResultsSheet(XLWorkbook workbook, List<SearchResult> results)
{
var tableAttr = typeof(SearchResult).GetCustomAttribute<OutputTableAttribute>();
var tabName = tableAttr?.TabName ?? "Search Results";
var map = _registry.GetMap<SearchResult>();
var tabName = map.TabName ?? "Search Results";
var worksheet = workbook.Worksheets.Add(tabName);
var table = _tableWriter.WriteTable(worksheet, 1, 1, results);
@@ -147,8 +153,8 @@ public class ExcelExportService : IExcelExportService
private void GenerateMisInfoSheet(XLWorkbook workbook, List<MisSearchResult> misResults)
{
var tableAttr = typeof(MisSearchResult).GetCustomAttribute<OutputTableAttribute>();
var tabName = tableAttr?.TabName ?? "MIS Info";
var map = _registry.GetMap<MisSearchResult>();
var tabName = map.TabName ?? "MIS Info";
var worksheet = workbook.Worksheets.Add(tabName);
var table = _tableWriter.WriteTable(worksheet, 1, 1, misResults);
@@ -166,8 +172,8 @@ public class ExcelExportService : IExcelExportService
private void GenerateInvestigationSheet(XLWorkbook workbook, List<MisNonMatchSearchResult> misNonMatchResults)
{
var tableAttr = typeof(MisNonMatchSearchResult).GetCustomAttribute<OutputTableAttribute>();
var tabName = tableAttr?.TabName ?? "Investigation";
var map = _registry.GetMap<MisNonMatchSearchResult>();
var tabName = map.TabName ?? "Investigation";
var worksheet = workbook.Worksheets.Add(tabName);
var table = _tableWriter.WriteTable(worksheet, 1, 1, misNonMatchResults);
@@ -1,3 +1,7 @@
using CoreSearchResult = JdeScoping.Core.Models.SearchResults.SearchResult;
using CoreMisSearchResult = JdeScoping.Core.Models.SearchResults.MisSearchResult;
using CoreMisNonMatchSearchResult = JdeScoping.Core.Models.SearchResults.MisNonMatchSearchResult;
namespace JdeScoping.ExcelIO.Models.Reporting;
/// <summary>
@@ -128,15 +132,15 @@ public class SearchModel
/// <summary>
/// Work order search results.
/// </summary>
public List<SearchResult> Results { get; set; } = [];
public List<CoreSearchResult> Results { get; set; } = [];
/// <summary>
/// MIS results.
/// </summary>
public List<MisSearchResult>? MisResults { get; set; }
public List<CoreMisSearchResult>? MisResults { get; set; }
/// <summary>
/// MIS no match found results.
/// </summary>
public List<MisNonMatchSearchResult>? MisNonMatchResults { get; set; }
public List<CoreMisNonMatchSearchResult>? MisNonMatchResults { get; set; }
}