Skip to content

Commit e0e25e3

Browse files
Cooksaucesay25
authored andcommitted
Docs and Enhancing Tests
1 parent 873dc02 commit e0e25e3

4 files changed

Lines changed: 70 additions & 28 deletions

File tree

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,21 @@ private async Task<ulong> WriteToDatabaseAsync(PostgreSQLCopyHelper<TestEntity>
112112
}
113113
```
114114

115+
Or asynchronously with asynchronous enumerables:
116+
117+
```csharp
118+
private async Task<ulong> WriteToDatabaseAsync(PostgreSQLCopyHelper<TestEntity> copyHelper, IAsyncEnumerable<TestEntity> entities, CancellationToken cancellationToken = default)
119+
{
120+
using (var connection = new NpgsqlConnection("Server=127.0.0.1;Port=5432;Database=sampledb;User Id=philipp;Password=test_pwd;"))
121+
{
122+
await connection.OpenAsync(cancellationToken);
123+
124+
// Returns count of rows written
125+
return await copyHelper.SaveAllAsync(connection, entities, cancellationToken);
126+
}
127+
}
128+
```
129+
115130
## Case-Sensitive Identifiers ##
116131

117132
By default the library does not apply quotes to identifiers, such as Table Names and Column Names. If you want PostgreSQL-conform quoting for identifiers,

src/PostgreSQLCopyHelper.Test/Issues/Issue58_CancelRequest_Test.cs

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
using System;
2-
using System.Collections.Generic;
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Runtime.CompilerServices;
34
using System.Threading;
45
using System.Threading.Tasks;
56
using Npgsql;
67
using NUnit.Framework;
8+
using PostgreSQLCopyHelper.Test.Extensions;
79

810
namespace PostgreSQLCopyHelper.Test.Issues
911
{
@@ -26,40 +28,64 @@ protected override void OnSetupInTransaction()
2628
}
2729

2830
[Test]
29-
public async Task Test_CanceledBulkInsertThrowsWhenCanceled()
31+
public Task Test_CanceledBulkInsertThrowsWhenCanceledBeforeStarting()
3032
{
3133
subject = new PostgreSQLCopyHelper<User>("sample", "TestUsers")
3234
.MapInteger("Id", x => x.Id)
3335
.MapText("Name", x => x.Name);
3436

35-
var cancellationTokenSource = new CancellationTokenSource();
36-
37-
// Try to work with the Bulk Inserter:
38-
try
39-
{
40-
cancellationTokenSource.CancelAfter(15);
41-
await subject.SaveAllAsync(connection, FetchUserData(), cancellationTokenSource.Token);
42-
Assert.Fail("Should Never Reach Here!");
43-
}
44-
catch (TaskCanceledException)
37+
using (var cts = new CancellationTokenSource(1))
4538
{
39+
Assert.ThrowsAsync<TaskCanceledException>(async () =>
40+
await subject.SaveAllAsync(connection, FetchUserData(5), cts.Token), $"Should Throw Exception of Type {nameof(TaskCanceledException)}!");
4641
}
47-
catch (Exception)
42+
43+
return Task.CompletedTask;
44+
}
45+
46+
[Test]
47+
public Task Test_CanceledBulkInsertThrowsWhenCanceled()
48+
{
49+
subject = new PostgreSQLCopyHelper<User>("sample", "TestUsers")
50+
.MapInteger("Id", x => x.Id)
51+
.MapText("Name", x => x.Name);
52+
53+
using (var cts = new CancellationTokenSource(15))
4854
{
49-
Assert.Fail("Should Throw Exception of Type TaskCanceledException!");
55+
Assert.ThrowsAsync<TaskCanceledException>(async () =>
56+
await subject.SaveAllAsync(connection, FetchUserData(10), cts.Token), $"Should Throw Exception of Type {nameof(TaskCanceledException)}!");
5057
}
51-
finally
58+
59+
return Task.CompletedTask;
60+
}
61+
62+
[Test]
63+
public async Task Test_CanceledBulkInsertDoesNotThrowWhenCancelledAfterCompletion()
64+
{
65+
subject = new PostgreSQLCopyHelper<User>("sample", "TestUsers")
66+
.MapInteger("Id", x => x.Id)
67+
.MapText("Name", x => x.Name);
68+
69+
using (var cts = new CancellationTokenSource(50))
5270
{
53-
cancellationTokenSource.Dispose();
71+
var recordsSaved = await subject.SaveAllAsync(connection, FetchUserData(10), cts.Token);
72+
var result = connection.GetAll("sample", "\"TestUsers\"")
73+
.Cast<User>()
74+
.OrderBy(x => x.Id)
75+
.ToList();
76+
77+
Assert.AreEqual(2, recordsSaved);
78+
Assert.AreEqual(1, result.First().Id);
79+
Assert.AreEqual(2, result.Last().Id);
5480
}
5581
}
5682

57-
private static async IAsyncEnumerable<User> FetchUserData()
83+
private static async IAsyncEnumerable<User> FetchUserData(int delayMillis, [EnumeratorCancellation] CancellationToken cancellationToken = default)
5884
{
5985
for (var i = 1; i <= 2; i++)
6086
{
6187
// Simulate waiting for data to come through.
62-
await Task.Delay(10);
88+
await Task.Delay(delayMillis, cancellationToken);
6389
yield return new User
6490
{
6591
Id = i,
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
22

33
using System;
4+
using System.Threading;
45
using System.Threading.Tasks;
56
using Npgsql;
67

@@ -10,11 +11,11 @@ internal class ColumnDefinition<TEntity>
1011
{
1112
public string ColumnName { get; set; }
1213

13-
public Func<NpgsqlBinaryImporter, TEntity, Task> Write { get; set; }
14+
public Func<NpgsqlBinaryImporter, TEntity, CancellationToken, Task> WriteAsync { get; set; }
1415

1516
public override string ToString()
1617
{
17-
return $"ColumnDefinition (ColumnName = {ColumnName}, Serialize = {Write})";
18+
return $"ColumnDefinition (ColumnName = {ColumnName}, Serialize = {WriteAsync})";
1819
}
1920
}
2021
}

src/PostgreSQLCopyHelper/PostgreSQLCopyHelper.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,23 +92,23 @@ public PostgreSQLCopyHelper<TEntity> UsePostgresQuoting(bool enabled = true)
9292

9393
public PostgreSQLCopyHelper<TEntity> Map<TProperty>(string columnName, Func<TEntity, TProperty> propertyGetter, NpgsqlDbType type)
9494
{
95-
return AddColumn(columnName, (writer, entity) => writer.WriteAsync(propertyGetter(entity), type));
95+
return AddColumn(columnName, (writer, entity, token) => writer.WriteAsync(propertyGetter(entity), type, cancellationToken: token));
9696
}
9797

9898
public PostgreSQLCopyHelper<TEntity> MapNullable<TProperty>(string columnName, Func<TEntity, TProperty?> propertyGetter, NpgsqlDbType type)
9999
where TProperty : struct
100100
{
101-
return AddColumn(columnName, async (writer, entity) =>
101+
return AddColumn(columnName, async (writer, entity, token) =>
102102
{
103103
var val = propertyGetter(entity);
104104

105105
if (!val.HasValue)
106106
{
107-
await writer.WriteNullAsync();
107+
await writer.WriteNullAsync(cancellationToken: token);
108108
}
109109
else
110110
{
111-
await writer.WriteAsync(val.Value, type);
111+
await writer.WriteAsync(val.Value, type, cancellationToken: token);
112112
}
113113
});
114114
}
@@ -135,16 +135,16 @@ private async Task WriteToStreamAsync(NpgsqlBinaryImporter writer, TEntity entit
135135

136136
foreach (var columnDefinition in _columns)
137137
{
138-
await columnDefinition.Write(writer, entity);
138+
await columnDefinition.WriteAsync(writer, entity, cancellationToken);
139139
}
140140
}
141141

142-
private PostgreSQLCopyHelper<TEntity> AddColumn(string columnName, Func<NpgsqlBinaryImporter, TEntity, Task> action)
142+
private PostgreSQLCopyHelper<TEntity> AddColumn(string columnName, Func<NpgsqlBinaryImporter, TEntity, CancellationToken, Task> action)
143143
{
144144
_columns.Add(new ColumnDefinition<TEntity>
145145
{
146146
ColumnName = columnName,
147-
Write = action
147+
WriteAsync = action
148148
});
149149

150150
return this;

0 commit comments

Comments
 (0)