Skip to content

Commit 1eba235

Browse files
committed
Issue rsm-hcd#34 and rsm-hcd#17: Implemented CreateAsync and CreateDistinctAsync
1 parent b2ed58d commit 1eba235

10 files changed

+181
-20
lines changed

src/Conductors/RepositoryConductor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public partial class RepositoryConductor<T> : Conductor, IRepositoryConductor<T>
5555
/// <param name="items">List of items to be created</param>
5656
/// <param name="createdById">Id of user creating the items</param>
5757
/// <returns></returns>
58+
[Obsolete("This method is deprecated in favor of its async counter part", false)]
5859
public virtual IResult<List<T>> Create(IEnumerable<T> items, long? createdById = default(long?)) => _createConductor.Create(items, createdById);
5960

6061
/// <summary>
@@ -65,6 +66,7 @@ public partial class RepositoryConductor<T> : Conductor, IRepositoryConductor<T>
6566
/// <param name="property">Property used to remove duplicates</param>
6667
/// <param name="createdById">Id of user creating the items</param>
6768
/// <returns></returns>
69+
[Obsolete("This method is deprecated in favor of its async counter part", false)]
6870
public virtual IResult<List<T>> CreateDistinct<TKey>(IEnumerable<T> items, Func<T, TKey> property, long? createdById = null) => _createConductor.CreateDistinct(items, property, createdById);
6971

7072
#endregion Create

src/Conductors/RepositoryConductorAsync.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,13 @@ public Task<IResult<List<T>>> BulkCreateDistinctAsync<TKey>(IEnumerable<T> items
8383
/// <inheritdoc />
8484
public Task<IResult<T>> CreateAsync(T item, long? createdById = null, CancellationToken cancellationToken = default) =>
8585
_createConductor.CreateAsync(item, createdById, cancellationToken);
86+
87+
/// <inheritdoc />
88+
public Task<IResult<List<T>>> CreateAsync(IEnumerable<T> items, long? createdById = null, CancellationToken cancellationToken = default) =>
89+
_createConductor.CreateAsync(items, createdById, cancellationToken);
90+
91+
/// <inheritdoc />
92+
public Task<IResult<List<T>>> CreateDistinctAsync<TKey>(IEnumerable<T> items, System.Func<T, TKey> property, long? createdById = null, CancellationToken cancellationToken = default) =>
93+
_createConductor.CreateDistinctAsync(items, property, createdById, cancellationToken);
8694
}
8795
}

src/Conductors/RepositoryCreateConductor.cs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,15 @@ public IResult<List<T>> BulkCreateDistinct<TKey>(IEnumerable<T> items, Func<T, T
3737
return _repository.Create(item, createdById);
3838
}
3939

40-
/// <summary>
41-
/// Ability to create entities individually using a list
42-
/// </summary>
43-
/// <param name="items">List of items to be created</param>
44-
/// <param name="createdById">Id of user creating the items</param>
45-
/// <returns></returns>
40+
/// <inheritdoc />
41+
[Obsolete("This method is deprecated in favor of its async counter part", false)]
4642
public virtual IResult<List<T>> Create(IEnumerable<T> items, long? createdById = default(long?))
4743
{
4844
return _repository.Create(items, createdById);
4945
}
5046

51-
/// <summary>
52-
/// Ability to create entities individually without duplicates
53-
/// </summary>
54-
/// <typeparam name="TKey"></typeparam>
55-
/// <param name="items">List of items to create</param>
56-
/// <param name="property">Property used to remove duplicates</param>
57-
/// <param name="createdById">Id of user creating the items</param>
58-
/// <returns></returns>
47+
/// <inheritdoc />
48+
[Obsolete("This method is deprecated in favor of its async counter part", false)]
5949
public IResult<List<T>> CreateDistinct<TKey>(IEnumerable<T> items, Func<T, TKey> property, long? createdById = null)
6050
{
6151
return _repository.CreateDistinct(items, property, createdById);

src/Conductors/RepositoryCreateConductorAsync.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public int? CommandTimeout
2323
}
2424

2525
readonly IRepository<T> _repository;
26-
26+
const string ARGUMENT_EXCEPTION_MESSAGE = "An empty collection was provided";
2727

2828
/// <summary>
2929
/// Constructor
@@ -41,7 +41,7 @@ public virtual Task<IResult<List<T>>> BulkCreateAsync(IEnumerable<T> items, long
4141
{
4242
cancellationToken.ThrowIfCancellationRequested();
4343
if (items == null) throw new ArgumentNullException(nameof(items));
44-
if(!items.Any()) throw new ArgumentException("An empty collection was provided", nameof(items));
44+
if(!items.Any()) throw new ArgumentException(ARGUMENT_EXCEPTION_MESSAGE, nameof(items));
4545
return _repository.BulkCreateAsync(items, createdById);
4646
}
4747

@@ -50,7 +50,7 @@ public Task<IResult<List<T>>> BulkCreateDistinctAsync<TKey>(IEnumerable<T> items
5050
{
5151
cancellationToken.ThrowIfCancellationRequested();
5252
if (items == null) throw new ArgumentNullException(nameof(items));
53-
if (!items.Any()) throw new ArgumentException("An empty collection was provided", nameof(items));
53+
if (!items.Any()) throw new ArgumentException(ARGUMENT_EXCEPTION_MESSAGE, nameof(items));
5454
return _repository.BulkCreateDistinctAsync(items, property, createdById, cancellationToken);
5555
}
5656

@@ -61,5 +61,21 @@ public virtual Task<IResult<T>> CreateAsync(T item, long? createdById = null, Ca
6161
if (item == null) throw new ArgumentNullException(nameof(item));
6262
return _repository.CreateAsync(item, createdById);
6363
}
64+
65+
public Task<IResult<List<T>>> CreateAsync(IEnumerable<T> items, long? createdById = null, CancellationToken cancellationToken = default)
66+
{
67+
cancellationToken.ThrowIfCancellationRequested();
68+
if (items == null) throw new ArgumentNullException(nameof(items));
69+
if (!items.Any()) throw new ArgumentException(ARGUMENT_EXCEPTION_MESSAGE, nameof(items));
70+
return _repository.CreateAsync(items, createdById, cancellationToken);
71+
}
72+
73+
public Task<IResult<List<T>>> CreateDistinctAsync<TKey>(IEnumerable<T> items, Func<T, TKey> property, long? createdById = null, CancellationToken cancellationToken = default)
74+
{
75+
cancellationToken.ThrowIfCancellationRequested();
76+
if (items == null) throw new ArgumentNullException(nameof(items));
77+
if (!items.Any()) throw new ArgumentException(ARGUMENT_EXCEPTION_MESSAGE, nameof(items));
78+
return _repository.BulkCreateDistinctAsync(items, property, createdById, cancellationToken);
79+
}
6480
}
6581
}

src/Core/Interfaces/Conductors/IRepositoryCreateConductor.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,15 @@ public partial interface IRepositoryCreateConductor<T>
4848
/// <param name="createdById">Id of user creating the item</param>
4949
/// <returns></returns>
5050
[Obsolete("This method is deprecated in favor of its async counter part", false)]
51-
IResult<T> Create(T item, long? createdById = null);
51+
IResult<T> Create(T item, long? createdById = null);
52+
53+
/// <summary>
54+
/// Ability to create entities individually using a list
55+
/// </summary>
56+
/// <param name="items">List of items to be created</param>
57+
/// <param name="createdById">Id of user creating the items</param>
58+
/// <returns></returns>
59+
[Obsolete("This method is deprecated in favor of its async counter part", false)]
5260
IResult<List<T>> Create(IEnumerable<T> items, long? createdById = null);
5361

5462
/// <summary>
@@ -61,6 +69,7 @@ public partial interface IRepositoryCreateConductor<T>
6169
/// <param name="createdById">Id of the user creating the entity</param>
6270
/// <typeparam name="TKey"></typeparam>
6371
/// <returns></returns>
72+
[Obsolete("This method is deprecated in favor of its async counter part", false)]
6473
IResult<List<T>> CreateDistinct<TKey>(IEnumerable<T> items, Func<T, TKey> property, long? createdById = null);
6574

6675
#endregion Methods

src/Core/Interfaces/Conductors/IRepositoryCreateConductorAsync.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,28 @@ public partial interface IRepositoryCreateConductor<T>
3939
/// <param name="cancellationToken">a token allowing aborting of this request</param>
4040
/// <returns></returns>
4141
Task<IResult<T>> CreateAsync(T item, long? createdById = null, CancellationToken cancellationToken = default);
42+
43+
/// <summary>
44+
/// Ability to create entities individually using a list
45+
/// </summary>
46+
/// <param name="items">List of items to be created</param>
47+
/// <param name="createdById">Id of user creating the items</param>
48+
/// <param name="cancellationToken">a token allowing aborting of this request</param>
49+
/// <returns></returns>
50+
Task<IResult<List<T>>> CreateAsync(IEnumerable<T> items, long? createdById = null, CancellationToken cancellationToken = default);
51+
52+
/// <summary>
53+
/// Calls batched overload of Create() with a de-duped list of objects as determined by the
54+
/// property (or properties) of the object for the 'property' argument.
55+
/// NOTE: Batching is generally slower than bulking, but does not lock the table.
56+
/// </summary>
57+
/// <param name="items">List of items to attempt to create</param>
58+
/// <param name="property">Property or properties of the typed object to determine distinctness</param>
59+
/// <param name="createdById">Id of the user creating the entity</param>
60+
/// <param name="cancellationToken">a token allowing aborting of this request</param>
61+
/// <typeparam name="TKey"></typeparam>
62+
/// <returns></returns>
63+
Task<IResult<List<T>>> CreateDistinctAsync<TKey>(IEnumerable<T> items, Func<T, TKey> property, long? createdById = null, CancellationToken cancellationToken = default);
64+
4265
}
4366
}

src/Core/Interfaces/Data/IRepositoryAsync.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,28 @@ public partial interface IRepository<T>
3737
/// <param name="cancellationToken">a token allowing aborting of this request</param>
3838
/// <returns></returns>
3939
Task<IResult<T>> CreateAsync(T item, long? createdById = null, CancellationToken cancellationToken = default);
40+
41+
/// <summary>
42+
/// Ability to create entities individually using a list
43+
/// </summary>
44+
/// <param name="items">List of items to be created</param>
45+
/// <param name="createdById">Id of user creating the items</param>
46+
/// <param name="cancellationToken">a token allowing aborting of this request</param>
47+
/// <returns></returns>
48+
Task<IResult<List<T>>> CreateAsync(IEnumerable<T> items, long? createdById = null, CancellationToken cancellationToken = default);
49+
50+
/// <summary>
51+
/// Calls batched overload of Create() with a de-duped list of objects as determined by the
52+
/// property (or properties) of the object for the 'property' argument.
53+
/// NOTE: Batching is generally slower than bulking, but does not lock the table.
54+
/// </summary>
55+
/// <param name="items">List of items to attempt to create</param>
56+
/// <param name="property">Property or properties of the typed object to determine distinctness</param>
57+
/// <param name="createdById">Id of the user creating the entity</param>
58+
/// <param name="cancellationToken">a token allowing aborting of this request</param>
59+
/// <typeparam name="TKey"></typeparam>
60+
/// <returns></returns>
61+
Task<IResult<List<T>>> CreateDistinctAsync<TKey>(IEnumerable<T> items, Func<T, TKey> property, long? createdById = null, CancellationToken cancellationToken = default);
62+
4063
}
4164
}

test/Conductors.Tests/RepositoryConductorTests/BulkCreateDistinctAsyncShould.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using Xunit;
88
using Xunit.Abstractions;
99

10-
1110
namespace AndcultureCode.CSharp.Conductors.Tests.RepositoryConductorTests
1211
{
1312
public class BulkCreateDistinctAsyncShould : ProjectUnitTest

test/Conductors.Tests/RepositoryConductorTests/CreateAsyncShould.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,34 @@ public async Task Throw_Argument_Null_Exception_When_Given_Null_Input()
3434
// Arrange
3535
var repositoryMock = new IRepositoryMock<UserStub>();
3636
var respositoryConductor = SetupSut(repositoryMock);
37+
UserStub userStub = null;
3738

3839
// Act & Assert
39-
await Assert.ThrowsAsync<ArgumentNullException>(() => respositoryConductor.CreateAsync(null));
40+
await Assert.ThrowsAsync<ArgumentNullException>(() => respositoryConductor.CreateAsync(userStub));
41+
}
42+
43+
[Fact]
44+
public async Task Throw_Argument_Null_Exception_When_Given_Null_List_Input()
45+
{
46+
// Arrange
47+
var repositoryMock = new IRepositoryMock<UserStub>();
48+
var respositoryConductor = SetupSut(repositoryMock);
49+
IEnumerable<UserStub> userStub = null;
50+
51+
// Act & Assert
52+
await Assert.ThrowsAsync<ArgumentNullException>(() => respositoryConductor.CreateAsync(userStub));
53+
}
54+
55+
[Fact]
56+
public async Task Throw_Argument_Exception_When_Given_Empty_Input()
57+
{
58+
// Arrange
59+
var repositoryMock = new IRepositoryMock<UserStub>();
60+
var respositoryConductor = SetupSut(repositoryMock);
61+
IEnumerable<UserStub> userStubs = new List<UserStub>();
62+
63+
// Act & Assert
64+
await Assert.ThrowsAsync<ArgumentException>(() => respositoryConductor.CreateAsync(userStubs));
4065
}
4166

4267
[Fact]
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using AndcultureCode.CSharp.Core.Interfaces.Conductors;
6+
using AndcultureCode.CSharp.Testing.Models.Stubs;
7+
using Xunit;
8+
using Xunit.Abstractions;
9+
10+
namespace AndcultureCode.CSharp.Conductors.Tests.RepositoryConductorTests
11+
{
12+
public class CreateDistinctAsyncShould : ProjectUnitTest
13+
{
14+
public CreateDistinctAsyncShould(ITestOutputHelper output) : base(output)
15+
{
16+
}
17+
18+
private IRepositoryConductor<UserStub> SetupSut(
19+
IRepositoryMock<UserStub> repositoryMock
20+
)
21+
{
22+
var repositoryCreateConductor = new RepositoryCreateConductor<UserStub>(repositoryMock.Object);
23+
return new RepositoryConductor<UserStub>(
24+
createConductor: repositoryCreateConductor,
25+
deleteConductor: null,
26+
readConductor: null,
27+
updateConductor: null
28+
);
29+
}
30+
31+
[Fact]
32+
public async Task Throw_Argument_Null_Exception_When_Given_Null_Input()
33+
{
34+
// Arrange
35+
var repositoryMock = new IRepositoryMock<UserStub>();
36+
var respositoryConductor = SetupSut(repositoryMock);
37+
38+
// Act & Assert
39+
await Assert.ThrowsAsync<ArgumentNullException>(() => respositoryConductor.CreateDistinctAsync(null, (x) => x.Id));
40+
}
41+
42+
[Fact]
43+
public async Task Throw_Argument_Exception_When_Given_Empty_Input()
44+
{
45+
// Arrange
46+
var repositoryMock = new IRepositoryMock<UserStub>();
47+
var respositoryConductor = SetupSut(repositoryMock);
48+
49+
// Act & Assert
50+
await Assert.ThrowsAsync<ArgumentException>(() => respositoryConductor.CreateDistinctAsync(new List<UserStub>(), (x) => x.Id));
51+
}
52+
53+
[Fact]
54+
public async Task Throw_Stop_If_Canceled()
55+
{
56+
// Arrange
57+
var repositoryMock = new IRepositoryMock<UserStub>();
58+
var respositoryConductor = SetupSut(repositoryMock);
59+
var cancellationTokenSource = new CancellationTokenSource();
60+
var cancellationToken = cancellationTokenSource.Token;
61+
cancellationTokenSource.Cancel();
62+
// Act & Assert
63+
await Assert.ThrowsAsync<OperationCanceledException>(() => respositoryConductor.CreateDistinctAsync(new List<UserStub>(), (x) => x.Id, 5, cancellationToken));
64+
}
65+
}
66+
}

0 commit comments

Comments
 (0)