From 5f3d76d118310396387b52246242a12cc35bed75 Mon Sep 17 00:00:00 2001 From: josdeweger Date: Sun, 23 Dec 2018 23:07:52 +0100 Subject: [PATCH 1/4] Added customer parser --- .../FluentConfiguration/ColumnMapping.cs | 20 ++++--- .../ColumnMappingBuilder.cs | 15 +++-- .../FluentConfiguration/IndexColumnMapping.cs | 14 ++++- .../LetterColumnMapping.cs | 14 ++++- .../FluentConfiguration/NameColumnMapping.cs | 15 ++++- .../PropertyColumnMapping.cs | 14 ++++- src/SheetToObjects.Lib/IMapValue.cs | 7 +-- src/SheetToObjects.Lib/RowMapper.cs | 6 +- src/SheetToObjects.Lib/ValueMapper.cs | 45 ++++++++++----- .../Lib/SheetMapperSpecs.cs | 55 +++++++++++++++++++ .../Lib/ValueMapperSpecs.cs | 44 +++++++-------- .../TestModels/EnumModel.cs | 3 +- 12 files changed, 181 insertions(+), 71 deletions(-) diff --git a/src/SheetToObjects.Lib/FluentConfiguration/ColumnMapping.cs b/src/SheetToObjects.Lib/FluentConfiguration/ColumnMapping.cs index 49ec53f..5eaf093 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/ColumnMapping.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/ColumnMapping.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using SheetToObjects.Lib.Validation; namespace SheetToObjects.Lib.FluentConfiguration @@ -6,21 +7,24 @@ namespace SheetToObjects.Lib.FluentConfiguration public abstract class ColumnMapping { public abstract string DisplayName { get; } - - public bool IsRequired - { - get { return ParsingRules.Exists(r => r is RequiredRule); } - } - + public bool IsRequired => ParsingRules.Exists(r => r is RequiredRule); public int ColumnIndex { get; protected set; } public string PropertyName { get; } public string Format { get; } public List ParsingRules { get; } public List Rules { get; } public object DefaultValue { get; } + public readonly Func CustomParser; - protected ColumnMapping(string propertyName, string format, List parsingRules, List rules, object defaultValue) + protected ColumnMapping( + string propertyName, + string format, + List parsingRules, + List rules, + object defaultValue, + Func customParser) { + CustomParser = customParser; PropertyName = propertyName; Format = format; ParsingRules = parsingRules ?? new List(); diff --git a/src/SheetToObjects.Lib/FluentConfiguration/ColumnMappingBuilder.cs b/src/SheetToObjects.Lib/FluentConfiguration/ColumnMappingBuilder.cs index 5c17a10..e5b9ca7 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/ColumnMappingBuilder.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/ColumnMappingBuilder.cs @@ -20,6 +20,7 @@ public class ColumnMappingBuilder private bool _isRequiredInHeaderRow; private readonly List _parsingRules = new List(); private readonly List _rules = new List(); + private Func _customParser; /// /// Map to column by header (other options are to map by column index or column letter) @@ -101,6 +102,12 @@ public ColumnMappingBuilder UsingFormat(string format) return this; } + public ColumnMappingBuilder WithCustomParser(Func customParser) + { + _customParser = customParser; + return this; + } + /// /// Specify the model property this column needs to map to. The type is inferred from the type on the model /// @@ -145,13 +152,13 @@ public ColumnMapping MapTo(PropertyInfo property) _propertyName = property.Name; if(_header.IsNotNullOrWhiteSpace()) - return new NameColumnMapping(_header, _propertyName, _format, _parsingRules, _rules, _defaultValue,_isRequiredInHeaderRow); + return new NameColumnMapping(_header, _propertyName, _format, _parsingRules, _rules, _defaultValue,_isRequiredInHeaderRow, _customParser); if(_columnLetter.IsNotNullOrWhiteSpace()) - return new LetterColumnMapping(_columnLetter, _propertyName, _format, _parsingRules, _rules, _defaultValue); + return new LetterColumnMapping(_columnLetter, _propertyName, _format, _parsingRules, _rules, _defaultValue, _customParser); if(_columnIndex >= 0) - return new IndexColumnMapping(_columnIndex, _propertyName, _format, _parsingRules, _rules, _defaultValue); + return new IndexColumnMapping(_columnIndex, _propertyName, _format, _parsingRules, _rules, _defaultValue, _customParser); - return new PropertyColumnMapping(_propertyName, _format, _parsingRules, _rules, _defaultValue,_isRequiredInHeaderRow); + return new PropertyColumnMapping(_propertyName, _format, _parsingRules, _rules, _defaultValue,_isRequiredInHeaderRow, _customParser); } } } diff --git a/src/SheetToObjects.Lib/FluentConfiguration/IndexColumnMapping.cs b/src/SheetToObjects.Lib/FluentConfiguration/IndexColumnMapping.cs index e82285b..cacda0b 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/IndexColumnMapping.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/IndexColumnMapping.cs @@ -1,12 +1,20 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using SheetToObjects.Lib.Validation; namespace SheetToObjects.Lib.FluentConfiguration { internal class IndexColumnMapping : ColumnMapping { - public IndexColumnMapping(int columnIndex, string propertyName, string format, List parsingRules, List rules, object defaultValue) - : base(propertyName, format, parsingRules, rules, defaultValue) + public IndexColumnMapping( + int columnIndex, + string propertyName, + string format, + List parsingRules, + List rules, + object defaultValue, + Func customParser) + : base(propertyName, format, parsingRules, rules, defaultValue, customParser) { ColumnIndex = columnIndex; } diff --git a/src/SheetToObjects.Lib/FluentConfiguration/LetterColumnMapping.cs b/src/SheetToObjects.Lib/FluentConfiguration/LetterColumnMapping.cs index 70f79e4..f0a7e76 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/LetterColumnMapping.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/LetterColumnMapping.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using SheetToObjects.Core; using SheetToObjects.Lib.Validation; @@ -8,8 +9,15 @@ internal class LetterColumnMapping : ColumnMapping { public string ColumnName { get; } - public LetterColumnMapping(string columnLetter, string propertyName, string format, List parsingRules, List rules, object defaultValue) - : base(propertyName, format, parsingRules, rules, defaultValue) + public LetterColumnMapping( + string columnLetter, + string propertyName, + string format, + List parsingRules, + List rules, + object defaultValue, + Func customParser) + : base(propertyName, format, parsingRules, rules, defaultValue, customParser) { ColumnName = columnLetter; ColumnIndex = columnLetter.ConvertExcelColumnNameToIndex(); diff --git a/src/SheetToObjects.Lib/FluentConfiguration/NameColumnMapping.cs b/src/SheetToObjects.Lib/FluentConfiguration/NameColumnMapping.cs index dd1b67d..078ce2b 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/NameColumnMapping.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/NameColumnMapping.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using SheetToObjects.Lib.Validation; namespace SheetToObjects.Lib.FluentConfiguration @@ -9,8 +10,16 @@ internal class NameColumnMapping : ColumnMapping, IUseHeaderRow public bool IsRequiredInHeaderRow { get; } - public NameColumnMapping(string columnName, string propertyName, string format, List parsingRules, List rules, object defaultValue, bool isRequiredInHeaderRow) - : base(propertyName, format, parsingRules, rules, defaultValue) + public NameColumnMapping( + string columnName, + string propertyName, + string format, + List parsingRules, + List rules, + object defaultValue, + bool isRequiredInHeaderRow, + Func customParser) + : base(propertyName, format, parsingRules, rules, defaultValue, customParser) { ColumnName = columnName; ColumnIndex = -1; diff --git a/src/SheetToObjects.Lib/FluentConfiguration/PropertyColumnMapping.cs b/src/SheetToObjects.Lib/FluentConfiguration/PropertyColumnMapping.cs index d276adc..21f230e 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/PropertyColumnMapping.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/PropertyColumnMapping.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using SheetToObjects.Lib.Validation; namespace SheetToObjects.Lib.FluentConfiguration @@ -8,8 +9,15 @@ internal class PropertyColumnMapping : ColumnMapping, IUseHeaderRow public string ColumnName { get; } public bool IsRequiredInHeaderRow { get; } - public PropertyColumnMapping(string propertyName, string format, List parsingRules, List rules, object defaultValue, bool isRequiredInHeaderRow) - : base(propertyName, format, parsingRules, rules, defaultValue) + public PropertyColumnMapping( + string propertyName, + string format, + List parsingRules, + List rules, + object defaultValue, + bool isRequiredInHeaderRow, + Func customParser) + : base(propertyName, format, parsingRules, rules, defaultValue, customParser) { ColumnName = propertyName; ColumnIndex = -1; diff --git a/src/SheetToObjects.Lib/IMapValue.cs b/src/SheetToObjects.Lib/IMapValue.cs index b2dd9ab..7919e37 100644 --- a/src/SheetToObjects.Lib/IMapValue.cs +++ b/src/SheetToObjects.Lib/IMapValue.cs @@ -1,5 +1,6 @@ using System; using CSharpFunctionalExtensions; +using SheetToObjects.Lib.FluentConfiguration; using SheetToObjects.Lib.Validation; namespace SheetToObjects.Lib @@ -11,10 +12,6 @@ Result Map( Type propertyType, int columnIndex, int rowIndex, - string displayName, - string propertyName, - string format, - bool isRequired, - object defaultValue); + ColumnMapping columnMapping); } } \ No newline at end of file diff --git a/src/SheetToObjects.Lib/RowMapper.cs b/src/SheetToObjects.Lib/RowMapper.cs index d47d0d8..42cad3c 100644 --- a/src/SheetToObjects.Lib/RowMapper.cs +++ b/src/SheetToObjects.Lib/RowMapper.cs @@ -48,11 +48,7 @@ public Result, List> Map(Row property.PropertyType, columnMapping.ColumnIndex, row.RowIndex, - columnMapping.DisplayName, - columnMapping.PropertyName, - columnMapping.Format, - columnMapping.IsRequired, - columnMapping.DefaultValue) + columnMapping) .OnSuccess(value => { if (value.ToString().IsNotNullOrEmpty()) diff --git a/src/SheetToObjects.Lib/ValueMapper.cs b/src/SheetToObjects.Lib/ValueMapper.cs index 4dcb2d7..6afb0b7 100644 --- a/src/SheetToObjects.Lib/ValueMapper.cs +++ b/src/SheetToObjects.Lib/ValueMapper.cs @@ -1,5 +1,7 @@ using System; using CSharpFunctionalExtensions; +using SheetToObjects.Core; +using SheetToObjects.Lib.FluentConfiguration; using SheetToObjects.Lib.Parsing; using SheetToObjects.Lib.Validation; @@ -19,26 +21,41 @@ public Result Map( Type propertyType, int columnIndex, int rowIndex, - string displayName, - string propertyName, - string format, - bool isRequired, - object defaultValue) + ColumnMapping columnMapping) { if (string.IsNullOrEmpty(value)) { - return HandleEmptyValue(isRequired, columnIndex, rowIndex, displayName, propertyName, defaultValue); + return HandleEmptyValue(columnIndex, rowIndex, columnMapping); } - var parsingResult = _valueParser.Parse(propertyType, value, format); + if (columnMapping.CustomParser.IsNotNull()) + { + try + { + var parsedValue = columnMapping.CustomParser(value); + return Result.Ok(parsedValue); + } + catch (Exception) + { + var parsingValidationError = ParsingValidationError.CouldNotParseValue( + columnIndex, + rowIndex, + columnMapping.DisplayName, + columnMapping.PropertyName); + + return Result.Fail(parsingValidationError); + } + } + + var parsingResult = _valueParser.Parse(propertyType, value, columnMapping.Format); if (!parsingResult.IsSuccess) { var validationError = ParsingValidationError.CouldNotParseValue( columnIndex, rowIndex, - displayName, - propertyName); + columnMapping.DisplayName, + columnMapping.PropertyName); return Result.Fail(validationError); } @@ -46,20 +63,20 @@ public Result Map( return Result.Ok(parsingResult.Value); } - private static Result HandleEmptyValue(bool isRequired, int columnIndex, int rowIndex, string displayName, string propertyName, object defaultValue) + private static Result HandleEmptyValue(int columnIndex, int rowIndex, ColumnMapping columnMapping) { - if (isRequired) + if (columnMapping.IsRequired) { var cellValueRequiredError = RuleValidationError.CellValueRequired( columnIndex, rowIndex, - displayName, - propertyName); + columnMapping.DisplayName, + columnMapping.PropertyName); return Result.Fail(cellValueRequiredError); } - return Result.Ok(defaultValue ?? string.Empty); + return Result.Ok(columnMapping.DefaultValue ?? string.Empty); } } } \ No newline at end of file diff --git a/src/SheetToObjects.Specs/Lib/SheetMapperSpecs.cs b/src/SheetToObjects.Specs/Lib/SheetMapperSpecs.cs index 3222286..12c555f 100644 --- a/src/SheetToObjects.Specs/Lib/SheetMapperSpecs.cs +++ b/src/SheetToObjects.Specs/Lib/SheetMapperSpecs.cs @@ -356,6 +356,61 @@ public void GivenParsingShouldBeStoppedOnFirstEmptyRow_WhenSecondRowIsEmptyAndTh result.IsSuccess.Should().BeTrue(); result.ParsedModels.Should().HaveCount(1); } + + [Fact] + public void GivenSheet_WhenCustomBooleanParserIsProvided_ValueIsConverted() + { + var sheetData = new SheetBuilder() + .AddHeaders("Bool") + .AddRow(r => r.AddCell(c => c.WithColumnIndex(0).WithRowIndex(1).WithValue("1").Build()).Build(1)) + .Build(); + + var result = new SheetMapper() + .AddConfigFor(cfg => cfg + .HasHeaders() + .MapColumn(column => column + .WithHeader("Bool") + .WithCustomParser(x => x.Equals("1") ? true : false) + .IsRequired() + .MapTo(t => t.BoolProperty))) + .Map(sheetData); + + result.IsSuccess.Should().BeTrue(); + result.ParsedModels.Should().HaveCount(1); + result.ParsedModels.First().ParsedModel.BoolProperty.Should().BeTrue(); + } + + [Fact] + public void GivenSheet_WhenCustomEnumParserIsProvided_ValueIsConverted() + { + var sheetData = new SheetBuilder() + .AddHeaders("EnumProperty") + .AddRow(r => r.AddCell(c => c.WithColumnIndex(0).WithRowIndex(1).WithValue("Second").Build()).Build(1)) + .Build(); + + var result = new SheetMapper() + .AddConfigFor(cfg => cfg + .HasHeaders() + .MapColumn(column => column + .WithHeader("EnumProperty") + .WithCustomParser(x => + { + switch (x) + { + case "First": return EnumModel.First; + case "Second": return EnumModel.Second; + case "Third": return EnumModel.Third; + default: return EnumModel.Default; + } + }) + .IsRequired() + .MapTo(t => t.EnumProperty))) + .Map(sheetData); + + result.IsSuccess.Should().BeTrue(); + result.ParsedModels.Should().HaveCount(1); + result.ParsedModels.First().ParsedModel.EnumProperty.Should().Be(EnumModel.Second); + } } public class ModelOne diff --git a/src/SheetToObjects.Specs/Lib/ValueMapperSpecs.cs b/src/SheetToObjects.Specs/Lib/ValueMapperSpecs.cs index efd7f39..b85c221 100644 --- a/src/SheetToObjects.Specs/Lib/ValueMapperSpecs.cs +++ b/src/SheetToObjects.Specs/Lib/ValueMapperSpecs.cs @@ -1,8 +1,11 @@ -using CSharpFunctionalExtensions; +using System.Collections.Generic; +using CSharpFunctionalExtensions; using FluentAssertions; using Moq; using SheetToObjects.Lib; +using SheetToObjects.Lib.FluentConfiguration; using SheetToObjects.Lib.Parsing; +using SheetToObjects.Lib.Validation; using Xunit; namespace SheetToObjects.Specs.Lib @@ -16,16 +19,14 @@ public void GivenNotRequiredEmptyValue_WhenMapping_ItIsSetToDefaultValue() var mapper = new ValueMapper(parsingStrategyProvider.Object); + var columnMapping = new NameColumnMapping(string.Empty, string.Empty, string.Empty, null, null, null, false, null); + var result = mapper.Map( value: string.Empty, propertyType: typeof(int), columnIndex: 0, rowIndex: 0, - displayName: string.Empty, - propertyName: string.Empty, - format: string.Empty, - isRequired: false, - defaultValue: null); + columnMapping: columnMapping); result.IsSuccess.Should().BeTrue(); result.Value.Should().Be(string.Empty); @@ -38,16 +39,19 @@ public void GivenRequiredEmptyValue_WhenMapping_ValidationFails() var mapper = new ValueMapper(parsingStrategyProvider.Object); + var columnMapping = new NameColumnMapping( + string.Empty, + string.Empty, + string.Empty, + new List { new RequiredRule() }, + null, null, false, null); + var result = mapper.Map( - value: string.Empty, + value: string.Empty, propertyType: typeof(int), columnIndex: 0, rowIndex: 0, - displayName: string.Empty, - propertyName: string.Empty, - format: string.Empty, - isRequired: true, - defaultValue: null); + columnMapping: columnMapping); result.IsFailure.Should().BeTrue(); } @@ -61,16 +65,14 @@ public void GivenValidValue_WhenParsingIsSuccesful_ItSucceeds() var mapper = new ValueMapper(parsingStrategyProvider.Object); + var columnMapping = new NameColumnMapping(string.Empty, string.Empty, string.Empty, null, null, null, false, null); + var result = mapper.Map( value: value.ToString(), propertyType: typeof(int), columnIndex: 0, rowIndex: 0, - displayName: string.Empty, - propertyName: string.Empty, - format: string.Empty, - isRequired: false, - defaultValue: null); + columnMapping: columnMapping); result.IsSuccess.Should().BeTrue(); result.Value.Should().Be(value); @@ -85,16 +87,14 @@ public void GivenInvalidValue_WhenParsingFails_FailureIsReturned() var mapper = new ValueMapper(parsingStrategyProvider.Object); + var columnMapping = new NameColumnMapping(string.Empty, string.Empty, string.Empty, null, null, null, false, null); + var result = mapper.Map( value: value, propertyType: typeof(int), columnIndex: 0, rowIndex: 0, - displayName: string.Empty, - propertyName: string.Empty, - format: string.Empty, - isRequired: false, - defaultValue: null); + columnMapping: columnMapping); result.IsFailure.Should().BeTrue(); } diff --git a/src/SheetToObjects.Specs/TestModels/EnumModel.cs b/src/SheetToObjects.Specs/TestModels/EnumModel.cs index b14247c..30c632f 100644 --- a/src/SheetToObjects.Specs/TestModels/EnumModel.cs +++ b/src/SheetToObjects.Specs/TestModels/EnumModel.cs @@ -2,8 +2,9 @@ { public enum EnumModel { + Default = 0, First = 1, Second =2, - Third= 3 + Third= 3, } } \ No newline at end of file From f93b45434b6dca6c91906ffbc968ddfa74cdbf27 Mon Sep 17 00:00:00 2001 From: josdeweger Date: Sun, 23 Dec 2018 23:08:23 +0100 Subject: [PATCH 2/4] Upped the versionnr --- src/Common.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common.props b/src/Common.props index 1d348f8..297935f 100644 --- a/src/Common.props +++ b/src/Common.props @@ -1,5 +1,5 @@ - 2.2.0 + 2.3.0 From 7f0fb8b3b3f3cbac5edc58a10f4fbc2f207d7a5b Mon Sep 17 00:00:00 2001 From: josdeweger Date: Mon, 24 Dec 2018 15:02:29 +0100 Subject: [PATCH 3/4] Rename WithCustomerParser to ParseValueUsing --- .../FluentConfiguration/ColumnMapping.cs | 6 +++--- .../FluentConfiguration/ColumnMappingBuilder.cs | 14 +++++++------- .../FluentConfiguration/IndexColumnMapping.cs | 4 ++-- .../FluentConfiguration/LetterColumnMapping.cs | 4 ++-- .../FluentConfiguration/NameColumnMapping.cs | 4 ++-- .../FluentConfiguration/PropertyColumnMapping.cs | 4 ++-- src/SheetToObjects.Lib/ValueMapper.cs | 4 ++-- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/SheetToObjects.Lib/FluentConfiguration/ColumnMapping.cs b/src/SheetToObjects.Lib/FluentConfiguration/ColumnMapping.cs index 5eaf093..18aee66 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/ColumnMapping.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/ColumnMapping.cs @@ -14,7 +14,7 @@ public abstract class ColumnMapping public List ParsingRules { get; } public List Rules { get; } public object DefaultValue { get; } - public readonly Func CustomParser; + public readonly Func CustomValueParser; protected ColumnMapping( string propertyName, @@ -22,9 +22,9 @@ protected ColumnMapping( List parsingRules, List rules, object defaultValue, - Func customParser) + Func customValueParser) { - CustomParser = customParser; + CustomValueParser = customValueParser; PropertyName = propertyName; Format = format; ParsingRules = parsingRules ?? new List(); diff --git a/src/SheetToObjects.Lib/FluentConfiguration/ColumnMappingBuilder.cs b/src/SheetToObjects.Lib/FluentConfiguration/ColumnMappingBuilder.cs index e5b9ca7..5f63ebe 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/ColumnMappingBuilder.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/ColumnMappingBuilder.cs @@ -20,7 +20,7 @@ public class ColumnMappingBuilder private bool _isRequiredInHeaderRow; private readonly List _parsingRules = new List(); private readonly List _rules = new List(); - private Func _customParser; + private Func _customValueParser; /// /// Map to column by header (other options are to map by column index or column letter) @@ -102,9 +102,9 @@ public ColumnMappingBuilder UsingFormat(string format) return this; } - public ColumnMappingBuilder WithCustomParser(Func customParser) + public ColumnMappingBuilder ParseValueUsing(Func customValueParser) { - _customParser = customParser; + _customValueParser = customValueParser; return this; } @@ -152,13 +152,13 @@ public ColumnMapping MapTo(PropertyInfo property) _propertyName = property.Name; if(_header.IsNotNullOrWhiteSpace()) - return new NameColumnMapping(_header, _propertyName, _format, _parsingRules, _rules, _defaultValue,_isRequiredInHeaderRow, _customParser); + return new NameColumnMapping(_header, _propertyName, _format, _parsingRules, _rules, _defaultValue,_isRequiredInHeaderRow, _customValueParser); if(_columnLetter.IsNotNullOrWhiteSpace()) - return new LetterColumnMapping(_columnLetter, _propertyName, _format, _parsingRules, _rules, _defaultValue, _customParser); + return new LetterColumnMapping(_columnLetter, _propertyName, _format, _parsingRules, _rules, _defaultValue, _customValueParser); if(_columnIndex >= 0) - return new IndexColumnMapping(_columnIndex, _propertyName, _format, _parsingRules, _rules, _defaultValue, _customParser); + return new IndexColumnMapping(_columnIndex, _propertyName, _format, _parsingRules, _rules, _defaultValue, _customValueParser); - return new PropertyColumnMapping(_propertyName, _format, _parsingRules, _rules, _defaultValue,_isRequiredInHeaderRow, _customParser); + return new PropertyColumnMapping(_propertyName, _format, _parsingRules, _rules, _defaultValue,_isRequiredInHeaderRow, _customValueParser); } } } diff --git a/src/SheetToObjects.Lib/FluentConfiguration/IndexColumnMapping.cs b/src/SheetToObjects.Lib/FluentConfiguration/IndexColumnMapping.cs index cacda0b..137c813 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/IndexColumnMapping.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/IndexColumnMapping.cs @@ -13,8 +13,8 @@ public IndexColumnMapping( List parsingRules, List rules, object defaultValue, - Func customParser) - : base(propertyName, format, parsingRules, rules, defaultValue, customParser) + Func customValueParser) + : base(propertyName, format, parsingRules, rules, defaultValue, customValueParser) { ColumnIndex = columnIndex; } diff --git a/src/SheetToObjects.Lib/FluentConfiguration/LetterColumnMapping.cs b/src/SheetToObjects.Lib/FluentConfiguration/LetterColumnMapping.cs index f0a7e76..84d84c1 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/LetterColumnMapping.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/LetterColumnMapping.cs @@ -16,8 +16,8 @@ public LetterColumnMapping( List parsingRules, List rules, object defaultValue, - Func customParser) - : base(propertyName, format, parsingRules, rules, defaultValue, customParser) + Func customValueParser) + : base(propertyName, format, parsingRules, rules, defaultValue, customValueParser) { ColumnName = columnLetter; ColumnIndex = columnLetter.ConvertExcelColumnNameToIndex(); diff --git a/src/SheetToObjects.Lib/FluentConfiguration/NameColumnMapping.cs b/src/SheetToObjects.Lib/FluentConfiguration/NameColumnMapping.cs index 078ce2b..a1bd482 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/NameColumnMapping.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/NameColumnMapping.cs @@ -18,8 +18,8 @@ public NameColumnMapping( List rules, object defaultValue, bool isRequiredInHeaderRow, - Func customParser) - : base(propertyName, format, parsingRules, rules, defaultValue, customParser) + Func customValueParser) + : base(propertyName, format, parsingRules, rules, defaultValue, customValueParser) { ColumnName = columnName; ColumnIndex = -1; diff --git a/src/SheetToObjects.Lib/FluentConfiguration/PropertyColumnMapping.cs b/src/SheetToObjects.Lib/FluentConfiguration/PropertyColumnMapping.cs index 21f230e..62be72b 100644 --- a/src/SheetToObjects.Lib/FluentConfiguration/PropertyColumnMapping.cs +++ b/src/SheetToObjects.Lib/FluentConfiguration/PropertyColumnMapping.cs @@ -16,8 +16,8 @@ public PropertyColumnMapping( List rules, object defaultValue, bool isRequiredInHeaderRow, - Func customParser) - : base(propertyName, format, parsingRules, rules, defaultValue, customParser) + Func customValueParser) + : base(propertyName, format, parsingRules, rules, defaultValue, customValueParser) { ColumnName = propertyName; ColumnIndex = -1; diff --git a/src/SheetToObjects.Lib/ValueMapper.cs b/src/SheetToObjects.Lib/ValueMapper.cs index 6afb0b7..4fcf6b9 100644 --- a/src/SheetToObjects.Lib/ValueMapper.cs +++ b/src/SheetToObjects.Lib/ValueMapper.cs @@ -28,11 +28,11 @@ public Result Map( return HandleEmptyValue(columnIndex, rowIndex, columnMapping); } - if (columnMapping.CustomParser.IsNotNull()) + if (columnMapping.CustomValueParser.IsNotNull()) { try { - var parsedValue = columnMapping.CustomParser(value); + var parsedValue = columnMapping.CustomValueParser(value); return Result.Ok(parsedValue); } catch (Exception) From 3952f7c9dbf316039963dcaf9739ad035b512f17 Mon Sep 17 00:00:00 2001 From: josdeweger Date: Mon, 24 Dec 2018 15:02:48 +0100 Subject: [PATCH 4/4] Spec for custom parsing failure --- .../Lib/SheetMapperSpecs.cs | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/SheetToObjects.Specs/Lib/SheetMapperSpecs.cs b/src/SheetToObjects.Specs/Lib/SheetMapperSpecs.cs index 12c555f..f69ddbd 100644 --- a/src/SheetToObjects.Specs/Lib/SheetMapperSpecs.cs +++ b/src/SheetToObjects.Specs/Lib/SheetMapperSpecs.cs @@ -358,7 +358,7 @@ public void GivenParsingShouldBeStoppedOnFirstEmptyRow_WhenSecondRowIsEmptyAndTh } [Fact] - public void GivenSheet_WhenCustomBooleanParserIsProvided_ValueIsConverted() + public void GivenSheet_WhenCustomBooleanParserIsProvided_ValueIsConvertedToBoolean() { var sheetData = new SheetBuilder() .AddHeaders("Bool") @@ -370,8 +370,8 @@ public void GivenSheet_WhenCustomBooleanParserIsProvided_ValueIsConverted() .HasHeaders() .MapColumn(column => column .WithHeader("Bool") - .WithCustomParser(x => x.Equals("1") ? true : false) .IsRequired() + .ParseValueUsing(x => x.Equals("1") ? true : false) .MapTo(t => t.BoolProperty))) .Map(sheetData); @@ -381,7 +381,7 @@ public void GivenSheet_WhenCustomBooleanParserIsProvided_ValueIsConverted() } [Fact] - public void GivenSheet_WhenCustomEnumParserIsProvided_ValueIsConverted() + public void GivenSheet_WhenCustomEnumParserIsProvided_ValueIsConvertedToEnum() { var sheetData = new SheetBuilder() .AddHeaders("EnumProperty") @@ -393,7 +393,8 @@ public void GivenSheet_WhenCustomEnumParserIsProvided_ValueIsConverted() .HasHeaders() .MapColumn(column => column .WithHeader("EnumProperty") - .WithCustomParser(x => + .IsRequired() + .ParseValueUsing(x => { switch (x) { @@ -403,7 +404,6 @@ public void GivenSheet_WhenCustomEnumParserIsProvided_ValueIsConverted() default: return EnumModel.Default; } }) - .IsRequired() .MapTo(t => t.EnumProperty))) .Map(sheetData); @@ -411,6 +411,28 @@ public void GivenSheet_WhenCustomEnumParserIsProvided_ValueIsConverted() result.ParsedModels.Should().HaveCount(1); result.ParsedModels.First().ParsedModel.EnumProperty.Should().Be(EnumModel.Second); } + + [Fact] + public void GivenSheet_WhenCustomEnumParserFails_ResultContainsFailure() + { + var sheetData = new SheetBuilder() + .AddHeaders("StringProperty") + .AddRow(r => r.AddCell(c => c.WithColumnIndex(0).WithRowIndex(1).WithValue("MyValue").Build()).Build(1)) + .Build(); + + var result = new SheetMapper() + .AddConfigFor(cfg => cfg + .HasHeaders() + .MapColumn(column => column + .WithHeader("StringProperty") + .ParseValueUsing(x => throw new Exception("An exception occured")) + .MapTo(t => t.StringProperty))) + .Map(sheetData); + + result.IsSuccess.Should().BeFalse(); + result.ValidationErrors.Should().HaveCount(1); + result.ValidationErrors.First().ErrorMessage.Should().Be("Could not parse value"); + } } public class ModelOne