Skip to content

Commit

Permalink
Throw custom exception when column not found (#543)
Browse files Browse the repository at this point in the history
Co-authored-by: Paweł Szybiak <[email protected]>
  • Loading branch information
pszybiak and Paweł Szybiak authored Dec 13, 2023
1 parent 205c763 commit abfc7ad
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 4 deletions.
24 changes: 24 additions & 0 deletions src/MiniExcel/Exceptions/ExcelColumnNotFoundException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Collections.Generic;

namespace MiniExcelLibs.Exceptions
{
public class ExcelColumnNotFoundException : KeyNotFoundException
{
public string ColumnName { get; set; }
public string[] ColumnAliases { get; }
public string ColumnIndex { get; set; }
public int RowIndex { get; set; }
public IDictionary<string, int> Headers { get; }
public object RowValues { get; set; }

public ExcelColumnNotFoundException(string columnIndex, string columnName, string[] columnAliases, int rowIndex, IDictionary<string, int> headers, object value, string message) : base(message)
{
ColumnIndex = columnIndex;
ColumnName = columnName;
ColumnAliases = columnAliases;
RowIndex = rowIndex;
Headers = headers;
RowValues = value;
}
}
}
34 changes: 31 additions & 3 deletions src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using MiniExcelLibs.Utils;
using MiniExcelLibs.Exceptions;
using MiniExcelLibs.Utils;
using MiniExcelLibs.Zip;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -449,7 +450,11 @@ private void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, ref Di
if (headersDic.ContainsKey(alias))
{
object newV = null;
object itemValue = item[keys[headersDic[alias]]];
var columnId = headersDic[alias];
var columnName = keys[columnId];
if (!item.ContainsKey(columnName))
ThrowExcelColumnNotFoundException(pInfo, rowIndex, startCell, headersDic, item);
object itemValue = item[columnName];

if (itemValue == null)
continue;
Expand All @@ -464,9 +469,19 @@ private void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, ref Di
object newV = null;
object itemValue = null;
if (pInfo.ExcelIndexName != null && keys.Contains(pInfo.ExcelIndexName))
{
if (!item.ContainsKey(pInfo.ExcelIndexName))
ThrowExcelColumnNotFoundException(pInfo, rowIndex, startCell, headersDic, item);
itemValue = item[pInfo.ExcelIndexName];
}
else if (headersDic.ContainsKey(pInfo.ExcelColumnName))
itemValue = item[keys[headersDic[pInfo.ExcelColumnName]]];
{
var columnId = headersDic[pInfo.ExcelColumnName];
var columnName = keys[columnId];
if (!item.ContainsKey(columnName))
ThrowExcelColumnNotFoundException(pInfo, rowIndex, startCell, headersDic, item);
itemValue = item[columnName];
}

if (itemValue == null)
continue;
Expand All @@ -479,6 +494,19 @@ private void SetCellsValueAndHeaders(object cellValue, bool useHeaderRow, ref Di
}
}

private static void ThrowExcelColumnNotFoundException(ExcelColumnInfo pInfo, int rowIndex, string startCell, IDictionary<string, int> headers, IDictionary<string, object> row)
{
var columnName = pInfo.ExcelColumnName ?? pInfo.Property.Name;
var errorRow = ReferenceHelper.ConvertCellToXY(startCell).Item2 + rowIndex + 1;
throw new ExcelColumnNotFoundException(pInfo.ExcelIndexName,
pInfo.ExcelColumnName ?? pInfo.Property.Name,
pInfo.ExcelColumnAliases,
ReferenceHelper.ConvertCellToXY(startCell).Item2 + rowIndex + 1,
headers,
row,
$"ColumnName : {columnName}, CellRow : {errorRow}, value of {pInfo.Property.Info.PropertyType.Name} type not found.");
}

private void SetSharedStrings()
{
if (_sharedStrings != null)
Expand Down
67 changes: 66 additions & 1 deletion tests/MiniExcelTests/MiniExcelCsvTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using CsvHelper;
using CsvHelper.Configuration;
using MiniExcelLibs.Attributes;
using MiniExcelLibs.Exceptions;
using MiniExcelLibs.Tests.Utils;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -207,6 +208,13 @@ public class Test
public string c1 { get; set; }
public string c2 { get; set; }
}
public class TestWithAlias
{
[ExcelColumnName(excelColumnName: "c1", aliases: new[] { "column1", "col1" })]
public string c1 { get; set; }
[ExcelColumnName(excelColumnName: "c2", aliases: new[] { "column2", "col2" })]
public string c2 { get; set; }
}

[Fact]
public void CsvExcelTypeTest()
Expand Down Expand Up @@ -294,6 +302,63 @@ public void CsvTypeMappingTest()
Assert.Equal("A2", rows[1].c1);
Assert.Equal("B2", rows[1].c2);
}
}

[Fact()]
public void CsvColumnNotFoundTest()
{
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.csv");
File.WriteAllLines(path, new[] { "c1,c2", "v1" });

using (var stream = File.OpenRead(path))
{
var exception = Assert.Throws<ExcelColumnNotFoundException>(() => stream.Query<Test>(excelType: ExcelType.CSV).ToList());

Assert.Equal("c2", exception.ColumnName);
Assert.Equal(2, exception.RowIndex);
Assert.Null(exception.ColumnIndex);
Assert.True(exception.RowValues is IDictionary<string, object>);
Assert.Equal(1, ((IDictionary<string, object>)exception.RowValues).Count);
}

{
var exception = Assert.Throws<ExcelColumnNotFoundException>(() => MiniExcel.Query<Test>(path, excelType: ExcelType.CSV).ToList());

Assert.Equal("c2", exception.ColumnName);
Assert.Equal(2, exception.RowIndex);
Assert.Null(exception.ColumnIndex);
Assert.True(exception.RowValues is IDictionary<string, object>);
Assert.Equal(1, ((IDictionary<string, object>)exception.RowValues).Count);
}

File.Delete(path);
}

[Fact()]
public void CsvColumnNotFoundWithAliasTest()
{
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.csv");
File.WriteAllLines(path, new[] { "col1,col2", "v1" });
using (var stream = File.OpenRead(path))
{
var exception = Assert.Throws<ExcelColumnNotFoundException>(() => stream.Query<TestWithAlias>(excelType: ExcelType.CSV).ToList());

Assert.Equal("c2", exception.ColumnName);
Assert.Equal(2, exception.RowIndex);
Assert.Null(exception.ColumnIndex);
Assert.True(exception.RowValues is IDictionary<string, object>);
Assert.Equal(1, ((IDictionary<string, object>)exception.RowValues).Count);
}

{
var exception = Assert.Throws<ExcelColumnNotFoundException>(() => MiniExcel.Query<TestWithAlias>(path, excelType: ExcelType.CSV).ToList());

Assert.Equal("c2", exception.ColumnName);
Assert.Equal(2, exception.RowIndex);
Assert.Null(exception.ColumnIndex);
Assert.True(exception.RowValues is IDictionary<string, object>);
Assert.Equal(1, ((IDictionary<string, object>)exception.RowValues).Count);
}

File.Delete(path);
}
Expand Down

0 comments on commit abfc7ad

Please sign in to comment.