Files
mixtape/zero.Core/Utils/TableBuilder/CsvCreator.cs
T

180 lines
4.2 KiB
C#
Raw Normal View History

2021-11-20 13:52:28 +01:00
using System.Globalization;
2021-11-19 16:11:12 +01:00
using System.IO;
using System.Text;
2021-11-20 13:52:28 +01:00
namespace zero.Utils;
2021-11-19 16:11:12 +01:00
public class CsvCreator<T> : ITableCreator<T>
{
private MemoryStream Stream { get; set; }
private StreamWriter StreamWriter { get; set; }
private IEnumerable<TableColumn<T>> Columns { get; set; }
private const char CHAR_DBL_QUOTE = '"';
private const char CHAR_QUOTE = '\'';
private const char CHAR_COLON = ',';
private const char CHAR_SEMICOLON = ';';
private const string DATE_FORMAT = "dd. MM. yyyy"; // TODO date format from culture
private const string BOOL_YES = "Ja"; // TODO translation
private const string BOOL_NO = "Nein";
public CsvCreator(IEnumerable<TableColumn<T>> columns)
{
Columns = columns;
}
/// <summary>
/// Create a readable stream from a source enumerable
/// </summary>
public MemoryStream CreateStream(IEnumerable<T> source, CultureInfo culture)
{
StringBuilder builder = Create(true);
foreach (T item in source)
{
List<object> values = Columns.Select(c => c.FieldSelector != null && c.CanRender(item) ? c.FieldSelector(item) : String.Empty).ToList();
AppendLine(builder, values);
}
Stream = new MemoryStream();
StreamWriter = new StreamWriter(Stream, Encoding.UTF8);
StreamWriter.Write(builder);
StreamWriter.Flush();
Stream.Position = 0;
return Stream;
}
/// <summary>
/// Create a readable stream from a source enumerable
/// </summary>
public async Task<MemoryStream> CreateStream(IAsyncEnumerable<T> source, CultureInfo culture, CancellationToken token = default)
{
StringBuilder builder = Create(true);
await foreach (T item in source.WithCancellation(token))
{
List<object> values = Columns.Select(c => c.FieldSelector != null && c.CanRender(item) ? c.FieldSelector(item) : String.Empty).ToList();
AppendLine(builder, values);
}
Stream = new MemoryStream();
StreamWriter = new StreamWriter(Stream, Encoding.UTF8);
StreamWriter.Write(builder);
StreamWriter.Flush();
Stream.Position = 0;
return Stream;
}
/// <summary>
/// Create a CSV from a source enumerable
/// </summary>
protected StringBuilder Create(bool headerRow = true)
{
StringBuilder csv = new StringBuilder();
// add header
if (headerRow)
{
AppendLine(csv, Columns.Select(c => c.Name));
}
return csv;
}
/// <summary>
/// Appends a line to the CSV
/// </summary>
protected void AppendLine(StringBuilder builder, IEnumerable<object> values)
{
int index = 0;
int length = values.Count();
foreach (object value in values)
{
string property = MapProperty(value);
if (!String.IsNullOrWhiteSpace(property))
{
builder.Append(CHAR_DBL_QUOTE + property + CHAR_DBL_QUOTE);
}
if (++index < length)
{
builder.Append(CHAR_COLON);
}
}
builder.AppendLine();
}
/// <summary>
/// Map a property to a string based on its type
/// </summary>
protected string MapProperty(object value)
{
string property = String.Empty;
if (value == null)
{
return property;
}
if (value is string)
{
property = (string)value;
}
else if (value is bool)
{
property = (bool)value ? BOOL_YES : BOOL_NO;
}
else if (value is decimal || value is double || value is float)
{
property = value.ToString().Replace(",", ".");
}
else if (value is DateTime)
{
property = ((DateTime)value).ToString(DATE_FORMAT);
}
else if (value is DateTime?)
{
var val = (DateTime?)value;
property = val.HasValue ? val.Value.ToString(DATE_FORMAT) : String.Empty;
}
else if (value is DateTimeOffset)
{
property = ((DateTimeOffset)value).ToString(DATE_FORMAT);
}
else if (value is DateTimeOffset?)
{
var val = (DateTimeOffset?)value;
property = val.HasValue ? val.Value.ToString(DATE_FORMAT) : String.Empty;
}
else
{
property = value.ToString();
}
return property.Replace(CHAR_DBL_QUOTE, CHAR_QUOTE).Replace(CHAR_COLON, CHAR_SEMICOLON);
}
public void Dispose()
{
Stream?.Dispose();
StreamWriter?.Dispose();
}
}