Skip to content

Commit

Permalink
Upgrade for CsvHelper v21.x (#11)
Browse files Browse the repository at this point in the history
* Upgrade for CsvHelper v22.x

* Fixed new-line for unit test
  • Loading branch information
shibayan authored Jan 19, 2021
1 parent 2bb2ed0 commit d4fb3d9
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 57 deletions.
49 changes: 35 additions & 14 deletions CsvHelper.FastDynamic.Performance/Internal/CsvReaderExtension.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,57 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CsvHelper.FastDynamic.Performance.Internal
{
internal static class CsvReaderExtension
{
internal static IReadOnlyList<IDictionary<string, object>> GetDictionaryRecords(this CsvReader csvReader)
=> csvReader.EnumerateDictionaryRecords().ToArray();

internal static IEnumerable<IDictionary<string, object>> EnumerateDictionaryRecords(this CsvReader csvReader)
{
// Read Header
csvReader.Read();
csvReader.ReadHeader();
if (csvReader.Configuration.HasHeaderRecord && csvReader.HeaderRecord == null)
{
if (!csvReader.Read())
{
yield break;
}

var headerRecord = csvReader.Context
.HeaderRecord
csvReader.ReadHeader();
}

var headerRecord = csvReader.HeaderRecord
.Select((x, i) => csvReader.Configuration.PrepareHeaderForMatch(x, i))
.ToArray();

var result = new List<IDictionary<string, object>>();

while (csvReader.Read())
{
var record = new Dictionary<string, object>(headerRecord.Length);
Dictionary<string, object> record;

for (int i = 0; i < headerRecord.Length; i++)
try
{
record[headerRecord[i]] = csvReader[i];
record = new Dictionary<string, object>(headerRecord.Length);

for (int i = 0; i < headerRecord.Length; i++)
{
record[headerRecord[i]] = csvReader.Parser[i];
}
}
catch (Exception ex)
{
var readerException = new ReaderException(csvReader.Context, "An unexpected error occurred.", ex);

result.Add(record);
}
if (csvReader.Configuration.ReadingExceptionOccurred?.Invoke(readerException) ?? true)
{
throw readerException;
}

return result;
continue;
}

yield return record;
}
}
}
}
5 changes: 3 additions & 2 deletions CsvHelper.FastDynamic.Tests/TestData.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;

namespace CsvHelper.FastDynamic.Tests
{
public static class TestData
{
public static readonly string CsvContent = "Id,Name,Location\r\n1,kazuakix,Wakayama\r\n2,daruyanagi,Ehime\r\n3,buchizo,Osaka\r\n";
public static readonly string CsvContent = $"Id,Name,Location{Environment.NewLine}1,kazuakix,Wakayama{Environment.NewLine}2,daruyanagi,Ehime{Environment.NewLine}3,buchizo,Osaka{Environment.NewLine}";

public static readonly IReadOnlyList<IDictionary<string, string>> CsvRecords = new[]
{
Expand Down
2 changes: 1 addition & 1 deletion CsvHelper.FastDynamic/CsvHelper.FastDynamic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CsvHelper" Version="19.0.0" />
<PackageReference Include="CsvHelper" Version="21.0.0" />
</ItemGroup>

<PropertyGroup>
Expand Down
39 changes: 19 additions & 20 deletions CsvHelper.FastDynamic/CsvReaderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ public static IReadOnlyList<dynamic> GetDynamicRecords(this CsvReader csvReader)

public static IEnumerable<dynamic> EnumerateDynamicRecords(this CsvReader csvReader)
{
var context = csvReader.Context;

if (context.ReaderConfiguration.HasHeaderRecord && context.HeaderRecord == null)
if (csvReader.Configuration.HasHeaderRecord && csvReader.HeaderRecord == null)
{
if (!csvReader.Read())
{
Expand All @@ -24,27 +22,30 @@ public static IEnumerable<dynamic> EnumerateDynamicRecords(this CsvReader csvRea
csvReader.ReadHeader();
}

var csvHeader = new CsvHeader(context.HeaderRecord
.Select((x, i) => csvReader.Configuration.PrepareHeaderForMatch(x, i))
.ToArray());
var csvHeader = new CsvHeader(csvReader.HeaderRecord
.Select((x, i) => csvReader.Configuration.PrepareHeaderForMatch(x, i))
.ToArray());

while (csvReader.Read())
{
CsvRecord record;

try
{
var values = new object[context.HeaderRecord.Length];
var values = new object[csvReader.HeaderRecord.Length];

Array.Copy(context.Record, values, context.Record.Length);
for (int i = 0; i < csvReader.HeaderRecord.Length; i++)
{
values[i] = csvReader.Parser[i];
}

record = new CsvRecord(csvHeader, values);
}
catch (Exception ex)
{
var readerException = new ReaderException(context, "An unexpected error occurred.", ex);
var readerException = new ReaderException(csvReader.Context, "An unexpected error occurred.", ex);

if (context.ReaderConfiguration.ReadingExceptionOccurred?.Invoke(readerException) ?? true)
if (csvReader.Configuration.ReadingExceptionOccurred?.Invoke(readerException) ?? true)
{
throw readerException;
}
Expand Down Expand Up @@ -72,9 +73,7 @@ public static async Task<IReadOnlyList<dynamic>> GetDynamicRecordsAsync(this Csv

public static async IAsyncEnumerable<dynamic> EnumerateDynamicRecordsAsync(this CsvReader csvReader)
{
var context = csvReader.Context;

if (context.ReaderConfiguration.HasHeaderRecord && context.HeaderRecord == null)
if (csvReader.Configuration.HasHeaderRecord && csvReader.HeaderRecord == null)
{
if (!await csvReader.ReadAsync().ConfigureAwait(false))
{
Expand All @@ -84,27 +83,27 @@ public static async IAsyncEnumerable<dynamic> EnumerateDynamicRecordsAsync(this
csvReader.ReadHeader();
}

var csvHeader = new CsvHeader(context.HeaderRecord
.Select((x, i) => csvReader.Configuration.PrepareHeaderForMatch(x, i))
.ToArray());
var csvHeader = new CsvHeader(csvReader.HeaderRecord
.Select((x, i) => csvReader.Configuration.PrepareHeaderForMatch(x, i))
.ToArray());

while (await csvReader.ReadAsync().ConfigureAwait(false))
{
CsvRecord record;

try
{
var values = new object[context.HeaderRecord.Length];
var values = new object[csvReader.HeaderRecord.Length];

Array.Copy(context.Record, values, context.Record.Length);
Array.Copy(csvReader.Parser.Record, values, csvReader.Parser.Record.Length);

record = new CsvRecord(csvHeader, values);
}
catch (Exception ex)
{
var readerException = new ReaderException(context, "An unexpected error occurred.", ex);
var readerException = new ReaderException(csvReader.Context, "An unexpected error occurred.", ex);

if (context.ReaderConfiguration.ReadingExceptionOccurred?.Invoke(readerException) ?? true)
if (csvReader.Configuration.ReadingExceptionOccurred?.Invoke(readerException) ?? true)
{
throw readerException;
}
Expand Down
17 changes: 12 additions & 5 deletions CsvHelper.FastDynamic/CsvWriterExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ public static class CsvWriterExtensions
public static void WriteDynamicRecords(this CsvWriter csvWriter, IEnumerable<object> records)
{
var context = csvWriter.Context;
var hasHeaderBeenWritten = false;

foreach (var record in records)
{
if (!context.HasHeaderBeenWritten && context.WriterConfiguration.HasHeaderRecord)
if (!hasHeaderBeenWritten && context.Configuration.HasHeaderRecord)
{
csvWriter.WriteHeaderInternal(record);
csvWriter.NextRecord();

hasHeaderBeenWritten = true;
}

csvWriter.WriteRecordInternal(record);
Expand All @@ -27,13 +30,16 @@ public static void WriteDynamicRecords(this CsvWriter csvWriter, IEnumerable<obj
public static async Task WriteDynamicRecordsAsync(this CsvWriter csvWriter, IEnumerable<object> records)
{
var context = csvWriter.Context;
var hasHeaderBeenWritten = false;

foreach (var record in records)
{
if (!context.HasHeaderBeenWritten && context.WriterConfiguration.HasHeaderRecord)
if (!hasHeaderBeenWritten && context.Configuration.HasHeaderRecord)
{
csvWriter.WriteHeaderInternal(record);
await csvWriter.NextRecordAsync().ConfigureAwait(false);

hasHeaderBeenWritten = true;
}

csvWriter.WriteRecordInternal(record);
Expand All @@ -46,13 +52,16 @@ public static async Task WriteDynamicRecordsAsync(this CsvWriter csvWriter, IEnu
public static async Task WriteDynamicRecordsAsync(this CsvWriter csvWriter, IAsyncEnumerable<object> records)
{
var context = csvWriter.Context;
var hasHeaderBeenWritten = false;

await foreach (var record in records.ConfigureAwait(false))
{
if (!context.HasHeaderBeenWritten && context.WriterConfiguration.HasHeaderRecord)
if (!hasHeaderBeenWritten && context.Configuration.HasHeaderRecord)
{
csvWriter.WriteHeaderInternal(record);
await csvWriter.NextRecordAsync().ConfigureAwait(false);

hasHeaderBeenWritten = true;
}

csvWriter.WriteRecordInternal(record);
Expand All @@ -77,8 +86,6 @@ private static void WriteHeaderInternal(this CsvWriter csvWriter, object record)
{
csvWriter.WriteField(fieldName);
}

csvWriter.Context.HasHeaderBeenWritten = true;
}
else if (record is IDynamicMetaObjectProvider dynamicObject)
{
Expand Down
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,34 +66,34 @@ class Program
### Reader

```
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.329 (2004/?/20H1)
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i9-10940X CPU 3.30GHz, 1 CPU, 28 logical and 14 physical cores
.NET Core SDK=3.1.301
[Host] : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT
DefaultJob : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT
.NET Core SDK=5.0.102
[Host] : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT
DefaultJob : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|--------------------- |-----------:|---------:|---------:|--------:|--------:|------:|----------:|
| GetRecords | 1,687.1 us | 17.11 us | 15.17 us | 83.9844 | 41.0156 | - | 829.18 KB |
| GetDictionaryRecords | 776.7 us | 14.59 us | 16.21 us | 73.2422 | 34.1797 | - | 725.63 KB |
| GetDynamicRecords | 617.3 us | 11.23 us | 9.96 us | 61.5234 | 2.9297 | - | 608.87 KB |
| GetRecords | 1,350.7 us | 26.83 us | 38.48 us | 78.1250 | 39.0625 | - | 785.81 KB |
| GetDictionaryRecords | 419.0 us | 8.24 us | 11.81 us | 53.2227 | 20.0195 | - | 526.7 KB |
| GetDynamicRecords | 331.0 us | 6.59 us | 10.45 us | 41.5039 | 7.3242 | - | 408.92 KB |
```

### Writer

```
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.329 (2004/?/20H1)
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i9-10940X CPU 3.30GHz, 1 CPU, 28 logical and 14 physical cores
.NET Core SDK=3.1.301
[Host] : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT
DefaultJob : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT
.NET Core SDK=5.0.102
[Host] : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT
DefaultJob : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|-------------------- |-----------:|---------:|---------:|---------:|--------:|------:|-----------:|
| WriteRecords | 2,355.6 us | 46.86 us | 64.14 us | 148.4375 | 27.3438 | - | 1476.46 KB |
| WriteDynamicRecords | 885.7 us | 17.50 us | 16.37 us | 17.5781 | 2.9297 | - | 174.49 KB |
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|-------------------- |-----------:|---------:|----------:|---------:|--------:|------:|-----------:|
| WriteRecords | 4,104.7 us | 81.42 us | 142.60 us | 359.3750 | 70.3125 | - | 3532.62 KB |
| WriteDynamicRecords | 714.8 us | 14.16 us | 25.17 us | 12.6953 | 1.9531 | - | 132.48 KB |
```

## Thanks
Expand Down

0 comments on commit d4fb3d9

Please sign in to comment.