-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
resolve merge conflicts after project restucture
Fixes #6
- Loading branch information
Showing
28 changed files
with
1,128 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using ExcelMapper.Test.Models; | ||
using NPOI.SS.UserModel; | ||
using YummyCode.ExcelMapper.Exporter; | ||
|
||
namespace YummyCode.ExcelMapper.Test.MapperProfiles | ||
{ | ||
public class ExportProfile: ExportMapper<Person> | ||
{ | ||
public ExportProfile(IWorkbook workbook): base(workbook) | ||
{ | ||
_ = CreateMap() | ||
.ForColumn("A", x => x.Name, opt => opt.WithHeader("Name")) | ||
.ForColumn("B", x => x.Family, opt => opt.WithHeader("Family")) | ||
.ForColumn("C", x => x.BirthDate, opt => opt.WithHeader("BirthDate").UseAction(ConvertToPersian)) | ||
.ForColumn("D", x => x.Address, opt => opt.WithHeader("Address")) | ||
.ForColumn("E", x => x.Name, opt => opt.WithHeader("NAME").UseAction(x => x?.ToUpper())); | ||
// .ForColumn("B", opt => opt.MapFrom<Employee>(x => x.Name)); | ||
} | ||
|
||
private static string ConvertToPersian(DateTime? arg) | ||
{ | ||
return arg?.ToShortDateString() ?? ""; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using YummyCode.ExcelMapper.Shared.Models; | ||
|
||
namespace YummyCode.ExcelMapper.Exceptions | ||
{ | ||
public class ExcelMappingException(Dictionary<string, ResultState> cols) : Exception | ||
{ | ||
public Dictionary<string, ResultState> Cols { get; set; } = cols; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
using System; | ||
|
||
namespace YummyCode.ExcelMapper.Models | ||
{ | ||
public sealed class ExcelColAttribute(string col) : Attribute | ||
{ | ||
public string Col { get; set; } = col; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using System.Collections.Generic; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
|
||
namespace YummyCode.ExcelMapper.Models | ||
{ | ||
public sealed class PropertyMapInfo(string name, PropertyInfo property, string columnName) | ||
{ | ||
public string Name { get; set; } = name; | ||
public PropertyInfo Property { get; set; } = property; | ||
public string ColumnName { get; set; } = columnName; | ||
public List<LambdaExpression> Actions { get; set; } = new(); | ||
public List<LambdaExpression> Validations { get; set; } = new(); | ||
public List<string> IgnoredValues { get; set; } = new List<string>(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using System; | ||
using System.IO; | ||
using NPOI.XSSF.Streaming; | ||
|
||
namespace YummyCode.ExcelMapper.Exporter | ||
{ | ||
public class ExcelWriter | ||
{ | ||
public SXSSFWorkbook WorkBook { get; } = new(); | ||
|
||
#region Methods | ||
/// <summary> | ||
/// Add new sheet using SheetBuilder | ||
/// </summary> | ||
/// <param name="mapper">mapper instance of TSource</param> | ||
/// <param name="builder">sheet builder</param> | ||
/// <returns></returns> | ||
public ExcelWriter AddSheet<TSource>(IExportMapper<TSource> mapper, Action<SheetBuilder<TSource>> builder) where TSource : new() | ||
{ | ||
builder.Invoke(new SheetBuilder<TSource>(WorkBook, mapper)); | ||
return this; | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Save generated excel document to memory stream and return it | ||
/// </summary> | ||
/// <returns>Memory stream contains excel file's outputs</returns> | ||
public MemoryStream GetFileContent() | ||
{ | ||
var memoryData = new MemoryStream(); | ||
WorkBook.Write(memoryData); | ||
GC.Collect(); | ||
|
||
return memoryData; | ||
} | ||
|
||
public void SaveToFile(string fileName) | ||
{ | ||
using var fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write); | ||
WorkBook.Write(fileStream); | ||
GC.Collect(); | ||
} | ||
|
||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using NPOI.SS.UserModel; | ||
<<<<<<<< HEAD:src/YummyCode.ExcelMapper.Exporter/ExportMapper.cs | ||
======== | ||
using YummyCode.ExcelMapper.Exporter.Models; | ||
>>>>>>>> 452e969fed67e87b821b76b42a2de365434c852f:YummyCode.ExcelMapper.Exporter/ExportMapper.cs | ||
using YummyCode.ExcelMapper.Shared.Models; | ||
|
||
namespace YummyCode.ExcelMapper.Exporter | ||
{ | ||
public abstract class ExportMapper<TSource> : IExportMapper<TSource> where TSource : new() | ||
{ | ||
// protected IWorkbook Workbook; | ||
private IExportMappingExpression<TSource> _mappingExpression; | ||
private Dictionary<int, List<Delegate>> _compiledActions; | ||
public ExportMapper(IWorkbook workbook) | ||
{ | ||
// Workbook = workbook; | ||
_mappingExpression = new ExportMappingExpression<TSource>(); | ||
_compiledActions = new Dictionary<int, List<Delegate>>(); | ||
} | ||
public List<CellMappingInfo> Mappings => | ||
_mappingExpression.Mappings; | ||
|
||
public IExportMappingExpression<TSource> CreateMap() | ||
{ | ||
var expression = new ExportMappingExpression<TSource>(); | ||
_mappingExpression = expression; | ||
_compiledActions = new Dictionary<int, List<Delegate>>(); | ||
return expression; | ||
} | ||
|
||
public void Map(TSource data, IRow row) | ||
{ | ||
if (_compiledActions.Count == 0) | ||
{ | ||
CompileMappingActions(); | ||
} | ||
|
||
var mappingCols = _mappingExpression.Mappings; | ||
foreach (var colMapping in mappingCols) | ||
{ | ||
try | ||
{ | ||
var converted = ExecuteMappingAction(data, colMapping); | ||
SetCellValue(row, colMapping, converted); | ||
} | ||
//TODO Check | ||
catch | ||
{ | ||
throw; | ||
} | ||
} | ||
} | ||
|
||
private void CompileMappingActions() | ||
{ | ||
foreach (var mapping in _mappingExpression.Mappings) | ||
{ | ||
if (mapping == null) { continue; } | ||
var mappingCompiledActions = mapping.Actions.Select(action => action.Compile()).ToList(); | ||
|
||
if (mappingCompiledActions.Any()) | ||
{ | ||
_compiledActions.Add(mapping.Column, mappingCompiledActions); | ||
} | ||
} | ||
} | ||
|
||
private static void SetCellValue(IRow row, CellMappingInfo colMapping, object converted) | ||
{ | ||
// TODO: should check for value is correct column name in excel | ||
if (colMapping.Column < 0) return; | ||
|
||
var cellValue = string.Empty; | ||
if (colMapping.ConstValue != null) | ||
cellValue = colMapping.ConstValue; | ||
|
||
else if (converted != null) | ||
cellValue = converted.ToString(); | ||
|
||
else if (colMapping.DefaultValue != null) | ||
cellValue = colMapping.DefaultValue; | ||
|
||
var cell = row.CreateCell(colMapping.Column); | ||
if (colMapping.Style != null) | ||
cell.CellStyle = colMapping.Style; | ||
|
||
cell.SetCellValue(cellValue); | ||
} | ||
|
||
private object ExecuteMappingAction(TSource data, CellMappingInfo mapping) | ||
{ | ||
//data = data ?? throw new ArgumentNullException(nameof(data)); | ||
//mapping = mapping ?? throw new ArgumentNullException(nameof(mapping)); | ||
var value = data?.GetType().GetProperty(mapping.Property?.Name).GetValue(data, null); | ||
if (!_compiledActions.ContainsKey(mapping.Column)) return value; | ||
var converted = value; | ||
for (var i = 0; i < _compiledActions[mapping.Column].Count; i++) | ||
{ | ||
var action = _compiledActions[mapping.Column][i]; | ||
converted = action.DynamicInvoke(converted); | ||
} | ||
|
||
return converted; | ||
} | ||
|
||
|
||
public void MapHeader(ref IRow headerRow) | ||
{ | ||
var mappingCols = _mappingExpression.Mappings; | ||
foreach (var mapping in mappingCols) | ||
{ | ||
headerRow.CreateCell(mapping.Column).SetCellValue(mapping.Header); | ||
} | ||
} | ||
|
||
public IEnumerable<string> GetMappingColumns() | ||
{ | ||
var items = _mappingExpression.Mappings; | ||
//items.Reverse(); | ||
foreach (var item in items) | ||
{ | ||
yield return item.Header ?? item.Property?.Name ?? ""; | ||
} | ||
} | ||
} | ||
} |
125 changes: 125 additions & 0 deletions
125
YummyCode.ExcelMapper.Exporter/ExportMappingExpression.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
using NPOI.SS.UserModel; | ||
using NPOI.SS.Util; | ||
using YummyCode.ExcelMapper.Exporter.Models; | ||
using YummyCode.ExcelMapper.Shared.Models; | ||
|
||
namespace YummyCode.ExcelMapper.Exporter | ||
{ | ||
public class ExportMappingExpression<TDestination> : IExportMappingExpression<TDestination> | ||
{ | ||
private ICellStyle _defaultStyle; | ||
|
||
public List<CellMappingInfo> Mappings { get; } = new List<CellMappingInfo>(); | ||
|
||
public IExportMappingExpression<TDestination> ForAllMembers | ||
(Action<ExportConfigurationExpression<TDestination>> memberOptions) | ||
{ | ||
|
||
throw new NotImplementedException(); | ||
} | ||
|
||
public IExportMappingExpression<TDestination> ForAllOtherMembers(Action<ExportConfigurationExpression<TDestination>> memberOptions) | ||
{ | ||
// TODO: implement this | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public ExportMappingExpression<TDestination> ForColumn<TMember> | ||
(string column, | ||
Expression<Func<TDestination, TMember>> destinationMember, | ||
Action<ExportMemberConfigurationExpression<TDestination, TMember>> memberOptions = null) | ||
{ | ||
var colRef = new CellReference(column); | ||
var config = GetCellConfig(colRef.Col, destinationMember, memberOptions); ; | ||
Mappings.Add(config); | ||
return this; | ||
} | ||
|
||
|
||
public ExportMappingExpression<TDestination> AddColumn<TMember> | ||
(Expression<Func<TDestination, TMember>> destinationMember, | ||
Action<ExportMemberConfigurationExpression<TDestination, TMember>> memberOptions = null) | ||
{ | ||
var config = GetCellConfig(Mappings.Count, destinationMember, memberOptions); | ||
Mappings.Add(config); | ||
return this; | ||
} | ||
|
||
private CellMappingInfo GetCellConfig<TMember>(int column, Expression<Func<TDestination, TMember>> destinationMember, Action<ExportMemberConfigurationExpression<TDestination, TMember>> memberOptions) | ||
{ | ||
var memberName = ((MemberExpression)destinationMember.Body).Member.Name; | ||
var property = typeof(TDestination).GetProperty(memberName); | ||
|
||
var expression = new ExportMemberConfigurationExpression<TDestination, TMember>(); | ||
memberOptions(expression); | ||
|
||
if (expression.CellStyle == null && _defaultStyle != null) | ||
{ | ||
expression.UseStyle(_defaultStyle); | ||
} | ||
|
||
var config = new CellMappingInfo | ||
{ | ||
Header = expression.Header, | ||
Column = column, | ||
Property = property, | ||
Actions = expression.Actions, | ||
Style = expression.CellStyle, | ||
ConstValue = expression.ConstValue, | ||
DefaultValue = expression.DefaultValue?.ToString() | ||
}; | ||
Mappings.Add(config); | ||
return config; | ||
} | ||
|
||
private string GetAvailableColumn() | ||
{ | ||
return ColumnIndexToColumnLetter(Mappings.Count + 1); | ||
} | ||
|
||
/// <summary> | ||
/// Converts index to excel column name | ||
/// for example 0=> A, 33 => AG | ||
/// </summary> | ||
/// <param name="colIndex">index of column in excel</param> | ||
/// <returns>corresponding column name for colIndex</returns> | ||
private string ColumnIndexToColumnLetter(int colIndex) | ||
{ | ||
var div = colIndex; | ||
var colLetter = string.Empty; | ||
while (div > 0) | ||
{ | ||
var mod = (div - 1) % 26; | ||
colLetter = (char)(65 + mod) + colLetter; | ||
div = ((div - mod) / 26); | ||
} | ||
return colLetter; | ||
} | ||
|
||
public List<LambdaExpression> GetActions(PropertyInfo property) | ||
{ | ||
return Mappings | ||
.FirstOrDefault(x => x.Property.Name == property.Name)? | ||
.Actions ?? new List<LambdaExpression>(); | ||
} | ||
|
||
public CellMappingInfo this[PropertyInfo property] | ||
{ | ||
get | ||
{ | ||
return Mappings.FirstOrDefault(x => x.Property.Name == property.Name); | ||
} | ||
} | ||
|
||
public ExportMappingExpression<TDestination> SetDefaultStyle(ICellStyle cellStyle) | ||
{ | ||
_defaultStyle = cellStyle; | ||
return this; | ||
} | ||
} | ||
} |
Oops, something went wrong.