MongodbReader cancellation tokens and some unit tests

This commit is contained in:
Sean Garrett
2023-06-25 15:03:52 +01:00
parent 11ce19cb5c
commit dee1376a41
22 changed files with 1758 additions and 614 deletions
@@ -2,7 +2,6 @@ using System.Collections.Generic;
using System.Threading; using System.Threading;
using CoreUnitTests.Infrastructure; using CoreUnitTests.Infrastructure;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDbGenericRepository.DataAccess.Index; using MongoDbGenericRepository.DataAccess.Index;
using Moq; using Moq;
@@ -41,5 +40,4 @@ public class BaseIndexTests : GenericTestContext<MongoDbIndexHandler>
return (asyncCursor, indexManager); return (asyncCursor, indexManager);
} }
} }
@@ -19,7 +19,7 @@ public class CreateAscendingIndexAsyncTests : BaseIndexTests
private readonly Expression<Func<TestDocument, object>> fieldExpression = t => t.SomeContent2; private readonly Expression<Func<TestDocument, object>> fieldExpression = t => t.SomeContent2;
[Fact] [Fact]
public async Task WhenFieldExpression_ThenCreatesIndex() public async Task WithFieldExpression_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -42,7 +42,7 @@ public class CreateAscendingIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndOptions_ThenCreatesIndex() public async Task WithFieldExpressionAndOptions_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -68,7 +68,7 @@ public class CreateAscendingIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndPartitionKey_ThenCreatesIndex() public async Task WithFieldExpressionAndPartitionKey_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -95,7 +95,7 @@ public class CreateAscendingIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndCancellationToken_ThenCreatesIndex() public async Task WithFieldExpressionAndCancellationToken_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -121,7 +121,7 @@ public class CreateAscendingIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndOptionsAndPartitionKeyAndCancellationToken_ThenCreatesIndex() public async Task WithFieldExpressionAndOptionsAndPartitionKeyAndCancellationToken_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -29,7 +29,7 @@ public class CreateCombinedTextIndexAsyncTests : BaseIndexTests
=> this.testOutputHelper = testOutputHelper; => this.testOutputHelper = testOutputHelper;
[Fact] [Fact]
public async Task WhenFieldExpression_ThenCreatesIndex() public async Task WithFieldExpression_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -52,7 +52,7 @@ public class CreateCombinedTextIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndOptions_ThenCreatesIndex() public async Task WithFieldExpressionAndOptions_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -78,7 +78,7 @@ public class CreateCombinedTextIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndPartitionKey_ThenCreatesIndex() public async Task WithFieldExpressionAndPartitionKey_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -105,7 +105,7 @@ public class CreateCombinedTextIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndCancellationToken_ThenCreatesIndex() public async Task WithFieldExpressionAndCancellationToken_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -131,7 +131,7 @@ public class CreateCombinedTextIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndOptionsAndPartitionKeyAndCancellationToken_ThenCreatesIndex() public async Task WithFieldExpressionAndOptionsAndPartitionKeyAndCancellationToken_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -19,7 +19,7 @@ public class CreateDescendingIndexAsyncTests : BaseIndexTests
private readonly Expression<Func<TestDocument, object>> fieldExpression = t => t.SomeContent2; private readonly Expression<Func<TestDocument, object>> fieldExpression = t => t.SomeContent2;
[Fact] [Fact]
public async Task WhenFieldExpression_ThenCreatesIndex() public async Task WithFieldExpression_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -42,7 +42,7 @@ public class CreateDescendingIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndOptions_ThenCreatesIndex() public async Task WithFieldExpressionAndOptions_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -68,7 +68,7 @@ public class CreateDescendingIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndPartitionKey_ThenCreatesIndex() public async Task WithFieldExpressionAndPartitionKey_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -95,7 +95,7 @@ public class CreateDescendingIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndCancellationToken_ThenCreatesIndex() public async Task WithFieldExpressionAndCancellationToken_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -121,7 +121,7 @@ public class CreateDescendingIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndOptionsAndPartitionKeyAndCancellationToken_ThenCreatesIndex() public async Task WithFieldExpressionAndOptionsAndPartitionKeyAndCancellationToken_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -24,7 +24,7 @@ public class CreateHashedIndexAsyncTests : BaseIndexTests
=> this.testOutputHelper = testOutputHelper; => this.testOutputHelper = testOutputHelper;
[Fact] [Fact]
public async Task WhenFieldExpression_ThenCreatesIndex() public async Task WithFieldExpression_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -47,7 +47,7 @@ public class CreateHashedIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndOptions_ThenCreatesIndex() public async Task WithFieldExpressionAndOptions_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -73,7 +73,7 @@ public class CreateHashedIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndPartitionKey_ThenCreatesIndex() public async Task WithFieldExpressionAndPartitionKey_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -100,7 +100,7 @@ public class CreateHashedIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndCancellationToken_ThenCreatesIndex() public async Task WithFieldExpressionAndCancellationToken_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -126,7 +126,7 @@ public class CreateHashedIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndOptionsAndPartitionKeyAndCancellationToken_ThenCreatesIndex() public async Task WithFieldExpressionAndOptionsAndPartitionKeyAndCancellationToken_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -19,7 +19,7 @@ public class CreateTextIndexAsyncTests : BaseIndexTests
private readonly Expression<Func<TestDocument, object>> fieldExpression = t => t.SomeContent2; private readonly Expression<Func<TestDocument, object>> fieldExpression = t => t.SomeContent2;
[Fact] [Fact]
public async Task WhenFieldExpression_ThenCreatesIndex() public async Task WithFieldExpression_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -42,7 +42,7 @@ public class CreateTextIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndOptions_ThenCreatesIndex() public async Task WithFieldExpressionAndOptions_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -68,7 +68,7 @@ public class CreateTextIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndPartitionKey_ThenCreatesIndex() public async Task WithFieldExpressionAndPartitionKey_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -95,7 +95,7 @@ public class CreateTextIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndCancellationToken_ThenCreatesIndex() public async Task WithFieldExpressionAndCancellationToken_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -121,7 +121,7 @@ public class CreateTextIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenFieldExpressionAndOptionsAndPartitionKeyAndCancellationToken_ThenCreatesIndex() public async Task WithFieldExpressionAndOptionsAndPartitionKeyAndCancellationToken_CreatesIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -13,7 +13,7 @@ namespace CoreUnitTests.DataAccessTests.MongoDbIndexHandlerTests;
public class DropIndexAsyncTests : BaseIndexTests public class DropIndexAsyncTests : BaseIndexTests
{ {
[Fact] [Fact]
public async Task WhenIndexName_ThenDropsIndex() public async Task WithIndexName_DropsIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -30,7 +30,7 @@ public class DropIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenIndexNameAndPartitionKey_ThenDropsIndex() public async Task WithIndexNameAndPartitionKey_DropsIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -50,7 +50,7 @@ public class DropIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenIndexNameAndCancellationToken_ThenDropsIndex() public async Task WithIndexNameAndCancellationToken_DropsIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -69,7 +69,7 @@ public class DropIndexAsyncTests : BaseIndexTests
} }
[Fact] [Fact]
public async Task WhenIndexNameAndPartitionKeyAndCancellationToken_ThenDropsIndex() public async Task WithIndexNameAndPartitionKeyAndCancellationToken_DropsIndex()
{ {
// Arrange // Arrange
var expectedIndexName = Fixture.Create<string>(); var expectedIndexName = Fixture.Create<string>();
@@ -0,0 +1,69 @@
using System.Collections.Generic;
using System.Threading;
using CoreUnitTests.Infrastructure;
using MongoDB.Driver;
using MongoDbGenericRepository.DataAccess.Read;
using Moq;
namespace CoreUnitTests.DataAccessTests.MongoDbReaderTests;
public class BaseReaderTests : GenericTestContext<MongoDbReader>
{
protected Mock<IAsyncCursor<TDocument>> SetupSyncCursor<TDocument>(List<TDocument> documents)
{
var asyncCursor = MockOf<IAsyncCursor<TDocument>>();
var moveNextSequence = asyncCursor
.SetupSequence(x => x.MoveNext(It.IsAny<CancellationToken>()));
var currentSequence = asyncCursor
.SetupSequence(x => x.Current);
foreach (var projection in documents)
{
moveNextSequence.Returns(true);
currentSequence.Returns(new[] {projection});
}
moveNextSequence.Returns(false);
return asyncCursor;
}
protected Mock<IAsyncCursor<TDocument>> SetupAsyncCursor<TDocument>(List<TDocument> documents)
{
var asyncCursor = MockOf<IAsyncCursor<TDocument>>();
var moveNextSequence = asyncCursor
.SetupSequence(x => x.MoveNextAsync(It.IsAny<CancellationToken>()));
var currentSequence = asyncCursor
.SetupSequence(x => x.Current);
foreach (var projection in documents)
{
moveNextSequence.ReturnsAsync(true);
currentSequence.Returns(new[] {projection});
}
moveNextSequence.ReturnsAsync(false);
return asyncCursor;
}
protected static void SetupFindAsync<TDocument, TProjection>(Mock<IMongoCollection<TDocument>> collection, Mock<IAsyncCursor<TProjection>> asyncCursor) =>
collection
.Setup(
x => x.FindAsync(
It.IsAny<FilterDefinition<TDocument>>(),
It.IsAny<FindOptions<TDocument, TProjection>>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(asyncCursor.Object);
protected static void SetupFindSync<TDocument, TProjection>(Mock<IMongoCollection<TDocument>> collection, Mock<IAsyncCursor<TProjection>> asyncCursor) =>
collection
.Setup(
x => x.FindSync(
It.IsAny<FilterDefinition<TDocument>>(),
It.IsAny<FindOptions<TDocument, TProjection>>(),
It.IsAny<CancellationToken>()))
.Returns(asyncCursor.Object);
}
@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using CoreUnitTests.Infrastructure.Model;
using FluentAssertions;
using MongoDB.Driver;
using MongoDbGenericRepository;
using Moq;
using Xunit;
namespace CoreUnitTests.DataAccessTests.MongoDbReaderTests;
public class GetByIdAsyncTests : BaseReaderTests
{
[Fact]
public async Task WithId_GetsMatchingDocument()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var (context, cursor) = SetupAsyncGet(documents, collection);
// Act
var result = await Sut.GetByIdAsync<TestDocument, Guid>(documents[0].Id);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithIdAndCancellationToken_GetsMatchingDocument()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var token = new CancellationToken(true);
var (context, cursor) = SetupAsyncGet(documents, collection);
// Act
var result = await Sut.GetByIdAsync<TestDocument, Guid>(documents[0].Id, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithIdAndPartitionKey_GetsMatchingDocument()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var partitionKey = Fixture.Create<string>();
var (context, cursor) = SetupAsyncGet(documents, collection, partitionKey);
// Act
var result = await Sut.GetByIdAsync<TestDocument, Guid>(documents[0].Id, partitionKey);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithIdAndPartitionKeyAndCancellationToken_GetsMatchingDocument()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var partitionKey = Fixture.Create<string>();
var token = new CancellationToken(true);
var (context, cursor) = SetupAsyncGet(documents, collection, partitionKey);
// Act
var result = await Sut.GetByIdAsync<TestDocument, Guid>(documents[0].Id, partitionKey, token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
private (Mock<IMongoDbContext>, Mock<IAsyncCursor<TDocument>>) SetupAsyncGet<TDocument>(
List<TDocument> documents,
Mock<IMongoCollection<TDocument>> collection,
string partitionKey = null)
{
var asyncCursor = SetupAsyncCursor(documents);
SetupFindAsync(collection, asyncCursor);
var context = MockOf<IMongoDbContext>();
context
.Setup(x => x.GetCollection<TDocument>(partitionKey))
.Returns(collection.Object);
return (context, asyncCursor);
}
}
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using AutoFixture;
using CoreUnitTests.Infrastructure.Model;
using FluentAssertions;
using MongoDB.Driver;
using MongoDbGenericRepository;
using Moq;
using Xunit;
namespace CoreUnitTests.DataAccessTests.MongoDbReaderTests;
public class GetByIdTests : BaseReaderTests
{
[Fact]
public void WithId_GetsMatchingDocument()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var (context, cursor) = SetupAsyncGet(documents, collection);
// Act
var result = Sut.GetById<TestDocument, Guid>(documents[0].Id);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithIdAndCancellationToken_GetsMatchingDocument()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var token = new CancellationToken(true);
var (context, cursor) = SetupAsyncGet(documents, collection);
// Act
var result = Sut.GetById<TestDocument, Guid>(documents[0].Id, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithIdAndPartitionKey_GetsMatchingDocument()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var partitionKey = Fixture.Create<string>();
var (context, cursor) = SetupAsyncGet(documents, collection, partitionKey);
// Act
var result = Sut.GetById<TestDocument, Guid>(documents[0].Id, partitionKey);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithIdAndPartitionKeyAndCancellationToken_GetsMatchingDocument()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var partitionKey = Fixture.Create<string>();
var token = new CancellationToken(true);
var (context, cursor) = SetupAsyncGet(documents, collection, partitionKey);
// Act
var result = Sut.GetById<TestDocument, Guid>(documents[0].Id, partitionKey, token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
private (Mock<IMongoDbContext>, Mock<IAsyncCursor<TDocument>>) SetupAsyncGet<TDocument>(
List<TDocument> documents,
Mock<IMongoCollection<TDocument>> collection,
string partitionKey = null)
{
var asyncCursor = SetupSyncCursor(documents);
SetupFindSync(collection, asyncCursor);
var context = MockOf<IMongoDbContext>();
context
.Setup(x => x.GetCollection<TDocument>(partitionKey))
.Returns(collection.Object);
return (context, asyncCursor);
}
}
@@ -0,0 +1,283 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using CoreUnitTests.Infrastructure.Model;
using FluentAssertions;
using MongoDB.Driver;
using MongoDbGenericRepository;
using Moq;
using Xunit;
namespace CoreUnitTests.DataAccessTests.MongoDbReaderTests;
public class GetOneAsyncTests : BaseReaderTests
{
[Fact]
public async Task WithFilter_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
Expression<Func<TestDocument, bool>> filter = x => x.Id == documents[0].Id;
var (context, cursor) = SetupAsyncGet(documents, collection);
// Act
var result = await Sut.GetOneAsync<TestDocument, Guid>(filter);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithFilterAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var token = new CancellationToken(true);
Expression<Func<TestDocument, bool>> filter = x => x.Id == documents[0].Id;
var (context, cursor) = SetupAsyncGet(documents, collection);
// Act
var result = await Sut.GetOneAsync<TestDocument, Guid>(filter, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithFilterAndPartitionKey_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var partitionKey = Fixture.Create<string>();
Expression<Func<TestDocument, bool>> filter = x => x.Id == documents[0].Id;
var (context, cursor) = SetupAsyncGet(documents, collection, partitionKey);
// Act
var result = await Sut.GetOneAsync<TestDocument, Guid>(filter, partitionKey);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithFilterAndPartitionKeyAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var partitionKey = Fixture.Create<string>();
var token = new CancellationToken(true);
Expression<Func<TestDocument, bool>> filter = x => x.Id == documents[0].Id;
var (context, cursor) = SetupAsyncGet(documents, collection, partitionKey);
// Act
var result = await Sut.GetOneAsync<TestDocument, Guid>(filter, partitionKey, token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithCondition_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var (context, cursor) = SetupAsyncGet(documents, collection);
// Act
var result = await Sut.GetOneAsync<TestDocument, Guid>(condition);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithConditionAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var token = new CancellationToken(true);
var (context, cursor) = SetupAsyncGet(documents, collection);
// Act
var result = await Sut.GetOneAsync<TestDocument, Guid>(condition, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithConditionAndPartitionKey_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var partitionKey = Fixture.Create<string>();
var (context, cursor) = SetupAsyncGet(documents, collection, partitionKey);
// Act
var result = await Sut.GetOneAsync<TestDocument, Guid>(condition, partitionKey: partitionKey);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.MoveNextAsync(CancellationToken.None), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithConditionAndPartitionKeyAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var partitionKey = Fixture.Create<string>();
var token = new CancellationToken(true);
var (context, cursor) = SetupAsyncGet(documents, collection, partitionKey);
// Act
var result = await Sut.GetOneAsync<TestDocument, Guid>(condition, partitionKey: partitionKey, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithConditionAndFindOptions_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var options = Fixture
.Build<FindOptions>()
.Without(x => x.Comment)
.Without(x => x.Hint)
.Create();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var (context, cursor) = SetupAsyncGet(documents, collection);
// Act
var result = await Sut.GetOneAsync<TestDocument, Guid>(condition, options);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithConditionAndFindOptionsAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var options = Fixture
.Build<FindOptions>()
.Without(x => x.Comment)
.Without(x => x.Hint)
.Create();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var token = new CancellationToken(true);
var (context, cursor) = SetupAsyncGet(documents, collection);
// Act
var result = await Sut.GetOneAsync<TestDocument, Guid>(condition, options, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public async Task WithConditionAndFindOptionsAndPartitionKeyAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var options = Fixture
.Build<FindOptions>()
.Without(x => x.Comment)
.Without(x => x.Hint)
.Create();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var token = new CancellationToken(true);
var partitionKey = Fixture.Create<string>();
var (context, cursor) = SetupAsyncGet(documents, collection, partitionKey);
// Act
var result = await Sut.GetOneAsync<TestDocument, Guid>(condition, options, partitionKey, token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
private (Mock<IMongoDbContext>, Mock<IAsyncCursor<TDocument>>) SetupAsyncGet<TDocument>(
List<TDocument> documents,
Mock<IMongoCollection<TDocument>> collection,
string partitionKey = null)
{
var asyncCursor = SetupAsyncCursor(documents);
SetupFindAsync(collection, asyncCursor);
var context = MockOf<IMongoDbContext>();
context
.Setup(x => x.GetCollection<TDocument>(partitionKey))
.Returns(collection.Object);
return (context, asyncCursor);
}
}
@@ -0,0 +1,282 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using AutoFixture;
using CoreUnitTests.Infrastructure.Model;
using FluentAssertions;
using MongoDB.Driver;
using MongoDbGenericRepository;
using Moq;
using Xunit;
namespace CoreUnitTests.DataAccessTests.MongoDbReaderTests;
public class GetOneTests : BaseReaderTests
{
[Fact]
public void WithFilter_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
Expression<Func<TestDocument, bool>> filter = x => x.Id == documents[0].Id;
var (context, cursor) = SetupSyncGet(documents, collection);
// Act
var result = Sut.GetOne<TestDocument, Guid>(filter);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.MoveNext(CancellationToken.None), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithFilterAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var token = new CancellationToken(true);
Expression<Func<TestDocument, bool>> filter = x => x.Id == documents[0].Id;
var (context, cursor) = SetupSyncGet(documents, collection);
// Act
var result = Sut.GetOne<TestDocument, Guid>(filter, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithFilterAndPartitionKey_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var partitionKey = Fixture.Create<string>();
Expression<Func<TestDocument, bool>> filter = x => x.Id == documents[0].Id;
var (context, cursor) = SetupSyncGet(documents, collection, partitionKey);
// Act
var result = Sut.GetOne<TestDocument, Guid>(filter, partitionKey);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithFilterAndPartitionKeyAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var partitionKey = Fixture.Create<string>();
var token = new CancellationToken(true);
Expression<Func<TestDocument, bool>> filter = x => x.Id == documents[0].Id;
var (context, cursor) = SetupSyncGet(documents, collection, partitionKey);
// Act
var result = Sut.GetOne<TestDocument, Guid>(filter, partitionKey, token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithCondition_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var (context, cursor) = SetupSyncGet(documents, collection);
// Act
var result = Sut.GetOne<TestDocument, Guid>(condition);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithConditionAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var token = new CancellationToken(true);
var (context, cursor) = SetupSyncGet(documents, collection);
// Act
var result = Sut.GetOne<TestDocument, Guid>(condition, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithConditionAndPartitionKey_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var partitionKey = Fixture.Create<string>();
var (context, cursor) = SetupSyncGet(documents, collection, partitionKey);
// Act
var result = Sut.GetOne<TestDocument, Guid>(condition, partitionKey: partitionKey);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.MoveNext(CancellationToken.None), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithConditionAndPartitionKeyAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var partitionKey = Fixture.Create<string>();
var token = new CancellationToken(true);
var (context, cursor) = SetupSyncGet(documents, collection, partitionKey);
// Act
var result = Sut.GetOne<TestDocument, Guid>(condition, partitionKey: partitionKey, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithConditionAndFindOptions_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var options = Fixture
.Build<FindOptions>()
.Without(x => x.Comment)
.Without(x => x.Hint)
.Create();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var (context, cursor) = SetupSyncGet(documents, collection);
// Act
var result = Sut.GetOne<TestDocument, Guid>(condition, options);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithConditionAndFindOptionsAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var options = Fixture
.Build<FindOptions>()
.Without(x => x.Comment)
.Without(x => x.Hint)
.Create();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var token = new CancellationToken(true);
var (context, cursor) = SetupSyncGet(documents, collection);
// Act
var result = Sut.GetOne<TestDocument, Guid>(condition, options, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
[Fact]
public void WithConditionAndFindOptionsAndPartitionKeyAndCancellationToken_GetsMatchingDocuments()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var documents = Fixture.CreateMany<TestDocument>().ToList();
var options = Fixture
.Build<FindOptions>()
.Without(x => x.Comment)
.Without(x => x.Hint)
.Create();
var condition = Builders<TestDocument>.Filter.Eq("Id", documents[0].Id);
var token = new CancellationToken(true);
var partitionKey = Fixture.Create<string>();
var (context, cursor) = SetupSyncGet(documents, collection, partitionKey);
// Act
var result = Sut.GetOne<TestDocument, Guid>(condition, options, partitionKey, token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(documents[0]);
}
private (Mock<IMongoDbContext>, Mock<IAsyncCursor<TDocument>>) SetupSyncGet<TDocument>(
List<TDocument> documents,
Mock<IMongoCollection<TDocument>> collection,
string partitionKey = null)
{
var asyncCursor = SetupSyncCursor(documents);
SetupFindSync(collection, asyncCursor);
var context = MockOf<IMongoDbContext>();
context
.Setup(x => x.GetCollection<TDocument>(partitionKey))
.Returns(collection.Object);
return (context, asyncCursor);
}
}
@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using CoreUnitTests.Infrastructure.Model;
using FluentAssertions;
using MongoDB.Driver;
using MongoDbGenericRepository;
using Moq;
using Xunit;
namespace CoreUnitTests.DataAccessTests.MongoDbReaderTests;
public class ProjectManyAsyncTests : BaseReaderTests
{
private readonly Expression<Func<TestDocument, bool>> filter = t => string.IsNullOrWhiteSpace(t.SomeContent2);
private readonly Expression<Func<TestDocument, TestProjection>>
projectionExpression = t => new TestProjection {TestDocumentId = t.Id, NestedData = t.Nested.SomeDate};
[Fact]
public async Task WithFilterAndProjection_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var (context, cursor) = SetupAsyncProjection(projections, collection);
// Act
var result = await Sut.ProjectManyAsync<TestDocument, TestProjection, Guid>(filter, projectionExpression);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.MoveNextAsync(CancellationToken.None), Times.AtLeast(1));
result.Should().NotBeNull();
result.Should().OnlyContain(x => projections.Contains(x));
}
[Fact]
public async Task WithFilterAndProjectionAndCancellationToken_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var token = new CancellationToken(false);
var (context, cursor) = SetupAsyncProjection(projections, collection);
// Act
var result = await Sut.ProjectManyAsync<TestDocument, TestProjection, Guid>(filter, projectionExpression, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.AtLeast(1));
result.Should().NotBeNull();
result.Should().OnlyContain(x => projections.Contains(x));
}
[Fact]
public async Task WithFilterAndProjectionAndPartitionKey_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var partitionKey = Fixture.Create<string>();
var (context, cursor) = SetupAsyncProjection(projections, collection, partitionKey);
// Act
var result = await Sut.ProjectManyAsync<TestDocument, TestProjection, Guid>(filter, projectionExpression, partitionKey);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.MoveNextAsync(CancellationToken.None), Times.AtLeast(1));
result.Should().NotBeNull();
result.Should().OnlyContain(x => projections.Contains(x));
}
[Fact]
public async Task WithFilterAndProjectionAndPartitionKeyAndCancellationToken_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var partitionKey = Fixture.Create<string>();
var token = new CancellationToken(false);
var (context, cursor) = SetupAsyncProjection(projections, collection, partitionKey);
// Act
var result = await Sut.ProjectManyAsync<TestDocument, TestProjection, Guid>(filter, projectionExpression, partitionKey, token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.AtLeast(1));
result.Should().NotBeNull();
result.Should().OnlyContain(x => projections.Contains(x));
}
private (Mock<IMongoDbContext>, Mock<IAsyncCursor<TProjection>>) SetupAsyncProjection<TDocument, TProjection>(
List<TProjection> projections,
Mock<IMongoCollection<TDocument>> collection,
string partitionKey = null)
{
var asyncCursor = SetupAsyncCursor(projections);
collection
.Setup(
x => x.FindAsync(
It.IsAny<FilterDefinition<TDocument>>(),
It.IsAny<FindOptions<TDocument, TProjection>>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(asyncCursor.Object);
var context = MockOf<IMongoDbContext>();
context
.Setup(x => x.GetCollection<TDocument>(partitionKey))
.Returns(collection.Object);
return (context, asyncCursor);
}
}
@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using CoreUnitTests.Infrastructure.Model;
using FluentAssertions;
using MongoDB.Driver;
using MongoDbGenericRepository;
using Moq;
using Xunit;
namespace CoreUnitTests.DataAccessTests.MongoDbReaderTests;
public class ProjectManyTests : BaseReaderTests
{
private readonly Expression<Func<TestDocument, bool>> filter = t => string.IsNullOrWhiteSpace(t.SomeContent2);
private readonly Expression<Func<TestDocument, TestProjection>>
projectionExpression = t => new TestProjection {TestDocumentId = t.Id, NestedData = t.Nested.SomeDate};
[Fact]
public void WithFilterAndProjection_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var (context, cursor) = SetupAsyncProjection(projections, collection);
// Act
var result = Sut.ProjectMany<TestDocument, TestProjection, Guid>(filter, projectionExpression);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.MoveNext(CancellationToken.None), Times.AtLeast(1));
result.Should().NotBeNull();
result.Should().OnlyContain(x => projections.Contains(x));
}
[Fact]
public void WithFilterAndProjectionAndCancellationToken_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var token = new CancellationToken(false);
var (context, cursor) = SetupAsyncProjection(projections, collection);
// Act
var result = Sut.ProjectMany<TestDocument, TestProjection, Guid>(filter, projectionExpression, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.AtLeast(1));
result.Should().NotBeNull();
result.Should().OnlyContain(x => projections.Contains(x));
}
[Fact]
public void WithFilterAndProjectionAndPartitionKey_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var partitionKey = Fixture.Create<string>();
var (context, cursor) = SetupAsyncProjection(projections, collection, partitionKey);
// Act
var result = Sut.ProjectMany<TestDocument, TestProjection, Guid>(filter, projectionExpression, partitionKey);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.MoveNext(CancellationToken.None), Times.AtLeast(1));
result.Should().NotBeNull();
result.Should().OnlyContain(x => projections.Contains(x));
}
[Fact]
public void WithFilterAndProjectionAndPartitionKeyAndCancellationToken_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var partitionKey = Fixture.Create<string>();
var token = new CancellationToken(false);
var (context, cursor) = SetupAsyncProjection(projections, collection, partitionKey);
// Act
var result = Sut.ProjectMany<TestDocument, TestProjection, Guid>(filter, projectionExpression, partitionKey, token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.AtLeast(projections.Count));
result.Should().NotBeNull();
result.Should().OnlyContain(x => projections.Contains(x));
}
private (Mock<IMongoDbContext>, Mock<IAsyncCursor<TProjection>>) SetupAsyncProjection<TDocument, TProjection>(
List<TProjection> projections,
Mock<IMongoCollection<TDocument>> collection,
string partitionKey = null)
{
var asyncCursor = SetupSyncCursor(projections);
SetupFindSync(collection, asyncCursor);
var context = MockOf<IMongoDbContext>();
context
.Setup(x => x.GetCollection<TDocument>(partitionKey))
.Returns(collection.Object);
return (context, asyncCursor);
}
}
@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using CoreUnitTests.Infrastructure.Model;
using FluentAssertions;
using MongoDB.Driver;
using MongoDbGenericRepository;
using Moq;
using Xunit;
namespace CoreUnitTests.DataAccessTests.MongoDbReaderTests;
public class ProjectOneAsyncTests : BaseReaderTests
{
private readonly Expression<Func<TestDocument, bool>> filter = t => string.IsNullOrWhiteSpace(t.SomeContent2);
private readonly Expression<Func<TestDocument, TestProjection>>
projectionExpression = t => new TestProjection {TestDocumentId = t.Id, NestedData = t.Nested.SomeDate};
[Fact]
public async Task WithFilterAndProjection_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var (context, cursor) = SetupAsyncProjection(projections, collection);
// Act
var result = await Sut.ProjectOneAsync<TestDocument, TestProjection, Guid>(filter, projectionExpression);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(projections[0]);
}
[Fact]
public async Task WithFilterAndProjectionAndCancellationToken_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var token = new CancellationToken(true);
var (context, cursor) = SetupAsyncProjection(projections, collection);
// Act
var result = await Sut.ProjectOneAsync<TestDocument, TestProjection, Guid>(filter, projectionExpression, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(projections[0]);
}
[Fact]
public async Task WithFilterAndProjectionAndPartitionKey_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var partitionKey = Fixture.Create<string>();
var (context, cursor) = SetupAsyncProjection(projections, collection, partitionKey);
// Act
var result = await Sut.ProjectOneAsync<TestDocument, TestProjection, Guid>(filter, projectionExpression, partitionKey);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(projections[0]);
}
[Fact]
public async Task WithFilterAndProjectionAndPartitionKeyAndCancellationToken_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var partitionKey = Fixture.Create<string>();
var token = new CancellationToken(true);
var (context, cursor) = SetupAsyncProjection(projections, collection, partitionKey);
// Act
var result = await Sut.ProjectOneAsync<TestDocument, TestProjection, Guid>(filter, projectionExpression, partitionKey, token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNextAsync(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(projections[0]);
}
private (Mock<IMongoDbContext>, Mock<IAsyncCursor<TProjection>>) SetupAsyncProjection<TDocument, TProjection>(
List<TProjection> projections,
Mock<IMongoCollection<TDocument>> collection,
string partitionKey = null)
{
var asyncCursor = SetupAsyncCursor(projections);
SetupFindAsync(collection, asyncCursor);
var context = MockOf<IMongoDbContext>();
context
.Setup(x => x.GetCollection<TDocument>(partitionKey))
.Returns(collection.Object);
return (context, asyncCursor);
}
}
@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using CoreUnitTests.Infrastructure.Model;
using FluentAssertions;
using MongoDB.Driver;
using MongoDbGenericRepository;
using Moq;
using Xunit;
namespace CoreUnitTests.DataAccessTests.MongoDbReaderTests;
public class ProjectOneTests : BaseReaderTests
{
private readonly Expression<Func<TestDocument, bool>> filter = t => string.IsNullOrWhiteSpace(t.SomeContent2);
private readonly Expression<Func<TestDocument, TestProjection>>
projectionExpression = t => new TestProjection {TestDocumentId = t.Id, NestedData = t.Nested.SomeDate};
[Fact]
public void WithFilterAndProjection_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var (context, cursor) = SetupProjection(projections, collection);
// Act
var result = Sut.ProjectOne<TestDocument, TestProjection, Guid>(filter, projectionExpression);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(projections[0]);
}
[Fact]
public void WithFilterAndProjectionAndCancellationToken_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var token = new CancellationToken(true);
var (context, cursor) = SetupProjection(projections, collection);
// Act
var result = Sut.ProjectOne<TestDocument, TestProjection, Guid>(filter, projectionExpression, cancellationToken: token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(null), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(projections[0]);
}
[Fact]
public void WithFilterAndProjectionAndPartitionKey_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var partitionKey = Fixture.Create<string>();
var (context, cursor) = SetupProjection(projections, collection, partitionKey);
// Act
var result = Sut.ProjectOne<TestDocument, TestProjection, Guid>(filter, projectionExpression, partitionKey);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(CancellationToken.None), Times.Once);
result.Should().NotBeNull();
result.Should().Be(projections[0]);
}
[Fact]
public void WithFilterAndProjectionAndPartitionKeyAndCancellationToken_Projects()
{
// Arrange
var collection = MockOf<IMongoCollection<TestDocument>>();
var projections = Fixture.CreateMany<TestProjection>().ToList();
var partitionKey = Fixture.Create<string>();
var token = new CancellationToken(true);
var (context, cursor) = SetupProjection(projections, collection, partitionKey);
// Act
var result = Sut.ProjectOne<TestDocument, TestProjection, Guid>(filter, projectionExpression, partitionKey, token);
// Assert
context.Verify(x => x.GetCollection<TestDocument>(partitionKey), Times.Once);
cursor.Verify(x => x.Current, Times.Once);
cursor.Verify(x => x.MoveNext(token), Times.Once);
result.Should().NotBeNull();
result.Should().Be(projections[0]);
}
private (Mock<IMongoDbContext>, Mock<IAsyncCursor<TProjection>>) SetupProjection<TDocument, TProjection>(
List<TProjection> projections,
Mock<IMongoCollection<TDocument>> collection,
string partitionKey = null)
{
var asyncCursor = SetupSyncCursor(projections);
SetupFindSync(collection, asyncCursor);
var context = MockOf<IMongoDbContext>();
context
.Setup(x => x.GetCollection<TDocument>(partitionKey))
.Returns(collection.Object);
return (context, asyncCursor);
}
}
@@ -0,0 +1,10 @@
using System;
namespace CoreUnitTests.Infrastructure.Model;
public class TestProjection
{
public Guid TestDocumentId { get; set; }
public DateTime NestedData { get; set; }
}
@@ -25,7 +25,7 @@ namespace MongoDbGenericRepository
IMongoCollection<TDocument> GetCollection<TDocument>(string partitionKey = null); IMongoCollection<TDocument> GetCollection<TDocument>(string partitionKey = null);
/// <summary> /// <summary>
/// Drops a collection having a partitionkey, use very carefully. /// Drops a collection having a partitionKey, use very carefully.
/// </summary> /// </summary>
/// <typeparam name="TDocument"></typeparam> /// <typeparam name="TDocument"></typeparam>
void DropCollection<TDocument>(string partitionKey = null); void DropCollection<TDocument>(string partitionKey = null);
@@ -43,7 +43,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <param name="filter">A LINQ expression filter.</param> /// <param name="filter">A LINQ expression filter.</param>
/// <param name="projection">The projection expression.</param> /// <param name="projection">The projection expression.</param>
/// <param name="partitionKey">An optional partition key.</param> /// <param name="partitionKey">An optional partition key.</param>
TProjection ProjectOne<TDocument, TProjection, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TProjection>> projection, string partitionKey = null) TProjection ProjectOne<TDocument, TProjection, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TProjection>> projection, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
where TProjection : class; where TProjection : class;
@@ -76,7 +76,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <param name="filter">The document filter.</param> /// <param name="filter">The document filter.</param>
/// <param name="projection">The projection expression.</param> /// <param name="projection">The projection expression.</param>
/// <param name="partitionKey">An optional partition key.</param> /// <param name="partitionKey">An optional partition key.</param>
List<TProjection> ProjectMany<TDocument, TProjection, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TProjection>> projection, string partitionKey = null) List<TProjection> ProjectMany<TDocument, TProjection, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TProjection>> projection, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
where TProjection : class; where TProjection : class;
@@ -95,7 +95,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
List<TProjection> GroupBy<TDocument, TGroupKey, TProjection, TKey>( List<TProjection> GroupBy<TDocument, TGroupKey, TProjection, TKey>(
Expression<Func<TDocument, TGroupKey>> groupingCriteria, Expression<Func<TDocument, TGroupKey>> groupingCriteria,
Expression<Func<IGrouping<TGroupKey, TDocument>, TProjection>> groupProjection, Expression<Func<IGrouping<TGroupKey, TDocument>, TProjection>> groupProjection,
string partitionKey = null) string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
where TProjection : class, new(); where TProjection : class, new();
@@ -116,7 +116,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, TGroupKey>> selector, Expression<Func<TDocument, TGroupKey>> selector,
Expression<Func<IGrouping<TGroupKey, TDocument>, TProjection>> projection, Expression<Func<IGrouping<TGroupKey, TDocument>, TProjection>> projection,
string partitionKey = null) string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
where TProjection : class, new(); where TProjection : class, new();
@@ -207,7 +207,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> /// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="id">The Id of the document you want to get.</param> /// <param name="id">The Id of the document you want to get.</param>
/// <param name="partitionKey">An optional partition key.</param> /// <param name="partitionKey">An optional partition key.</param>
TDocument GetById<TDocument, TKey>(TKey id, string partitionKey = null) TDocument GetById<TDocument, TKey>(TKey id, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -246,7 +246,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <param name="condition">A mongodb filter definition.</param> /// <param name="condition">A mongodb filter definition.</param>
/// <param name="findOption">A mongodb filter option.</param> /// <param name="findOption">A mongodb filter option.</param>
/// <param name="partitionKey">An optional partition key.</param> /// <param name="partitionKey">An optional partition key.</param>
TDocument GetOne<TDocument, TKey>(FilterDefinition<TDocument> condition, FindOptions findOption = null, string partitionKey = null) TDocument GetOne<TDocument, TKey>(FilterDefinition<TDocument> condition, FindOptions findOption = null, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -257,7 +257,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> /// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="filter">A LINQ expression filter.</param> /// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partition key.</param> /// <param name="partitionKey">An optional partition key.</param>
TDocument GetOne<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null) TDocument GetOne<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -307,7 +307,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <param name="countOption">A mongodb counting option.</param> /// <param name="countOption">A mongodb counting option.</param>
/// <param name="partitionKey">An optional partition key.</param> /// <param name="partitionKey">An optional partition key.</param>
bool Any<TDocument, TKey>(FilterDefinition<TDocument> condition, CountOptions countOption = null, bool Any<TDocument, TKey>(FilterDefinition<TDocument> condition, CountOptions countOption = null,
string partitionKey = null) string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -318,7 +318,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> /// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="filter">A LINQ expression filter.</param> /// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partition key.</param> /// <param name="partitionKey">An optional partition key.</param>
bool Any<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null) bool Any<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -357,7 +357,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <param name="findOption">A mongodb filter option.</param> /// <param name="findOption">A mongodb filter option.</param>
/// <param name="partitionKey">An optional partition key.</param> /// <param name="partitionKey">An optional partition key.</param>
List<TDocument> GetAll<TDocument, TKey>(FilterDefinition<TDocument> condition, FindOptions findOption = null, List<TDocument> GetAll<TDocument, TKey>(FilterDefinition<TDocument> condition, FindOptions findOption = null,
string partitionKey = null) string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -368,7 +368,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> /// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="filter">A LINQ expression filter.</param> /// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partition key.</param> /// <param name="partitionKey">An optional partition key.</param>
List<TDocument> GetAll<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null) List<TDocument> GetAll<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -407,7 +407,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <param name="countOption">A mongodb counting option.</param> /// <param name="countOption">A mongodb counting option.</param>
/// <param name="partitionKey">An optional partitionKey</param> /// <param name="partitionKey">An optional partitionKey</param>
long Count<TDocument, TKey>(FilterDefinition<TDocument> condition, CountOptions countOption = null, long Count<TDocument, TKey>(FilterDefinition<TDocument> condition, CountOptions countOption = null,
string partitionKey = null) string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -418,7 +418,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> /// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="filter">A LINQ expression filter.</param> /// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partitionKey</param> /// <param name="partitionKey">An optional partitionKey</param>
long Count<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null) long Count<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -443,7 +443,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <param name="filter">A LINQ expression filter.</param> /// <param name="filter">A LINQ expression filter.</param>
/// <param name="maxValueSelector">A property selector to order by descending.</param> /// <param name="maxValueSelector">A property selector to order by descending.</param>
/// <param name="partitionKey">An optional partitionKey.</param> /// <param name="partitionKey">An optional partitionKey.</param>
TDocument GetByMax<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, object>> maxValueSelector, string partitionKey = null) TDocument GetByMax<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, object>> maxValueSelector, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -468,7 +468,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <param name="filter">A LINQ expression filter.</param> /// <param name="filter">A LINQ expression filter.</param>
/// <param name="minValueSelector">A property selector to order by ascending.</param> /// <param name="minValueSelector">A property selector to order by ascending.</param>
/// <param name="partitionKey">An optional partitionKey.</param> /// <param name="partitionKey">An optional partitionKey.</param>
TDocument GetByMin<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, object>> minValueSelector, string partitionKey = null) TDocument GetByMin<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, object>> minValueSelector, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -495,7 +495,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <param name="filter">A LINQ expression filter.</param> /// <param name="filter">A LINQ expression filter.</param>
/// <param name="maxValueSelector">A property selector to order by ascending.</param> /// <param name="maxValueSelector">A property selector to order by ascending.</param>
/// <param name="partitionKey">An optional partitionKey.</param> /// <param name="partitionKey">An optional partitionKey.</param>
TValue GetMaxValue<TDocument, TKey, TValue>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TValue>> maxValueSelector, string partitionKey = null) TValue GetMaxValue<TDocument, TKey, TValue>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TValue>> maxValueSelector, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -522,7 +522,7 @@ namespace MongoDbGenericRepository.DataAccess.Read
/// <param name="filter">A LINQ expression filter.</param> /// <param name="filter">A LINQ expression filter.</param>
/// <param name="minValueSelector">A property selector to order by ascending.</param> /// <param name="minValueSelector">A property selector to order by ascending.</param>
/// <param name="partitionKey">An optional partition key.</param> /// <param name="partitionKey">An optional partition key.</param>
TValue GetMinValue<TDocument, TKey, TValue>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TValue>> minValueSelector, string partitionKey = null) TValue GetMinValue<TDocument, TKey, TValue>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TValue>> minValueSelector, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>; where TKey : IEquatable<TKey>;
@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDbGenericRepository.Models;
namespace MongoDbGenericRepository.DataAccess.Read
{
public partial class MongoDbReader
{
/// <inheritdoc />
public virtual List<TProjection> GroupBy<TDocument, TGroupKey, TProjection, TKey>(
Expression<Func<TDocument, TGroupKey>> groupingCriteria,
Expression<Func<IGrouping<TGroupKey, TDocument>, TProjection>> groupProjection,
string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
where TProjection : class, new()
{
return HandlePartitioned<TDocument, TKey>(partitionKey)
.Aggregate()
.Group(groupingCriteria, groupProjection)
.ToList(cancellationToken:cancellationToken);
}
/// <inheritdoc />
public virtual List<TProjection> GroupBy<TDocument, TGroupKey, TProjection, TKey>(
Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, TGroupKey>> selector,
Expression<Func<IGrouping<TGroupKey, TDocument>, TProjection>> projection,
string partitionKey = null,
CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
where TProjection : class, new()
{
var collection = HandlePartitioned<TDocument, TKey>(partitionKey);
return collection.Aggregate()
.Match(Builders<TDocument>.Filter.Where(filter))
.Group(selector, projection)
.ToList(cancellationToken);
}
/// <inheritdoc />
public virtual async Task<List<TProjection>> GroupByAsync<TDocument, TGroupKey, TProjection, TKey>(
Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, TGroupKey>> selector,
Expression<Func<IGrouping<TGroupKey, TDocument>, TProjection>> projection,
string partitionKey = null,
CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
where TProjection : class, new()
{
var collection = HandlePartitioned<TDocument, TKey>(partitionKey);
return await collection.Aggregate()
.Match(Builders<TDocument>.Filter.Where(filter))
.Group(selector, projection)
.ToListAsync(cancellationToken);
}
/// <inheritdoc />
public virtual async Task<List<TDocument>> GetSortedPaginatedAsync<TDocument, TKey>(
Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, object>> sortSelector,
bool ascending = true,
int skipNumber = 0,
int takeNumber = 50,
string partitionKey = null,
CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
{
var sorting = ascending
? Builders<TDocument>.Sort.Ascending(sortSelector)
: Builders<TDocument>.Sort.Descending(sortSelector);
return await HandlePartitioned<TDocument, TKey>(partitionKey)
.Find(filter)
.Sort(sorting)
.Skip(skipNumber)
.Limit(takeNumber)
.ToListAsync(cancellationToken);
}
/// <inheritdoc />
public virtual async Task<List<TDocument>> GetSortedPaginatedAsync<TDocument, TKey>(
Expression<Func<TDocument, bool>> filter,
SortDefinition<TDocument> sortDefinition,
int skipNumber = 0,
int takeNumber = 50,
string partitionKey = null,
CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
{
return await HandlePartitioned<TDocument, TKey>(partitionKey)
.Find(filter)
.Sort(sortDefinition)
.Skip(skipNumber)
.Limit(takeNumber)
.ToListAsync(cancellationToken);
}
}
}
@@ -1,39 +1,32 @@
using MongoDB.Driver; using System;
using MongoDB.Driver.Linq;
using MongoDbGenericRepository.DataAccess.Base;
using MongoDbGenericRepository.Models;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using MongoDbGenericRepository.DataAccess.Base;
using MongoDbGenericRepository.Models;
namespace MongoDbGenericRepository.DataAccess.Read namespace MongoDbGenericRepository.DataAccess.Read
{ {
/// <summary> /// <summary>
/// A class to read MongoDb document. /// A class to read MongoDb document.
/// </summary> /// </summary>
public partial class MongoDbReader : DataAccessBase public partial class MongoDbReader : DataAccessBase, IMongoDbReader
{ {
/// <summary> /// <summary>
/// The construct of the MongoDbReader class. /// The construct of the MongoDbReader class.
/// </summary> /// </summary>
/// <param name="mongoDbContext">A <see cref="IMongoDbContext"/> instance.</param> /// <param name="mongoDbContext">A <see cref="IMongoDbContext" /> instance.</param>
public MongoDbReader(IMongoDbContext mongoDbContext) : base(mongoDbContext) public MongoDbReader(IMongoDbContext mongoDbContext) : base(mongoDbContext)
{ {
} }
#region Read TKey #region Read TKey
/// <summary> /// <inheritdoc />
/// Asynchronously returns one document given its id.
/// </summary>
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="id">The Id of the document you want to get.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<TDocument> GetByIdAsync<TDocument, TKey>(TKey id, string partitionKey = null, CancellationToken cancellationToken = default) public virtual async Task<TDocument> GetByIdAsync<TDocument, TKey>(TKey id, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
@@ -42,31 +35,19 @@ namespace MongoDbGenericRepository.DataAccess.Read
return await HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).FirstOrDefaultAsync(cancellationToken); return await HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Returns one document given its id. public virtual TDocument GetById<TDocument, TKey>(TKey id, string partitionKey = null, CancellationToken cancellationToken = default)
/// </summary>
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="id">The Id of the document you want to get.</param>
/// <param name="partitionKey">An optional partition key.</param>
public virtual TDocument GetById<TDocument, TKey>(TKey id, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
var filter = Builders<TDocument>.Filter.Eq("Id", id); var filter = Builders<TDocument>.Filter.Eq("Id", id);
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).FirstOrDefault(); return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).FirstOrDefault(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Asynchronously returns one document given filter definition. public virtual Task<TDocument> GetOneAsync<TDocument, TKey>(
/// </summary> FilterDefinition<TDocument> condition,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> FindOptions findOption = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="condition">A mongodb filter definition.</param>
/// <param name="findOption">A mongodb filter option.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual Task<TDocument> GetOneAsync<TDocument, TKey>(FilterDefinition<TDocument> condition, FindOptions findOption = null,
string partitionKey = null, string partitionKey = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
@@ -75,57 +56,41 @@ namespace MongoDbGenericRepository.DataAccess.Read
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(condition, findOption).FirstOrDefaultAsync(cancellationToken); return HandlePartitioned<TDocument, TKey>(partitionKey).Find(condition, findOption).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Returns one document given filter definition. public virtual TDocument GetOne<TDocument, TKey>(
/// </summary> FilterDefinition<TDocument> condition,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> FindOptions findOption = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> string partitionKey = null,
/// <param name="condition">A mongodb filter definition.</param> CancellationToken cancellationToken = default)
/// <param name="findOption">A mongodb filter option.</param>
/// <param name="partitionKey">An optional partition key.</param>
public virtual TDocument GetOne<TDocument, TKey>(FilterDefinition<TDocument> condition, FindOptions findOption = null, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(condition, findOption).FirstOrDefault(); return HandlePartitioned<TDocument, TKey>(partitionKey).Find(condition, findOption).FirstOrDefault(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Asynchronously returns one document given an expression filter. public virtual async Task<TDocument> GetOneAsync<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> string partitionKey = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<TDocument> GetOneAsync<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return await HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).FirstOrDefaultAsync(cancellationToken); return await HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Returns one document given an expression filter. public virtual TDocument GetOne<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> string partitionKey = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partition key.</param>
public virtual TDocument GetOne<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).FirstOrDefault(); return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).FirstOrDefault(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Returns a collection cursor.
/// </summary>
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partition key.</param>
public virtual IFindFluent<TDocument, TDocument> GetCursor<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null) public virtual IFindFluent<TDocument, TDocument> GetCursor<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
@@ -133,16 +98,11 @@ namespace MongoDbGenericRepository.DataAccess.Read
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter); return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter);
} }
/// <summary> /// <inheritdoc />
/// Returns true if any of the document of the collection matches the filter condition. public virtual async Task<bool> AnyAsync<TDocument, TKey>(
/// </summary> FilterDefinition<TDocument> condition,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> CountOptions countOption = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> string partitionKey = null,
/// <param name="condition">A mongodb filter definition.</param>
/// <param name="countOption">A mongodb counting option.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<bool> AnyAsync<TDocument, TKey>(FilterDefinition<TDocument> condition, CountOptions countOption = null, string partitionKey = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
@@ -151,192 +111,145 @@ namespace MongoDbGenericRepository.DataAccess.Read
return count > 0; return count > 0;
} }
/// <summary> /// <inheritdoc />
/// Returns true if any of the document of the collection matches the filter condition. public virtual bool Any<TDocument, TKey>(
/// </summary> FilterDefinition<TDocument> condition,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> CountOptions countOption = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> string partitionKey = null,
/// <param name="condition">A mongodb filter definition.</param> CancellationToken cancellationToken = default)
/// <param name="countOption">A mongodb counting option.</param>
/// <param name="partitionKey">An optional partition key.</param>
public virtual bool Any<TDocument, TKey>(FilterDefinition<TDocument> condition, CountOptions countOption = null,
string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
var count = HandlePartitioned<TDocument, TKey>(partitionKey).CountDocuments(condition, countOption); var count = HandlePartitioned<TDocument, TKey>(partitionKey).CountDocuments(condition, countOption, cancellationToken);
return count > 0; return count > 0;
} }
/// <summary> /// <inheritdoc />
/// Returns true if any of the document of the collection matches the filter condition. public virtual async Task<bool> AnyAsync<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> string partitionKey = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<bool> AnyAsync<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
var count = await HandlePartitioned<TDocument, TKey>(partitionKey).CountDocumentsAsync(filter, cancellationToken: cancellationToken); var count = await HandlePartitioned<TDocument, TKey>(partitionKey).CountDocumentsAsync(filter, cancellationToken: cancellationToken);
return (count > 0); return count > 0;
} }
/// <summary> /// <inheritdoc />
/// Returns true if any of the document of the collection matches the filter condition. public virtual bool Any<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> string partitionKey = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partition key.</param>
public virtual bool Any<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
var count = HandlePartitioned<TDocument, TKey>(partitionKey).CountDocuments(filter); var count = HandlePartitioned<TDocument, TKey>(partitionKey).CountDocuments(filter, cancellationToken: cancellationToken);
return (count > 0); return count > 0;
} }
/// <summary> /// <inheritdoc />
/// Asynchronously returns a list of the documents matching the filter condition. public virtual Task<List<TDocument>> GetAllAsync<TDocument, TKey>(
/// </summary> FilterDefinition<TDocument> condition,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> FindOptions findOption = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> string partitionKey = null,
/// <param name="condition">A mongodb filter definition.</param> CancellationToken cancellationToken = default)
/// <param name="findOption">A mongodb filter option.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual Task<List<TDocument>> GetAllAsync<TDocument, TKey>(FilterDefinition<TDocument> condition,
FindOptions findOption = null, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(condition, findOption).ToListAsync(cancellationToken); return HandlePartitioned<TDocument, TKey>(partitionKey).Find(condition, findOption).ToListAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Returns a list of the documents matching the filter condition. public virtual List<TDocument> GetAll<TDocument, TKey>(
/// </summary> FilterDefinition<TDocument> condition,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> FindOptions findOption = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> string partitionKey = null,
/// <param name="condition">A mongodb filter definition.</param> CancellationToken cancellationToken = default)
/// <param name="findOption">A mongodb filter option.</param>
/// <param name="partitionKey">An optional partition key.</param>
public virtual List<TDocument> GetAll<TDocument, TKey>(FilterDefinition<TDocument> condition, FindOptions findOption = null,
string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(condition, findOption).ToList(); return HandlePartitioned<TDocument, TKey>(partitionKey).Find(condition, findOption).ToList(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Asynchronously returns a list of the documents matching the filter condition. public virtual async Task<List<TDocument>> GetAllAsync<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> string partitionKey = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<List<TDocument>> GetAllAsync<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return await HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).ToListAsync(cancellationToken); return await HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).ToListAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Returns a list of the documents matching the filter condition. public virtual List<TDocument> GetAll<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> string partitionKey = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partition key.</param>
public virtual List<TDocument> GetAll<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).ToList(); return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).ToList(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Asynchronously counts how many documents match the filter condition. public virtual Task<long> CountAsync<TDocument, TKey>(
/// </summary> FilterDefinition<TDocument> condition,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> CountOptions countOption = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> string partitionKey = null,
/// <param name="condition">A mongodb filter definition.</param> CancellationToken cancellationToken = default)
/// <param name="countOption">A mongodb counting option.</param>
/// <param name="partitionKey">An optional partitionKey</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual Task<long> CountAsync<TDocument, TKey>(FilterDefinition<TDocument> condition, CountOptions countOption = null,
string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return HandlePartitioned<TDocument, TKey>(partitionKey).CountDocumentsAsync(condition, countOption, cancellationToken); return HandlePartitioned<TDocument, TKey>(partitionKey).CountDocumentsAsync(condition, countOption, cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Counts how many documents match the filter condition. public virtual long Count<TDocument, TKey>(
/// </summary> FilterDefinition<TDocument> condition,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> CountOptions countOption = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> string partitionKey = null,
/// <param name="condition">A mongodb filter definition.</param> CancellationToken cancellationToken = default)
/// <param name="countOption">A mongodb counting option.</param>
/// <param name="partitionKey">An optional partitionKey</param>
public virtual long Count<TDocument, TKey>(FilterDefinition<TDocument> condition, CountOptions countOption = null,
string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return HandlePartitioned<TDocument, TKey>(partitionKey).CountDocuments(condition, countOption); return HandlePartitioned<TDocument, TKey>(partitionKey).CountDocuments(condition, countOption, cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Asynchronously counts how many documents match the filter condition. public virtual async Task<long> CountAsync<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> string partitionKey = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partitionKey</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<long> CountAsync<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return await HandlePartitioned<TDocument, TKey>(partitionKey).CountDocumentsAsync(filter, cancellationToken: cancellationToken); return await HandlePartitioned<TDocument, TKey>(partitionKey).CountDocumentsAsync(filter, cancellationToken: cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Counts how many documents match the filter condition. public virtual long Count<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> string partitionKey = null,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="partitionKey">An optional partitionKey</param>
public virtual long Count<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).CountDocuments(); return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter).CountDocuments(cancellationToken);
} }
#endregion #endregion
#region Min / Max #region Min / Max
/// <summary> /// <inheritdoc />
/// Gets the document with the maximum value of a specified property in a MongoDB collections that is satisfying the filter. public virtual async Task<TDocument> GetByMaxAsync<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The document type.</typeparam> Expression<Func<TDocument, object>> maxValueSelector,
/// <typeparam name="TKey">The type of the primary key.</typeparam> string partitionKey = null,
/// <param name="filter">A LINQ expression filter.</param> CancellationToken cancellationToken = default)
/// <param name="maxValueSelector">A property selector to order by descending.</param>
/// <param name="partitionKey">An optional partitionKey.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<TDocument> GetByMaxAsync<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, object>> maxValueSelector, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
@@ -346,34 +259,27 @@ namespace MongoDbGenericRepository.DataAccess.Read
.FirstOrDefaultAsync(cancellationToken); .FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Gets the document with the maximum value of a specified property in a MongoDB collections that is satisfying the filter. public virtual TDocument GetByMax<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The document type.</typeparam> Expression<Func<TDocument, object>> maxValueSelector,
/// <typeparam name="TKey">The type of the primary key.</typeparam> string partitionKey = null,
/// <param name="filter">A LINQ expression filter.</param> CancellationToken cancellationToken = default)
/// <param name="maxValueSelector">A property selector to order by descending.</param>
/// <param name="partitionKey">An optional partitionKey.</param>
public virtual TDocument GetByMax<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, object>> maxValueSelector, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return GetCollection<TDocument, TKey>(partitionKey).Find(Builders<TDocument>.Filter.Where(filter)) return GetCollection<TDocument, TKey>(partitionKey).Find(Builders<TDocument>.Filter.Where(filter))
.SortByDescending(maxValueSelector) .SortByDescending(maxValueSelector)
.Limit(1) .Limit(1)
.FirstOrDefault(); .FirstOrDefault(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Gets the document with the minimum value of a specified property in a MongoDB collections that is satisfying the filter. public virtual async Task<TDocument> GetByMinAsync<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The document type.</typeparam> Expression<Func<TDocument, object>> minValueSelector,
/// <typeparam name="TKey">The type of the primary key.</typeparam> string partitionKey = null,
/// <param name="filter">A LINQ expression filter.</param> CancellationToken cancellationToken = default)
/// <param name="minValueSelector">A property selector to order by ascending.</param>
/// <param name="partitionKey">An optional partitionKey.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<TDocument> GetByMinAsync<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, object>> minValueSelector, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
@@ -383,35 +289,27 @@ namespace MongoDbGenericRepository.DataAccess.Read
.FirstOrDefaultAsync(cancellationToken); .FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Gets the document with the minimum value of a specified property in a MongoDB collections that is satisfying the filter. public virtual TDocument GetByMin<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The document type.</typeparam> Expression<Func<TDocument, object>> minValueSelector,
/// <typeparam name="TKey">The type of the primary key.</typeparam> string partitionKey = null,
/// <param name="filter">A LINQ expression filter.</param> CancellationToken cancellationToken = default)
/// <param name="minValueSelector">A property selector to order by ascending.</param>
/// <param name="partitionKey">An optional partitionKey.</param>
public virtual TDocument GetByMin<TDocument, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, object>> minValueSelector, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return GetCollection<TDocument, TKey>(partitionKey).Find(Builders<TDocument>.Filter.Where(filter)) return GetCollection<TDocument, TKey>(partitionKey).Find(Builders<TDocument>.Filter.Where(filter))
.SortBy(minValueSelector) .SortBy(minValueSelector)
.Limit(1) .Limit(1)
.FirstOrDefault(); .FirstOrDefault(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Gets the maximum value of a property in a mongodb collections that is satisfying the filter. public virtual async Task<TValue> GetMaxValueAsync<TDocument, TKey, TValue>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The document type.</typeparam> Expression<Func<TDocument, TValue>> maxValueSelector,
/// <typeparam name="TKey">The type of the primary key.</typeparam> string partitionKey = null,
/// <typeparam name="TValue">The type of the field for which you want the maximum value.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="maxValueSelector">A property selector to order by ascending.</param>
/// <param name="partitionKey">An optional partitionKey.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<TValue> GetMaxValueAsync<TDocument, TKey, TValue>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TValue>> maxValueSelector, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
@@ -420,72 +318,53 @@ namespace MongoDbGenericRepository.DataAccess.Read
.FirstOrDefaultAsync(cancellationToken); .FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Gets the maximum value of a property in a mongodb collections that is satisfying the filter. public virtual TValue GetMaxValue<TDocument, TKey, TValue>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The document type.</typeparam> Expression<Func<TDocument, TValue>> maxValueSelector,
/// <typeparam name="TKey">The type of the primary key.</typeparam> string partitionKey = null,
/// <typeparam name="TValue">The type of the value used to order the query.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="maxValueSelector">A property selector to order by ascending.</param>
/// <param name="partitionKey">An optional partitionKey.</param>
public virtual TValue GetMaxValue<TDocument, TKey, TValue>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TValue>> maxValueSelector, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return GetMaxMongoQuery<TDocument, TKey, TValue>(filter, maxValueSelector, partitionKey) return GetMaxMongoQuery<TDocument, TKey, TValue>(filter, maxValueSelector, partitionKey)
.Project(maxValueSelector) .Project(maxValueSelector)
.FirstOrDefault(); .FirstOrDefault(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Gets the minimum value of a property in a mongodb collections that is satisfying the filter. public virtual async Task<TValue> GetMinValueAsync<TDocument, TKey, TValue>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The document type.</typeparam> Expression<Func<TDocument, TValue>> minValueSelector,
/// <typeparam name="TKey">The type of the primary key.</typeparam> string partitionKey = null,
/// <typeparam name="TValue">The type of the value used to order the query.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="minValueSelector">A property selector to order by ascending.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<TValue> GetMinValueAsync<TDocument, TKey, TValue>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TValue>> minValueSelector, string partitionKey = null, CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return await GetMinMongoQuery<TDocument, TKey, TValue>(filter, minValueSelector, partitionKey).Project(minValueSelector).FirstOrDefaultAsync(cancellationToken); return await GetMinMongoQuery<TDocument, TKey, TValue>(filter, minValueSelector, partitionKey).Project(minValueSelector)
.FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Gets the minimum value of a property in a mongodb collections that is satisfying the filter. public virtual TValue GetMinValue<TDocument, TKey, TValue>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The document type.</typeparam> Expression<Func<TDocument, TValue>> minValueSelector,
/// <typeparam name="TKey">The type of the primary key.</typeparam> string partitionKey = null,
/// <typeparam name="TValue">The type of the value used to order the query.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="minValueSelector">A property selector to order by ascending.</param>
/// <param name="partitionKey">An optional partition key.</param>
public virtual TValue GetMinValue<TDocument, TKey, TValue>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TValue>> minValueSelector, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return GetMinMongoQuery<TDocument, TKey, TValue>(filter, minValueSelector, partitionKey).Project(minValueSelector).FirstOrDefault(); return GetMinMongoQuery<TDocument, TKey, TValue>(filter, minValueSelector, partitionKey).Project(minValueSelector)
.FirstOrDefault(cancellationToken);
} }
#endregion Min / Max #endregion Min / Max
#region Sum TKey #region Sum TKey
/// <summary> /// <inheritdoc />
/// Sums the values of a selected field for a given filtered collection of documents. public virtual async Task<int> SumByAsync<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="selector">The field you want to sum.</param>
/// <param name="partitionKey">The partition key of your document, if any.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<int> SumByAsync<TDocument, TKey>(Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, int>> selector, Expression<Func<TDocument, int>> selector,
string partitionKey = null, string partitionKey = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
@@ -495,15 +374,9 @@ namespace MongoDbGenericRepository.DataAccess.Read
return await GetQuery<TDocument, TKey>(filter, partitionKey).SumAsync(selector, cancellationToken); return await GetQuery<TDocument, TKey>(filter, partitionKey).SumAsync(selector, cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Sums the values of a selected field for a given filtered collection of documents. public virtual int SumBy<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="selector">The field you want to sum.</param>
/// <param name="partitionKey">The partition key of your document, if any.</param>
public virtual int SumBy<TDocument, TKey>(Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, int>> selector, Expression<Func<TDocument, int>> selector,
string partitionKey = null) string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
@@ -512,33 +385,21 @@ namespace MongoDbGenericRepository.DataAccess.Read
return GetQuery<TDocument, TKey>(filter, partitionKey).Sum(selector); return GetQuery<TDocument, TKey>(filter, partitionKey).Sum(selector);
} }
/// <summary> /// <inheritdoc />
/// Sums the values of a selected field for a given filtered collection of documents. public virtual async Task<decimal> SumByAsync<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="selector">The field you want to sum.</param>
/// <param name="partitionKey">The partition key of your document, if any.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<decimal> SumByAsync<TDocument, TKey>(Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, decimal>> selector, Expression<Func<TDocument, decimal>> selector,
string partitionKey = null, CancellationToken cancellationToken = default) string partitionKey = null,
CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
{ {
return await GetQuery<TDocument, TKey>(filter, partitionKey).SumAsync(selector, cancellationToken); return await GetQuery<TDocument, TKey>(filter, partitionKey).SumAsync(selector, cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Sums the values of a selected field for a given filtered collection of documents. public virtual decimal SumBy<TDocument, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="selector">The field you want to sum.</param>
/// <param name="partitionKey">The partition key of your document, if any.</param>
public virtual decimal SumBy<TDocument, TKey>(Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, decimal>> selector, Expression<Func<TDocument, decimal>> selector,
string partitionKey = null) string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
@@ -549,155 +410,4 @@ namespace MongoDbGenericRepository.DataAccess.Read
#endregion Sum TKey #endregion Sum TKey
} }
public partial class MongoDbReader
{
/// <summary>
/// Groups a collection of documents given a grouping criteria,
/// and returns a dictionary of listed document groups with keys having the different values of the grouping criteria.
/// </summary>
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <typeparam name="TGroupKey">The type of the grouping criteria.</typeparam>
/// <typeparam name="TProjection">The type of the projected group.</typeparam>
/// <param name="groupingCriteria">The grouping criteria.</param>
/// <param name="groupProjection">The projected group result.</param>
/// <param name="partitionKey">The partition key of your document, if any.</param>
public virtual List<TProjection> GroupBy<TDocument, TGroupKey, TProjection, TKey>(
Expression<Func<TDocument, TGroupKey>> groupingCriteria,
Expression<Func<IGrouping<TGroupKey, TDocument>, TProjection>> groupProjection,
string partitionKey = null)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
where TProjection : class, new()
{
return HandlePartitioned<TDocument, TKey>(partitionKey)
.Aggregate()
.Group(groupingCriteria, groupProjection)
.ToList();
}
/// <summary>
/// Groups filtered a collection of documents given a grouping criteria,
/// and returns a dictionary of listed document groups with keys having the different values of the grouping criteria.
/// </summary>
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <typeparam name="TGroupKey">The type of the grouping criteria.</typeparam>
/// <typeparam name="TProjection">The type of the projected group.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="selector">The grouping criteria.</param>
/// <param name="projection">The projected group result.</param>
/// <param name="partitionKey">The partition key of your document, if any.</param>
public virtual List<TProjection> GroupBy<TDocument, TGroupKey, TProjection, TKey>(
Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, TGroupKey>> selector,
Expression<Func<IGrouping<TGroupKey, TDocument>, TProjection>> projection,
string partitionKey = null)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
where TProjection : class, new()
{
var collection = HandlePartitioned<TDocument, TKey>(partitionKey);
return collection.Aggregate()
.Match(Builders<TDocument>.Filter.Where(filter))
.Group(selector, projection)
.ToList();
}
/// <summary>
/// Groups filtered a collection of documents given a grouping criteria,
/// and returns a dictionary of listed document groups with keys having the different values of the grouping criteria.
/// </summary>
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <typeparam name="TGroupKey">The type of the grouping criteria.</typeparam>
/// <typeparam name="TProjection">The type of the projected group.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="selector">The grouping criteria.</param>
/// <param name="projection">The projected group result.</param>
/// <param name="partitionKey">The partition key of your document, if any.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<List<TProjection>> GroupByAsync<TDocument, TGroupKey, TProjection, TKey>(
Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, TGroupKey>> selector,
Expression<Func<IGrouping<TGroupKey, TDocument>, TProjection>> projection,
string partitionKey = null,
CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
where TProjection : class, new()
{
var collection = HandlePartitioned<TDocument, TKey>(partitionKey);
return await collection.Aggregate()
.Match(Builders<TDocument>.Filter.Where(filter))
.Group(selector, projection)
.ToListAsync(cancellationToken);
}
/// <summary>
/// Asynchronously returns a paginated list of the documents matching the filter condition.
/// </summary>
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="sortSelector">The property selector.</param>
/// <param name="ascending">Order of the sorting.</param>
/// <param name="skipNumber">The number of documents you want to skip. Default value is 0.</param>
/// <param name="takeNumber">The number of documents you want to take. Default value is 50.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<List<TDocument>> GetSortedPaginatedAsync<TDocument, TKey>(
Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, object>> sortSelector,
bool ascending = true,
int skipNumber = 0,
int takeNumber = 50,
string partitionKey = null,
CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
{
var sorting = ascending
? Builders<TDocument>.Sort.Ascending(sortSelector)
: Builders<TDocument>.Sort.Descending(sortSelector);
return await HandlePartitioned<TDocument, TKey>(partitionKey)
.Find(filter)
.Sort(sorting)
.Skip(skipNumber)
.Limit(takeNumber)
.ToListAsync(cancellationToken);
}
/// <summary>
/// Asynchronously returns a paginated list of the documents matching the filter condition.
/// </summary>
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="sortDefinition">The sort definition.</param>
/// <param name="skipNumber">The number of documents you want to skip. Default value is 0.</param>
/// <param name="takeNumber">The number of documents you want to take. Default value is 50.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<List<TDocument>> GetSortedPaginatedAsync<TDocument, TKey>(
Expression<Func<TDocument, bool>> filter,
SortDefinition<TDocument> sortDefinition,
int skipNumber = 0,
int takeNumber = 50,
string partitionKey = null,
CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
{
return await HandlePartitioned<TDocument, TKey>(partitionKey)
.Find(filter)
.Sort(sortDefinition)
.Skip(skipNumber)
.Limit(takeNumber)
.ToListAsync(cancellationToken);
}
}
} }
@@ -1,27 +1,16 @@
using MongoDB.Driver; using System;
using MongoDB.Driver.Linq;
using MongoDbGenericRepository.Models;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDbGenericRepository.Models;
namespace MongoDbGenericRepository.DataAccess.Read namespace MongoDbGenericRepository.DataAccess.Read
{ {
public partial class MongoDbReader : IMongoDbReader public partial class MongoDbReader
{ {
/// <summary> /// <inheritdoc />
/// Asynchronously returns a projected document matching the filter condition.
/// </summary>
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <typeparam name="TProjection">The type representing the model you want to project to.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="projection">The projection expression.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<TProjection> ProjectOneAsync<TDocument, TProjection, TKey>( public virtual async Task<TProjection> ProjectOneAsync<TDocument, TProjection, TKey>(
Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, TProjection>> projection, Expression<Func<TDocument, TProjection>> projection,
@@ -31,40 +20,13 @@ namespace MongoDbGenericRepository.DataAccess.Read
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
where TProjection : class where TProjection : class
{ {
return await HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter) return await HandlePartitioned<TDocument, TKey>(partitionKey)
.Find(filter)
.Project(projection) .Project(projection)
.FirstOrDefaultAsync(cancellationToken); .FirstOrDefaultAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Returns a projected document matching the filter condition.
/// </summary>
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <typeparam name="TProjection">The type representing the model you want to project to.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="projection">The projection expression.</param>
/// <param name="partitionKey">An optional partition key.</param>
public virtual TProjection ProjectOne<TDocument, TProjection, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TProjection>> projection, string partitionKey = null)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
where TProjection : class
{
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter)
.Project(projection)
.FirstOrDefault();
}
/// <summary>
/// Asynchronously returns a list of projected documents matching the filter condition.
/// </summary>
/// <typeparam name="TDocument">The type representing a Document.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam>
/// <typeparam name="TProjection">The type representing the model you want to project to.</typeparam>
/// <param name="filter">A LINQ expression filter.</param>
/// <param name="projection">The projection expression.</param>
/// <param name="partitionKey">An optional partition key.</param>
/// <param name="cancellationToken">An optional cancellation Token.</param>
public virtual async Task<List<TProjection>> ProjectManyAsync<TDocument, TProjection, TKey>( public virtual async Task<List<TProjection>> ProjectManyAsync<TDocument, TProjection, TKey>(
Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, TProjection>> projection, Expression<Func<TDocument, TProjection>> projection,
@@ -79,23 +41,34 @@ namespace MongoDbGenericRepository.DataAccess.Read
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
} }
/// <summary> /// <inheritdoc />
/// Asynchronously returns a list of projected documents matching the filter condition. public virtual TProjection ProjectOne<TDocument, TProjection, TKey>(
/// </summary> Expression<Func<TDocument, bool>> filter,
/// <typeparam name="TDocument">The type representing a Document.</typeparam> Expression<Func<TDocument, TProjection>> projection,
/// <typeparam name="TKey">The type of the primary key for a Document.</typeparam> string partitionKey = null,
/// <typeparam name="TProjection">The type representing the model you want to project to.</typeparam> CancellationToken cancellationToken = default)
/// <param name="filter">The document filter.</param>
/// <param name="projection">The projection expression.</param>
/// <param name="partitionKey">An optional partition key.</param>
public virtual List<TProjection> ProjectMany<TDocument, TProjection, TKey>(Expression<Func<TDocument, bool>> filter, Expression<Func<TDocument, TProjection>> projection, string partitionKey = null)
where TDocument : IDocument<TKey> where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey> where TKey : IEquatable<TKey>
where TProjection : class where TProjection : class
{ {
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter) return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter)
.Project(projection) .Project(projection)
.ToList(); .FirstOrDefault(cancellationToken);
}
/// <inheritdoc />
public virtual List<TProjection> ProjectMany<TDocument, TProjection, TKey>(
Expression<Func<TDocument, bool>> filter,
Expression<Func<TDocument, TProjection>> projection,
string partitionKey = null,
CancellationToken cancellationToken = default)
where TDocument : IDocument<TKey>
where TKey : IEquatable<TKey>
where TProjection : class
{
return HandlePartitioned<TDocument, TKey>(partitionKey).Find(filter)
.Project(projection)
.ToList(cancellationToken);
} }
} }
} }