From 25766febd487fc15d91ecc15f9e14c93bed40c03 Mon Sep 17 00:00:00 2001 From: Sean Garrett Date: Tue, 20 Jun 2023 22:06:30 +0100 Subject: [PATCH] Index tests --- .../IndexTests/CreateTextIndexTests.cs | 24 +-- .../IndexTests/GetIndexNamesTests.cs | 6 +- .../BaseIndexTests.cs | 45 +++++ .../CreateTextIndexAsyncTests.cs | 180 ++++++++++++++++++ .../GetIndexNamesAsyncTests.cs | 129 +++++++++++++ .../Infrastructure/IndexExtensions.cs | 57 ++++++ .../DataAccess/Index/IMongoDbIndexHandler.cs | 78 +++++--- .../DataAccess/Index/MongoDbIndexHandler.cs | 180 +++++++----------- 8 files changed, 553 insertions(+), 146 deletions(-) create mode 100644 CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/BaseIndexTests.cs create mode 100644 CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/CreateTextIndexAsyncTests.cs create mode 100644 CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/GetIndexNamesAsyncTests.cs create mode 100644 CoreUnitTests/Infrastructure/IndexExtensions.cs diff --git a/CoreUnitTests/BaseMongoRepositoryTests/IndexTests/CreateTextIndexTests.cs b/CoreUnitTests/BaseMongoRepositoryTests/IndexTests/CreateTextIndexTests.cs index e7dd3be..c3584ec 100644 --- a/CoreUnitTests/BaseMongoRepositoryTests/IndexTests/CreateTextIndexTests.cs +++ b/CoreUnitTests/BaseMongoRepositoryTests/IndexTests/CreateTextIndexTests.cs @@ -12,20 +12,20 @@ namespace CoreUnitTests.BaseMongoRepositoryTests.IndexTests; public class CreateTextIndexTests : BaseIndexTests { - private readonly Expression> _fieldExpression = t => t.SomeContent2; + private readonly Expression> fieldExpression = t => t.SomeContent2; [Fact] - public async Task Ensure_Creates_Index() + public async Task WhenFieldExpression_CreatesIndex() { // Arrange IndexHandler = new Mock(); // Act - await Sut.CreateTextIndexAsync(_fieldExpression); + await Sut.CreateTextIndexAsync(fieldExpression); // Assert IndexHandler.Verify( - x => x.CreateTextIndexAsync(_fieldExpression, null, null)); + x => x.CreateTextIndexAsync(fieldExpression, null, null, CancellationToken.None)); } [Fact] @@ -36,12 +36,12 @@ public class CreateTextIndexTests : BaseIndexTests var options = new IndexCreationOptions { Name = "theIndexName" }; // Act - await Sut.CreateTextIndexAsync(_fieldExpression, options); + await Sut.CreateTextIndexAsync(fieldExpression, options); // Assert IndexHandler.Verify( x => x.CreateTextIndexAsync( - _fieldExpression, options, null)); + fieldExpression, options, null, CancellationToken.None)); } [Fact] @@ -53,16 +53,15 @@ public class CreateTextIndexTests : BaseIndexTests IndexHandler = new Mock(); // Act - await Sut.CreateTextIndexAsync(_fieldExpression, partitionKey: partitionKey); + await Sut.CreateTextIndexAsync(fieldExpression, partitionKey: partitionKey); // Assert IndexHandler.Verify( x => x.CreateTextIndexAsync( - _fieldExpression, null, partitionKey)); + fieldExpression, null, partitionKey, CancellationToken.None)); } - /* - [Fact] + /*[Fact] public async Task Ensure_Creates_Index_With_CancellationToken() { // Arrange @@ -70,13 +69,14 @@ public class CreateTextIndexTests : BaseIndexTests var token = new CancellationToken(true); // Act - await Sut.CreateTextIndexAsync(_fieldExpression, token); + await Sut.CreateTextIndexAsync(fieldExpression, token); // Assert IndexHandler.Verify( x => x.CreateTextIndexAsync(_fieldExpression, null, null, token)); - } + }*/ + /* [Fact] public async Task Ensure_Passes_Options_With_CancellationToken() { diff --git a/CoreUnitTests/BaseMongoRepositoryTests/IndexTests/GetIndexNamesTests.cs b/CoreUnitTests/BaseMongoRepositoryTests/IndexTests/GetIndexNamesTests.cs index a23350a..c73e7ae 100644 --- a/CoreUnitTests/BaseMongoRepositoryTests/IndexTests/GetIndexNamesTests.cs +++ b/CoreUnitTests/BaseMongoRepositoryTests/IndexTests/GetIndexNamesTests.cs @@ -19,7 +19,7 @@ public class GetIndexNamesTests : BaseIndexTests const string indexName = "theIndexName"; IndexHandler - .Setup(x => x.GetIndexesNamesAsync(null)) + .Setup(x => x.GetIndexesNamesAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(new List { indexName }); // Act @@ -28,7 +28,7 @@ public class GetIndexNamesTests : BaseIndexTests // Assert Assert.NotNull(result); Assert.Contains(result, x => x == indexName); - IndexHandler.Verify(x => x.GetIndexesNamesAsync(null), Times.Once()); + IndexHandler.Verify(x => x.GetIndexesNamesAsync(null, CancellationToken.None), Times.Once()); } /* @@ -61,7 +61,7 @@ public class GetIndexNamesTests : BaseIndexTests IndexHandler = new Mock(); IndexHandler - .Setup(x => x.GetIndexesNamesAsync(partitionKey)) + .Setup(x => x.GetIndexesNamesAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(new List { indexName }); // Act diff --git a/CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/BaseIndexTests.cs b/CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/BaseIndexTests.cs new file mode 100644 index 0000000..566aa75 --- /dev/null +++ b/CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/BaseIndexTests.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Threading; +using CoreUnitTests.Infrastructure; +using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using MongoDB.Driver; +using MongoDbGenericRepository.DataAccess.Index; +using Moq; + +namespace CoreUnitTests.DataAccessTests.MongoDbIndexHandlerTests; + +public class BaseIndexTests : GenericTestContext +{ + protected (Mock>, Mock>) SetupIndexes( + List indexes, + Mock> collection) + { + var asyncCursor = MockOf>(); + var moveNextSequence = asyncCursor + .SetupSequence(x => x.MoveNextAsync(It.IsAny())); + + var currentSequence = asyncCursor + .SetupSequence(x => x.Current); + + foreach (var bsonDocument in indexes) + { + moveNextSequence.ReturnsAsync(true); + currentSequence.Returns(new[] {bsonDocument}); + } + + moveNextSequence.ReturnsAsync(false); + + var indexManager = MockOf>(); + indexManager + .Setup(x => x.ListAsync(It.IsAny())) + .ReturnsAsync(asyncCursor.Object); + + collection + .SetupGet(x => x.Indexes) + .Returns(indexManager.Object); + + return (asyncCursor, indexManager); + } + +} diff --git a/CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/CreateTextIndexAsyncTests.cs b/CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/CreateTextIndexAsyncTests.cs new file mode 100644 index 0000000..f54b2ff --- /dev/null +++ b/CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/CreateTextIndexAsyncTests.cs @@ -0,0 +1,180 @@ +using System; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using AutoFixture; +using CoreUnitTests.Infrastructure; +using CoreUnitTests.Infrastructure.Model; +using FluentAssertions; +using MongoDB.Driver; +using MongoDbGenericRepository; +using MongoDbGenericRepository.Models; +using Moq; +using Xunit; + +namespace CoreUnitTests.DataAccessTests.MongoDbIndexHandlerTests; + +public class CreateTextIndexAsyncTests : BaseIndexTests +{ + private readonly Expression> fieldExpression = t => t.SomeContent2; + + [Fact] + public async Task WhenFieldExpression_ThenCreatesIndex() + { + // Arrange + var expectedIndexName = Fixture.Create(); + var collection = MockOf>(); + SetupContext(collection); + + var indexManger = SetupIndexManager(collection, expectedIndexName); + + // Act + var result = await Sut.CreateTextIndexAsync(fieldExpression); + + // Assert + result.Should().Be(expectedIndexName); + indexManger.Verify( + x => x.CreateOneAsync( + It.Is>(t => t.Keys.EqualToJson("{\"SomeContent2\":\"text\"}")), + null, + CancellationToken.None), + Times.Once); + } + + [Fact] + public async Task WhenFieldExpressionAndOptions_ThenCreatesIndex() + { + // Arrange + var expectedIndexName = Fixture.Create(); + var collection = MockOf>(); + var options = Fixture.Create(); + + SetupContext(collection); + var indexManger = SetupIndexManager(collection, expectedIndexName); + + // Act + var result = await Sut.CreateTextIndexAsync(fieldExpression, options); + + // Assert + result.Should().Be(expectedIndexName); + indexManger.Verify( + x => x.CreateOneAsync( + It.Is>( + t => t.Keys.EqualToJson("{\"SomeContent2\":\"text\"}") && + t.Options.EqualTo(options)), + null, + CancellationToken.None), + Times.Once); + } + + [Fact] + public async Task WhenFieldExpressionAndPartitionKey_ThenCreatesIndex() + { + // Arrange + var expectedIndexName = Fixture.Create(); + var collection = MockOf>(); + var partitionKey = Fixture.Create(); + + var context = SetupContext(collection); + + var indexManger = SetupIndexManager(collection, expectedIndexName); + + // Act + var result = await Sut.CreateTextIndexAsync(fieldExpression, partitionKey: partitionKey); + + // Assert + result.Should().Be(expectedIndexName); + indexManger.Verify( + x => x.CreateOneAsync( + It.Is>( + t => t.Keys.EqualToJson("{\"SomeContent2\":\"text\"}") ), + null, + CancellationToken.None), + Times.Once); + context.Verify(x => x.GetCollection(partitionKey), Times.Once); + } + + [Fact] + public async Task WhenFieldExpressionAndCancellationToken_ThenCreatesIndex() + { + // Arrange + var expectedIndexName = Fixture.Create(); + var collection = MockOf>(); + var token = new CancellationToken(true); + + SetupContext(collection); + + var indexManger = SetupIndexManager(collection, expectedIndexName); + + // Act + var result = await Sut.CreateTextIndexAsync(fieldExpression, cancellationToken: token); + + // Assert + result.Should().Be(expectedIndexName); + indexManger.Verify( + x => x.CreateOneAsync( + It.Is>( + t => t.Keys.EqualToJson("{\"SomeContent2\":\"text\"}") ), + null, + token), + Times.Once); + } + + [Fact] + public async Task WhenFieldExpressionAndOptionsAndPartitionKeyAndCancellationToken_ThenCreatesIndex() + { + // Arrange + var expectedIndexName = Fixture.Create(); + var collection = MockOf>(); + var token = new CancellationToken(true); + var partitionKey = Fixture.Create(); + var options = Fixture.Create(); + + var context = SetupContext(collection); + + var indexManger = SetupIndexManager(collection, expectedIndexName); + + // Act + var result = await Sut.CreateTextIndexAsync(fieldExpression, options, partitionKey, token); + + // Assert + result.Should().Be(expectedIndexName); + indexManger.Verify( + x => x.CreateOneAsync( + It.Is>( + t => t.Keys.EqualToJson("{\"SomeContent2\":\"text\"}") && + t.Options.EqualTo(options)), + null, + token), + Times.Once); + context.Verify(x => x.GetCollection(partitionKey), Times.Once); + } + + private Mock SetupContext(Mock> collection) + { + var context = MockOf(); + context + .Setup(x => x.GetCollection(It.IsAny())) + .Returns(collection.Object); + + return context; + } + + private Mock> SetupIndexManager(Mock> collection, string indexName) + { + var indexManager = MockOf>(); + indexManager + .Setup( + x => x.CreateOneAsync( + It.IsAny>(), + It.IsAny(), + It.IsAny())) + .ReturnsAsync(indexName); + + collection + .SetupGet(x => x.Indexes) + .Returns(indexManager.Object); + + return indexManager; + } +} diff --git a/CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/GetIndexNamesAsyncTests.cs b/CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/GetIndexNamesAsyncTests.cs new file mode 100644 index 0000000..45e8b56 --- /dev/null +++ b/CoreUnitTests/DataAccessTests/MongoDbIndexHandlerTests/GetIndexNamesAsyncTests.cs @@ -0,0 +1,129 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using AutoFixture; +using CoreUnitTests.Infrastructure.Model; +using FluentAssertions; +using MongoDB.Bson; +using MongoDB.Driver; +using MongoDbGenericRepository; +using Moq; +using Xunit; + +namespace CoreUnitTests.DataAccessTests.MongoDbIndexHandlerTests; + +public class GetIndexNamesAsyncTests : BaseIndexTests +{ + [Fact] + public async Task WithNoParameters_ReturnsAllIndexNames() + { + // Arrange + var indexNames = Fixture.CreateMany().ToList(); + var indexes = indexNames.Select(x => new BsonDocument {{"name", x}}).ToList(); + + var collection = MockOf>(); + + var context = MockOf(); + context + .Setup(x => x.GetCollection(It.IsAny())) + .Returns(collection.Object); + + var (cursor, manager) = SetupIndexes(indexes, collection); + + // Act + var result = await Sut.GetIndexesNamesAsync(); + + // Assert + result.Should().NotBeNull(); + result.Should().BeEquivalentTo(indexNames); + context.Verify(x => x.GetCollection(null)); + manager.Verify(x => x.ListAsync(CancellationToken.None)); + cursor.Verify(x => x.MoveNextAsync(CancellationToken.None)); + } + + [Fact] + public async Task WithPartitionKey_ReturnsAllIndexNames() + { + // Arrange + var partitionKey = Fixture.Create(); + var indexNames = Fixture.CreateMany().ToList(); + var indexes = indexNames.Select(x => new BsonDocument {{"name", x}}).ToList(); + + var collection = MockOf>(); + + var context = MockOf(); + context + .Setup(x => x.GetCollection(It.IsAny())) + .Returns(collection.Object); + + var (cursor, manager) = SetupIndexes(indexes, collection); + + // Act + var result = await Sut.GetIndexesNamesAsync(partitionKey); + + // Assert + result.Should().NotBeNull(); + result.Should().BeEquivalentTo(indexNames); + context.Verify(x => x.GetCollection(partitionKey)); + manager.Verify(x => x.ListAsync(CancellationToken.None)); + cursor.Verify(x => x.MoveNextAsync(CancellationToken.None)); + } + + [Fact] + public async Task WithCancellationToken_ReturnsAllIndexNames() + { + // Arrange + var token = new CancellationToken(); + var indexNames = Fixture.CreateMany().ToList(); + var indexes = indexNames.Select(x => new BsonDocument {{"name", x}}).ToList(); + + var collection = MockOf>(); + + var context = MockOf(); + context + .Setup(x => x.GetCollection(It.IsAny())) + .Returns(collection.Object); + + var (cursor, manager) = SetupIndexes(indexes, collection); + + // Act + var result = await Sut.GetIndexesNamesAsync(cancellationToken:token); + + // Assert + result.Should().NotBeNull(); + result.Should().BeEquivalentTo(indexNames); + context.Verify(x => x.GetCollection(null)); + manager.Verify(x => x.ListAsync(token)); + cursor.Verify(x => x.MoveNextAsync(token)); + } + + [Fact] + public async Task WithPartitionKeyCancellationToken_ReturnsAllIndexNames() + { + // Arrange + var partitionKey = Fixture.Create(); + var token = new CancellationToken(); + var indexNames = Fixture.CreateMany().ToList(); + var indexes = indexNames.Select(x => new BsonDocument {{"name", x}}).ToList(); + + var collection = MockOf>(); + + var context = MockOf(); + context + .Setup(x => x.GetCollection(It.IsAny())) + .Returns(collection.Object); + + var (cursor, manager) = SetupIndexes(indexes, collection); + + // Act + var result = await Sut.GetIndexesNamesAsync(partitionKey, token); + + // Assert + result.Should().NotBeNull(); + result.Should().BeEquivalentTo(indexNames); + context.Verify(x => x.GetCollection(partitionKey)); + manager.Verify(x => x.ListAsync(token)); + cursor.Verify(x => x.MoveNextAsync(token)); + } +} diff --git a/CoreUnitTests/Infrastructure/IndexExtensions.cs b/CoreUnitTests/Infrastructure/IndexExtensions.cs new file mode 100644 index 0000000..7daa789 --- /dev/null +++ b/CoreUnitTests/Infrastructure/IndexExtensions.cs @@ -0,0 +1,57 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using MongoDB.Driver; +using MongoDbGenericRepository.Models; + +namespace CoreUnitTests.Infrastructure; + +public static class IndexExtensions +{ + public static bool EqualToJson(this IndexKeysDefinition keys, string json) + { + var indexModelRendered = RenderIndexModelKeys(keys); + return indexModelRendered.Equals(json, System.StringComparison.Ordinal); + } + + public static bool EqualTo(this IndexCreationOptions x, CreateIndexOptions y) => + x.Unique == y.Unique && + x.TextIndexVersion == y.TextIndexVersion && + x.SphereIndexVersion == y.SphereIndexVersion && + x.Sparse == y.Sparse && + x.Name == y.Name && + x.Min == y.Min && + x.Max == y.Max && + x.LanguageOverride == y.LanguageOverride && + x.ExpireAfter == y.ExpireAfter && + x.DefaultLanguage == y.DefaultLanguage && + x.Bits == y.Bits && + x.Background == y.Background && + x.Version == y.Version; + + public static bool EqualTo(this CreateIndexOptions x, IndexCreationOptions y) => + x.Unique == y.Unique && + x.TextIndexVersion == y.TextIndexVersion && + x.SphereIndexVersion == y.SphereIndexVersion && + x.Sparse == y.Sparse && + x.Name == y.Name && + x.Min == y.Min && + x.Max == y.Max && + x.LanguageOverride == y.LanguageOverride && + x.ExpireAfter == y.ExpireAfter && + x.DefaultLanguage == y.DefaultLanguage && + x.Bits == y.Bits && + x.Background == y.Background && + x.Version == y.Version; + + private static string RenderIndexModelKeys(IndexKeysDefinition keys) + { + var indexModelRendered = keys.Render( + BsonSerializer.SerializerRegistry.GetSerializer(), + BsonSerializer.SerializerRegistry); + + var result = indexModelRendered.ToString(); + return result.Replace(" ", ""); + } + + +} diff --git a/MongoDbGenericRepository/DataAccess/Index/IMongoDbIndexHandler.cs b/MongoDbGenericRepository/DataAccess/Index/IMongoDbIndexHandler.cs index 247ad6a..9c79ab5 100644 --- a/MongoDbGenericRepository/DataAccess/Index/IMongoDbIndexHandler.cs +++ b/MongoDbGenericRepository/DataAccess/Index/IMongoDbIndexHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; +using System.Threading; using System.Threading.Tasks; using MongoDbGenericRepository.DataAccess.Base; using MongoDbGenericRepository.Models; @@ -8,104 +9,131 @@ using MongoDbGenericRepository.Models; namespace MongoDbGenericRepository.DataAccess.Index { /// - /// The MongoDbIndexHandler interface. used to create indexes on collections. + /// The MongoDbIndexHandler interface. used to create indexes on collections. /// public interface IMongoDbIndexHandler : IDataAccessBase { /// - /// Returns the names of the indexes present on a collection. + /// Returns the names of the indexes present on a collection. /// /// The type representing a Document. /// The type of the primary key for a Document. /// An optional partition key + /// An optional Cancellation Token. /// A list containing the names of the indexes on on the concerned collection. - Task> GetIndexesNamesAsync(string partitionKey = null) + Task> GetIndexesNamesAsync(string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable; /// - /// Create a text index on the given field. - /// IndexCreationOptions can be supplied to further specify - /// how the creation should be done. + /// Create a text index on the given field. + /// IndexCreationOptions can be supplied to further specify + /// how the creation should be done. /// /// The type representing a Document. /// The type of the primary key for a Document. /// The field we want to index. /// Options for creating an index. /// An optional partition key. + /// An optional cancellation token /// The result of the create index operation. - Task CreateTextIndexAsync(Expression> field, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) + Task CreateTextIndexAsync( + Expression> field, + IndexCreationOptions indexCreationOptions = null, + string partitionKey = null, + CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable; /// - /// Creates an index on the given field in ascending order. - /// IndexCreationOptions can be supplied to further specify - /// how the creation should be done. + /// Creates an index on the given field in ascending order. + /// IndexCreationOptions can be supplied to further specify + /// how the creation should be done. /// /// The type representing a Document. /// The type of the primary key for a Document. /// The field we want to index. /// Options for creating an index. /// An optional partition key. + /// An optional cancellation token. /// The result of the create index operation. - Task CreateAscendingIndexAsync(Expression> field, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) + Task CreateAscendingIndexAsync( + Expression> field, + IndexCreationOptions indexCreationOptions = null, + string partitionKey = null, + CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable; /// - /// Creates an index on the given field in descending order. - /// IndexCreationOptions can be supplied to further specify - /// how the creation should be done. + /// Creates an index on the given field in descending order. + /// IndexCreationOptions can be supplied to further specify + /// how the creation should be done. /// /// The type representing a Document. /// The type of the primary key for a Document. /// The field we want to index. /// Options for creating an index. /// An optional partition key. + /// An optional cancellation token. /// The result of the create index operation. - Task CreateDescendingIndexAsync(Expression> field, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) + Task CreateDescendingIndexAsync( + Expression> field, + IndexCreationOptions indexCreationOptions = null, + string partitionKey = null, + CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable; /// - /// Creates a hashed index on the given field. - /// IndexCreationOptions can be supplied to further specify - /// how the creation should be done. + /// Creates a hashed index on the given field. + /// IndexCreationOptions can be supplied to further specify + /// how the creation should be done. /// /// The type representing a Document. /// The type of the primary key for a Document. /// The field we want to index. /// Options for creating an index. /// An optional partition key. + /// An optional cancellation token. /// The result of the create index operation. - Task CreateHashedIndexAsync(Expression> field, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) + Task CreateHashedIndexAsync( + Expression> field, + IndexCreationOptions indexCreationOptions = null, + string partitionKey = null, + CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable; /// - /// Creates a combined text index. - /// IndexCreationOptions can be supplied to further specify - /// how the creation should be done. + /// Creates a combined text index. + /// IndexCreationOptions can be supplied to further specify + /// how the creation should be done. /// /// The type representing a Document. /// The type of the primary key for a Document. /// The fields we want to index. /// Options for creating an index. /// An optional partition key. + /// An optional Cancellation token. /// The result of the create index operation. - Task CreateCombinedTextIndexAsync(IEnumerable>> fields, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) + Task CreateCombinedTextIndexAsync( + IEnumerable>> fields, + IndexCreationOptions indexCreationOptions = null, + string partitionKey = null, + CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable; /// - /// Drops the index given a field name + /// Drops the index given a field name /// /// The type representing a Document. /// The type of the primary key for a Document. /// The name of the index /// An optional partition key - Task DropIndexAsync(string indexName, string partitionKey = null) + /// An optional cancellation token, + Task DropIndexAsync(string indexName, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable; } diff --git a/MongoDbGenericRepository/DataAccess/Index/MongoDbIndexHandler.cs b/MongoDbGenericRepository/DataAccess/Index/MongoDbIndexHandler.cs index a4bf5e8..0bfe00b 100644 --- a/MongoDbGenericRepository/DataAccess/Index/MongoDbIndexHandler.cs +++ b/MongoDbGenericRepository/DataAccess/Index/MongoDbIndexHandler.cs @@ -1,11 +1,12 @@ -using MongoDB.Driver; -using MongoDbGenericRepository.DataAccess.Base; -using MongoDbGenericRepository.Models; -using System; +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.DataAccess.Base; +using MongoDbGenericRepository.Models; namespace MongoDbGenericRepository.DataAccess.Index { @@ -13,64 +14,67 @@ namespace MongoDbGenericRepository.DataAccess.Index public class MongoDbIndexHandler : DataAccessBase, IMongoDbIndexHandler { /// - /// The MongoDbIndexHandler constructor. + /// The MongoDbIndexHandler constructor. /// /// The mongo db context public MongoDbIndexHandler(IMongoDbContext mongoDbContext) : base(mongoDbContext) { } - /// - /// Returns the names of the indexes present on a collection. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// An optional partition key - /// A list containing the names of the indexes on on the concerned collection. - public virtual async Task> GetIndexesNamesAsync(string partitionKey = null) + /// + public virtual async Task> GetIndexesNamesAsync(string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { - var indexCursor = await HandlePartitioned(partitionKey).Indexes.ListAsync(); - var indexes = await indexCursor.ToListAsync(); + var indexCursor = await HandlePartitioned(partitionKey).Indexes.ListAsync(cancellationToken); + var indexes = await indexCursor.ToListAsync(cancellationToken); return indexes.Select(e => e["name"].ToString()).ToList(); } - /// - /// Create a text index on the given field. - /// IndexCreationOptions can be supplied to further specify - /// how the creation should be done. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The field we want to index. - /// Options for creating an index. - /// An optional partition key. - /// The result of the create index operation. - public virtual async Task CreateTextIndexAsync(Expression> field, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) + /// + public virtual async Task CreateTextIndexAsync( + Expression> field, + IndexCreationOptions indexCreationOptions = null, + string partitionKey = null, + CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { + var model = new CreateIndexModel( + Builders.IndexKeys.Text(field), + indexCreationOptions == null ? null : MapIndexOptions(indexCreationOptions) + ); + return await HandlePartitioned(partitionKey).Indexes - .CreateOneAsync( - new CreateIndexModel( - Builders.IndexKeys.Text(field), - indexCreationOptions == null ? null : MapIndexOptions(indexCreationOptions) - )); + .CreateOneAsync( + model, + cancellationToken: cancellationToken); } - /// - /// Creates an index on the given field in ascending order. - /// IndexCreationOptions can be supplied to further specify - /// how the creation should be done. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The field we want to index. - /// Options for creating an index. - /// An optional partition key. - /// The result of the create index operation. - public virtual async Task CreateAscendingIndexAsync(Expression> field, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) + /// + public virtual async Task CreateAscendingIndexAsync( + Expression> field, + IndexCreationOptions indexCreationOptions = null, + string partitionKey = null, + CancellationToken cancellationToken = default) + where TDocument : IDocument + where TKey : IEquatable + { + var collection = HandlePartitioned(partitionKey); + var createOptions = indexCreationOptions == null ? null : MapIndexOptions(indexCreationOptions); + var indexKey = Builders.IndexKeys; + return await + collection.Indexes.CreateOneAsync( + new CreateIndexModel(indexKey.Ascending(field), createOptions), + cancellationToken: cancellationToken); + } + + /// + public virtual async Task CreateDescendingIndexAsync( + Expression> field, + IndexCreationOptions indexCreationOptions = null, + string partitionKey = null, + CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { @@ -78,22 +82,17 @@ namespace MongoDbGenericRepository.DataAccess.Index var createOptions = indexCreationOptions == null ? null : MapIndexOptions(indexCreationOptions); var indexKey = Builders.IndexKeys; return await collection.Indexes - .CreateOneAsync( - new CreateIndexModel(indexKey.Ascending(field), createOptions)); + .CreateOneAsync( + new CreateIndexModel(indexKey.Descending(field), createOptions), + cancellationToken: cancellationToken); } - /// - /// Creates an index on the given field in descending order. - /// IndexCreationOptions can be supplied to further specify - /// how the creation should be done. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The field we want to index. - /// Options for creating an index. - /// An optional partition key. - /// The result of the create index operation. - public virtual async Task CreateDescendingIndexAsync(Expression> field, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) + /// + public virtual async Task CreateHashedIndexAsync( + Expression> field, + IndexCreationOptions indexCreationOptions = null, + string partitionKey = null, + CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { @@ -101,45 +100,17 @@ namespace MongoDbGenericRepository.DataAccess.Index var createOptions = indexCreationOptions == null ? null : MapIndexOptions(indexCreationOptions); var indexKey = Builders.IndexKeys; return await collection.Indexes - .CreateOneAsync( - new CreateIndexModel(indexKey.Descending(field), createOptions)); + .CreateOneAsync( + new CreateIndexModel(indexKey.Hashed(field), createOptions), + cancellationToken: cancellationToken); } - /// - /// Creates a hashed index on the given field. - /// IndexCreationOptions can be supplied to further specify - /// how the creation should be done. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The field we want to index. - /// Options for creating an index. - /// An optional partition key. - /// The result of the create index operation. - public virtual async Task CreateHashedIndexAsync(Expression> field, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - var collection = HandlePartitioned(partitionKey); - var createOptions = indexCreationOptions == null ? null : MapIndexOptions(indexCreationOptions); - var indexKey = Builders.IndexKeys; - return await collection.Indexes - .CreateOneAsync( - new CreateIndexModel(indexKey.Hashed(field), createOptions)); - } - - /// - /// Creates a combined text index. - /// IndexCreationOptions can be supplied to further specify - /// how the creation should be done. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The fields we want to index. - /// Options for creating an index. - /// An optional partition key. - /// The result of the create index operation. - public virtual async Task CreateCombinedTextIndexAsync(IEnumerable>> fields, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) + /// + public virtual async Task CreateCombinedTextIndexAsync( + IEnumerable>> fields, + IndexCreationOptions indexCreationOptions = null, + string partitionKey = null, + CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { @@ -150,22 +121,19 @@ namespace MongoDbGenericRepository.DataAccess.Index { listOfDefs.Add(Builders.IndexKeys.Text(field)); } + return await collection.Indexes - .CreateOneAsync(new CreateIndexModel(Builders.IndexKeys.Combine(listOfDefs), createOptions)); + .CreateOneAsync( + new CreateIndexModel(Builders.IndexKeys.Combine(listOfDefs), createOptions), + cancellationToken: cancellationToken); } - /// - /// Drops the index given a field name - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The name of the index - /// An optional partition key - public virtual async Task DropIndexAsync(string indexName, string partitionKey = null) + /// + public virtual async Task DropIndexAsync(string indexName, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { - await HandlePartitioned(partitionKey).Indexes.DropOneAsync(indexName); + await HandlePartitioned(partitionKey).Indexes.DropOneAsync(indexName, cancellationToken); } } -} +} \ No newline at end of file