< Summary

Information
Class: ArturRios.Data.Export.Excel.Exporters.ExcelExporter<T>
Assembly: ArturRios.Data.Export.Excel
File(s): /home/ci/agent/workspace/dotnet-data-docs_main/app/src/ArturRios.Data.Export.Excel/Exporters/ExcelExporter.cs
Line coverage
84%
Covered lines: 37
Uncovered lines: 7
Coverable lines: 44
Total lines: 99
Line coverage: 84%
Branch coverage
90%
Covered branches: 47
Total branches: 52
Branch coverage: 90.3%
Method coverage
100%
Covered methods: 3
Fully covered methods: 2
Total methods: 3
Method coverage: 100%
Full method coverage: 66.6%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
WriteCoreAsync(...)100%1414100%
SetCell(...)86.84%853868.18%

File(s)

/home/ci/agent/workspace/dotnet-data-docs_main/app/src/ArturRios.Data.Export.Excel/Exporters/ExcelExporter.cs

#LineLine coverage
 1using ArturRios.Data.Export.Abstractions;
 2using ArturRios.Data.Export.Excel.Configuration;
 3using ArturRios.Data.Export.Exporters;
 4using ClosedXML.Excel;
 5using Microsoft.Extensions.Logging;
 6
 7namespace ArturRios.Data.Export.Excel.Exporters;
 8
 9/// <summary>Writes records to a single-worksheet .xlsx workbook using ClosedXML and the shared column map.</summary>
 10/// <typeparam name="T">The record type.</typeparam>
 11/// <param name="options">Excel options.</param>
 12/// <param name="logger">Optional logger; see <see cref="ExporterBase{T}" />.</param>
 13public class ExcelExporter<T>(ExcelExportOptions options, ILogger<ExcelExporter<T>>? logger = null)
 1814    : ExporterBase<T>(logger) where T : class
 15{
 16    /// <inheritdoc />
 17    protected override Task WriteCoreAsync(IEnumerable<T> data, Stream destination, CancellationToken ct)
 18    {
 1619        var columns = ColumnMap.For<T>();
 1620        using var workbook = new XLWorkbook();
 1621        var worksheet = workbook.Worksheets.Add(options.SheetName);
 1622        var row = 1;
 23
 1624        if (options.IncludeHeader)
 25        {
 16826            for (var i = 0; i < columns.Count; i++)
 27            {
 6828                var cell = worksheet.Cell(row, i + 1);
 6829                cell.Value = columns[i].Header;
 6830                if (options.BoldHeader)
 6831                    cell.Style.Font.Bold = true;
 32            }
 33
 1634            row++;
 35        }
 36
 6037        foreach (var item in data)
 38        {
 1439            ct.ThrowIfCancellationRequested();
 15240            for (var i = 0; i < columns.Count; i++)
 41            {
 6242                SetCell(worksheet.Cell(row, i + 1), columns[i].Getter(item));
 43            }
 44
 1445            row++;
 46        }
 47
 1648        if (options.AutoFitColumns && columns.Count > 0)
 49        {
 1650            worksheet.Columns().AdjustToContents();
 51        }
 52
 1653        workbook.SaveAs(destination);
 1654        return Task.CompletedTask;
 1655    }
 56
 57    // Built-in number format 14: the short date in the reader's locale.
 58    private const int ShortDateFormatId = 14;
 59
 60    private static void SetCell(IXLCell cell, object? value)
 61    {
 6262        switch (value)
 63        {
 64            case null:
 65                break;
 66            case bool b:
 067                cell.Value = b;
 068                break;
 69            case DateTime dt:
 070                cell.Value = dt;
 071                break;
 72            case DateOnly date:
 1073                cell.Value = date.ToDateTime(TimeOnly.MinValue);
 1074                cell.Style.NumberFormat.NumberFormatId = ShortDateFormatId;
 1075                break;
 76            case TimeSpan span:
 1077                cell.Value = span;
 1078                break;
 79            case TimeOnly time:
 1080                cell.Value = time.ToTimeSpan();
 1081                break;
 82            // A cell cannot hold NaN or an infinity - ClosedXML rejects them, which would fail the whole
 83            // export - so they are written as text, the way CSV renders them.
 1084            case double d when !double.IsFinite(d):
 685                cell.Value = ValueRenderer.Render(d);
 686                break;
 087            case float f when !float.IsFinite(f):
 088                cell.Value = ValueRenderer.Render(f);
 089                break;
 90            // xlsx stores all numbers as IEEE-754 double; long/ulong > 2^53 and high-precision decimals lose precision.
 91            case sbyte or byte or short or ushort or int or uint or long or ulong or float or double or decimal:
 1292                cell.Value = Convert.ToDouble(value, System.Globalization.CultureInfo.InvariantCulture);
 1293                break;
 94            default:
 1495                cell.Value = ValueRenderer.Render(value);
 96                break;
 97        }
 1498    }
 99}