Skip to content

Commit

Permalink
added support for CSV serialization to the main library
Browse files Browse the repository at this point in the history
  • Loading branch information
martinkonopka committed Nov 23, 2018
1 parent 5e28213 commit 9e1694f
Show file tree
Hide file tree
Showing 11 changed files with 618 additions and 0 deletions.
98 changes: 98 additions & 0 deletions src/UXI.GazeToolkit.Serialization/Formats/Csv/CsvDataReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CsvHelper;
using UXI.GazeToolkit.Serialization.Common;
using UXI.GazeToolkit.Serialization.Csv.DataConverters;

namespace UXI.GazeToolkit.Serialization.Csv
{
public class CsvDataReader : DisposableBase, IDataReader, IDisposable
{
private readonly CsvReader _reader;
private readonly CsvSerializerContext _serializer;
private readonly IDataConverter _converter;
private bool _shouldReadHeader = true;

public CsvDataReader(TextReader reader, Type dataType, CsvSerializerContext serializer)
{
_reader = new CsvReader(reader, serializer.Configuration);
_serializer = serializer;

_converter = serializer.DataConverters.FirstOrDefault(c => c.CanConvert(dataType)); // TODO ?? DefaultCsvConverter ?

DataType = dataType;
}


public Type DataType { get; }

// TODO not in converters, will never work if object of other type is passed because no converter will be found
public bool CanRead(Type objectType)
{
return DataType == objectType
|| DataType.IsSubclassOf(objectType)
|| objectType.IsAssignableFrom(DataType);
}


public bool TryRead(out object data)
{
TryReadHeader();

try
{
if (_reader.Read())
{
data = _converter.ReadCsv(_reader, DataType, _serializer);
return true;
}
}
catch (Exception exception)
{
throw new System.Runtime.Serialization.SerializationException("Failed to read or deserialize next data from the CSV file. See inner exception for more details.", exception);
}

data = null;
return false;
}


private void TryReadHeader()
{
if (_shouldReadHeader)
{
try
{
if (_reader.Read())
{
_converter.ReadCsvHeader(_reader, _serializer);
_shouldReadHeader = false;
}
}
catch (CsvHelperException exception)
{
throw new System.Runtime.Serialization.SerializationException("Failed to read CSV file header. See inner exception for more details.", exception);
}
}
}


private bool _disposed = false;
protected override void Dispose(bool disposing)
{
if (_disposed == false)
{
if (disposing)
{
_reader.Dispose();
}
_disposed = true;
}
base.Dispose(disposing);
}
}
}
100 changes: 100 additions & 0 deletions src/UXI.GazeToolkit.Serialization/Formats/Csv/CsvDataWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using CsvHelper;
using UXI.GazeToolkit.Serialization.Common;
using UXI.GazeToolkit.Serialization.Csv.DataConverters;

namespace UXI.GazeToolkit.Serialization.Csv
{
public class CsvDataWriter : DisposableBase, IDataWriter, IDisposable
{
private readonly CsvWriter _writer;
private readonly CsvSerializerContext _serializer;
private readonly IDataConverter _converter;
private bool _isOpen = true;

private bool _shouldWriteHeader = true;

public CsvDataWriter(TextWriter writer, Type dataType, CsvSerializerContext serializer)
{
_writer = new CsvWriter(writer, serializer.Configuration);

_serializer = serializer;

_converter = serializer.DataConverters.FirstOrDefault(c => c.CanConvert(dataType));

DataType = dataType;
}


public Type DataType { get; }


public bool CanWrite(Type objectType)
{
return _isOpen
&& (DataType == objectType
|| objectType.IsSubclassOf(DataType)
|| DataType.IsAssignableFrom(objectType));
}


public void Write(object data)
{
TryWriteHeader();

if (_isOpen)
{
try
{
_converter.WriteCsv(data, _writer, _serializer);
}
catch (Exception exception)
{
throw new SerializationException($"Failed to write or serialize next data to the CSV file. See inner exception for more details.", exception);
}
}
}


private void TryWriteHeader()
{
if (_shouldWriteHeader)
{
_converter.WriteCsvHeader(_writer, DataType, _serializer);
_shouldWriteHeader = false;
}
}


public void Close()
{
if (_isOpen)
{
TryWriteHeader();
_isOpen = false;
_writer.Flush();
}
}


private bool _disposed = false;
protected override void Dispose(bool disposing)
{
if (_disposed == false)
{
if (disposing)
{
_writer.Dispose();
}
_disposed = true;
}
base.Dispose(disposing);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using CsvHelper;
using CsvHelper.TypeConversion;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UXI.GazeToolkit.Serialization.Converters;
using UXI.GazeToolkit.Serialization.Csv.DataConverters;
using UXI.GazeToolkit.Serialization.Csv.TypeConverters;

namespace UXI.GazeToolkit.Serialization.Csv
{
public class CsvSerializationFactory : IDataSerializationFactory
{
public CsvSerializationFactory() { }

public CsvSerializationFactory(IDictionary<Type, ITypeConverter> typeConverters, bool replaceDefaultConverters, params IDataConverter[] converters)
: this(typeConverters, replaceDefaultConverters, converters.AsEnumerable())
{ }

public CsvSerializationFactory(params IDataConverter[] converters)
: this(null, false, converters.AsEnumerable())
{ }

public CsvSerializationFactory(bool replaceDefaultConverters, params IDataConverter[] converters)
: this(null, replaceDefaultConverters, converters.AsEnumerable())
{ }

public CsvSerializationFactory(IDictionary<Type, ITypeConverter> typeConverters, bool replaceDefaultConverters, IEnumerable<IDataConverter> converters)
{
if (typeConverters != null)
{
foreach (var typeConverterPair in typeConverters)
{
if (DefaultTypeConverters.ContainsKey(typeConverterPair.Key))
{
DefaultTypeConverters[typeConverterPair.Key] = typeConverterPair.Value;
}
else
{
DefaultTypeConverters.Add(typeConverterPair.Key, typeConverterPair.Value);
}
}
}

if (replaceDefaultConverters)
{
DefaultConverters.Clear();
}

if (converters != null)
{
DefaultConverters.AddRange(converters);
}
}


public FileFormat Format => FileFormat.CSV;


public Dictionary<Type, ITypeConverter> DefaultTypeConverters { get; } = new Dictionary<Type, ITypeConverter>();


public List<IDataConverter> DefaultConverters { get; } = new List<IDataConverter>()
{
new DefaultDataConverter()
};


public IDataReader CreateReaderForType(TextReader reader, Type dataType, SerializationConfiguration configuration)
{
var serializer = CreateSerializer(configuration);

return new CsvDataReader(reader, dataType, serializer);
}


public IDataWriter CreateWriterForType(TextWriter writer, Type dataType, SerializationConfiguration configuration)
{
var serializer = CreateSerializer(configuration);

return new CsvDataWriter(writer, dataType, serializer);
}


private CsvSerializerContext CreateSerializer(SerializationConfiguration configuration)
{
var serializer = new CsvSerializerContext();

serializer.Configuration.PrepareHeaderForMatch = header => header.ToLower();

SetupDateTimeOffsetSerialization(serializer, configuration.TimestampConverter);
SetupTimestampedDataSerialization(serializer, configuration.TimestampFieldName);

SetupDefaultConverters(serializer);

return serializer;
}


private void SetupDateTimeOffsetSerialization(CsvSerializerContext serializer, ITimestampStringConverter timestampConverter)
{
serializer.Configuration.TypeConverterCache.AddConverter<DateTimeOffset>(new DateTimeOffsetTypeConverter(timestampConverter));
}


private void SetupTimestampedDataSerialization(CsvSerializerContext serializer, string timestampFieldName)
{
serializer.TimestampFieldName = timestampFieldName;
}


private void SetupDefaultConverters(CsvSerializerContext serializer)
{
foreach (var typeConverter in DefaultTypeConverters)
{
serializer.Configuration.TypeConverterCache.AddConverter(typeConverter.Key, typeConverter.Value);
}

foreach (var converter in DefaultConverters)
{
serializer.DataConverters.Add(converter);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CsvHelper.Configuration;
using UXI.GazeToolkit.Serialization.Converters;
using UXI.GazeToolkit.Serialization.Csv.DataConverters;

namespace UXI.GazeToolkit.Serialization.Csv
{
public class CsvSerializerContext
{
public Configuration Configuration { get; set; } = new CsvHelper.Configuration.Configuration();

public Collection<IDataConverter> DataConverters { get; set; } = new Collection<IDataConverter>();

public ITimestampStringConverter TimestampConverter { get; set; }

public string TimestampFieldName { get; set; }
}
}

0 comments on commit 9e1694f

Please sign in to comment.