diff --git a/CoreIntegrationTests/CoreIntegrationTests.csproj b/CoreIntegrationTests/CoreIntegrationTests.csproj index 2e4ad1b..4edac06 100644 --- a/CoreIntegrationTests/CoreIntegrationTests.csproj +++ b/CoreIntegrationTests/CoreIntegrationTests.csproj @@ -7,13 +7,16 @@ - + + + + Always diff --git a/IntegrationTests/App.config b/IntegrationTests/App.config index 139995c..6d19a67 100644 --- a/IntegrationTests/App.config +++ b/IntegrationTests/App.config @@ -7,4 +7,12 @@ + + + + + + + + \ No newline at end of file diff --git a/IntegrationTests/IntegrationTests.csproj b/IntegrationTests/IntegrationTests.csproj index 58a2d21..580fb5d 100644 --- a/IntegrationTests/IntegrationTests.csproj +++ b/IntegrationTests/IntegrationTests.csproj @@ -31,16 +31,13 @@ - ..\packages\MongoDbGenericRepository.1.2.1\lib\net45\MongoDB.Bson.dll + ..\packages\MongoDB.Bson.2.4.4\lib\net45\MongoDB.Bson.dll - ..\packages\MongoDbGenericRepository.1.2.1\lib\net45\MongoDB.Driver.dll + ..\packages\MongoDB.Driver.2.4.4\lib\net45\MongoDB.Driver.dll - ..\packages\MongoDbGenericRepository.1.2.1\lib\net45\MongoDB.Driver.Core.dll - - - ..\packages\MongoDbGenericRepository.1.2.1\lib\net45\MongoDbGenericRepository.dll + ..\packages\MongoDB.Driver.Core.2.4.4\lib\net45\MongoDB.Driver.Core.dll ..\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll @@ -49,8 +46,9 @@ - - ..\packages\MongoDbGenericRepository.1.2.1\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True @@ -78,5 +76,11 @@ + + + {efc776c4-2af3-440c-be80-3fbe335817a5} + MongoDbGenericRepository + + \ No newline at end of file diff --git a/IntegrationTests/packages.config b/IntegrationTests/packages.config index 8ef186d..383927f 100644 --- a/IntegrationTests/packages.config +++ b/IntegrationTests/packages.config @@ -3,8 +3,8 @@ - - + + \ No newline at end of file diff --git a/MongoDbGenericRepository/BaseMongoDbRepository.cs b/MongoDbGenericRepository/BaseMongoDbRepository.cs index 1427742..f7f566c 100644 --- a/MongoDbGenericRepository/BaseMongoDbRepository.cs +++ b/MongoDbGenericRepository/BaseMongoDbRepository.cs @@ -1,1114 +1,1372 @@ -using MongoDB.Driver; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using System.Linq.Expressions; -using MongoDbGenericRepository.Models; -using System.Linq; - -namespace MongoDbGenericRepository -{ - /// - /// The IBaseMongoRepository exposes the functionality of the BaseMongoRepository. - /// - public interface IBaseMongoRepository - { - /// - /// The connection string. - /// - string ConnectionString { get; set; } - /// - /// The database name. - /// - string DatabaseName { get; set; } - - #region Create - - /// - /// Asynchronously adds a document to the collection. - /// - /// The type representing a Document. - /// The document you want to add. - Task AddOneAsync(TDocument document) where TDocument : IDocument; - - /// - /// Adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - void AddOne(TDocument document) where TDocument : IDocument; - - /// - /// Asynchronously adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - Task AddManyAsync(IEnumerable documents) where TDocument : IDocument; - - /// - /// Adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - void AddMany(IEnumerable documents) where TDocument : IDocument; - - #endregion - - #region Read - - /// - /// Asynchronously returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns a collection cursor. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - #endregion - - #region Update - - /// - /// Asynchronously Updates a document. - /// - /// The type representing a Document. - /// The document with the modifications you want to persist. - Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument; - - /// - /// Updates a document. - /// - /// The type representing a Document. - /// The document with the modifications you want to persist. - bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument; - - #endregion - - #region Delete - - /// - /// Asynchronously deletes a document. - /// - /// The type representing a Document. - /// The document you want to delete. - /// The number of documents deleted. - Task DeleteOneAsync(TDocument document) where TDocument : IDocument; - - /// - /// Asynchronously deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - Task DeleteOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Deletes a document. - /// - /// The type representing a Document. - /// The document you want to delete. - /// The number of documents deleted. - long DeleteOne(TDocument document) where TDocument : IDocument; - - /// - /// Deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - long DeleteOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - Task DeleteManyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously deletes a list of documents. - /// - /// The type representing a Document. - /// The list of documents to delete. - /// The number of documents deleted. - Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument; - - /// - /// Deletes a list of documents. - /// - /// The type representing a Document. - /// The list of documents to delete. - /// The number of documents deleted. - long DeleteMany(IEnumerable documents) where TDocument : IDocument; - - /// - /// Deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - long DeleteMany(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - #endregion - - #region Project - - /// - /// Asynchronously returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Asynchronously returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - /// - /// Returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - #endregion - - /// - /// Asynchronously returns a paginated list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// - /// The number of documents you want to skip. Default value is 0. - /// The number of documents you want to take. Default value is 50. - /// An optional partition key. - Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) - where TDocument : IDocument; - - /// - /// Asynchronously returns a paginated list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// - /// The number of documents you want to skip. Default value is 0. - /// The number of documents you want to take. Default value is 50. - /// An optional partition key. - Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// GetAndUpdateOne with filter - /// - /// The type representing a Document. - /// - /// - /// - /// - Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) - where TDocument : IDocument; - - /// - /// GetAndUpdateOne with filter - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// - /// - /// - /// - Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) - where TDocument : IDocument - where TKey : IEquatable; - - } - - /// - /// The base Repository, it is meant to be inherited from by your custom custom MongoRepository implementation. - /// Its constructor must be given a connection string and a database name. - /// - public abstract class BaseMongoRepository : IBaseMongoRepository - { - /// - /// The connection string. - /// - public string ConnectionString { get; set; } - /// - /// The database name. - /// - public string DatabaseName { get; set; } - - /// - /// The constructor taking a connection string and a database name. - /// - /// The connection string of the MongoDb server. - /// The name of the database against which you want to perform operations. - protected BaseMongoRepository(string connectionString, string databaseName) - { - MongoDbContext = new MongoDbContext(connectionString, databaseName); - } - - /// - /// The contructor taking a . - /// - /// A mongodb context implementing - protected BaseMongoRepository(IMongoDbContext mongoDbContext) - { - MongoDbContext = mongoDbContext; - } - - /// - /// The MongoDbContext - /// - protected IMongoDbContext MongoDbContext = null; - - #region Create - - /// - /// Asynchronously adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - public async Task AddOneAsync(TDocument document) where TDocument : IDocument - { - FormatDocument(document); - await HandlePartitioned(document).InsertOneAsync(document); - } - - /// - /// Adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - public void AddOne(TDocument document) where TDocument : IDocument - { - FormatDocument(document); - HandlePartitioned(document).InsertOne(document); - } - - /// - /// Asynchronously adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The documents you want to add. - public async Task AddManyAsync(IEnumerable documents) where TDocument : IDocument - { - if (!documents.Any()) - { - return; - } - foreach (var doc in documents) - { - FormatDocument(doc); - } - await HandlePartitioned(documents.FirstOrDefault()).InsertManyAsync(documents); - } - - /// - /// Adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The documents you want to add. - public void AddMany(IEnumerable documents) where TDocument : IDocument - { - if (!documents.Any()) - { - return; - } - foreach (var document in documents) - { - FormatDocument(document); - } - HandlePartitioned(documents.FirstOrDefault()).InsertMany(documents.ToList()); - } - - #endregion Create - - #region Read - - /// - /// Asynchronously returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - public async Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument - { - var filter = Builders.Filter.Eq("Id", id); - return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); - } - - /// - /// Returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - public TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument - { - var filter = Builders.Filter.Eq("Id", id); - return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); - } - - /// - /// Asynchronously returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); - } - - /// - /// Returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); - } - - /// - /// Returns a collection cursor. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter); - } - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - var count = await HandlePartitioned(partitionKey).CountAsync(filter); - return (count > 0); - } - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - var count = HandlePartitioned(partitionKey).Count(filter); - return (count > 0); - } - - /// - /// Asynchronously returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(); - } - - /// - /// Returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter).ToList(); - } - - /// - /// Asynchronously counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partitionKey - public async Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return await HandlePartitioned(partitionKey).CountAsync(filter); - } - - /// - /// Counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partitionKey - public long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter).Count(); - } - - #endregion - - #region Update - - /// - /// Asynchronously Updates a document. - /// - /// The type representing a Document. - /// The document with the modifications you want to persist. - public async Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument - { - var updateRes = await HandlePartitioned(modifiedDocument).ReplaceOneAsync(x => x.Id == modifiedDocument.Id, modifiedDocument); - return updateRes.ModifiedCount == 1; - } - - /// - /// Updates a document. - /// - /// The type representing a Document. - /// The document with the modifications you want to persist. - public bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument - { - var updateRes = HandlePartitioned(modifiedDocument).ReplaceOne(x => x.Id == modifiedDocument.Id, modifiedDocument); - return updateRes.ModifiedCount == 1; - } - - #endregion Update - - #region Delete - - /// - /// Asynchronously deletes a document. - /// - /// The type representing a Document. - /// The document you want to delete. - /// The number of documents deleted. - public async Task DeleteOneAsync(TDocument document) where TDocument : IDocument - { - return (await HandlePartitioned(document).DeleteOneAsync(x => x.Id == document.Id)).DeletedCount; - } - - /// - /// Deletes a document. - /// - /// The type representing a Document. - /// The document you want to delete. - /// The number of documents deleted. - public long DeleteOne(TDocument document) where TDocument : IDocument - { - return HandlePartitioned(document).DeleteOne(x => x.Id == document.Id).DeletedCount; - } - - /// - /// Deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - public long DeleteOne(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).DeleteOne(filter).DeletedCount; - } - - /// - /// Asynchronously deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - public async Task DeleteOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return (await HandlePartitioned(partitionKey).DeleteOneAsync(filter)).DeletedCount; - } - - /// - /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - public async Task DeleteManyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return (await HandlePartitioned(partitionKey).DeleteManyAsync(filter)).DeletedCount; - } - - /// - /// Asynchronously deletes a list of documents. - /// - /// The type representing a Document. - /// The list of documents to delete. - /// The number of documents deleted. - public async Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument - { - if (!documents.Any()) - { - return 0; - } - var idsTodelete = documents.Select(e => e.Id).ToArray(); - return (await HandlePartitioned(documents.FirstOrDefault()).DeleteManyAsync(x => idsTodelete.Contains(x.Id))).DeletedCount; - } - - /// - /// Deletes a list of documents. - /// - /// The type representing a Document. - /// The list of documents to delete. - /// The number of documents deleted. - public long DeleteMany(IEnumerable documents) where TDocument : IDocument - { - if (!documents.Any()) - { - return 0; - } - var idsTodelete = documents.Select(e => e.Id).ToArray(); - return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; - } - - /// - /// Deletes a list of documents. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The list of documents to delete. - /// The number of documents deleted. - public long DeleteMany(IEnumerable documents) - where TDocument : IDocument - where TKey : IEquatable - { - if (!documents.Any()) - { - return 0; - } - var idsTodelete = documents.Select(e => e.Id).ToArray(); - return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; - } - - /// - /// Deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - public long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; - } - - /// - /// Deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - public long DeleteMany(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; - } - - #endregion Delete - - #region Project - - /// - /// Asynchronously returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class - { - return await HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .FirstOrDefaultAsync(); - } - - /// - /// Asynchronously returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class - { - return await HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .FirstOrDefaultAsync(); - } - - /// - /// Returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class - { - return HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .FirstOrDefault(); - } - - /// - /// Returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class - { - return HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .FirstOrDefault(); - } - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public async Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class - { - return await HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .ToListAsync(); - } - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public async Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class - { - return await HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .ToListAsync(); - } - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class - { - return HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .ToList(); - } - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - public List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class - { - return HandlePartitioned(partitionKey).Find(filter) - .Project(projection) - .ToList(); - } - - #endregion - - /// - /// Asynchronously returns a paginated list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// - /// The number of documents you want to skip. Default value is 0. - /// The number of documents you want to take. Default value is 50. - /// An optional partition key. - public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) - where TDocument : IDocument - { - return await HandlePartitioned(partitionKey).Find(filter).Skip(skipNumber).Limit(takeNumber).ToListAsync(); - } - - /// - /// Asynchronously returns a paginated list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// - /// The number of documents you want to skip. Default value is 0. - /// The number of documents you want to take. Default value is 50. - /// An optional partition key. - public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - return await HandlePartitioned(partitionKey).Find(filter).Skip(skipNumber).Limit(takeNumber).ToListAsync(); - } - - #region Find And Update - - /// - /// GetAndUpdateOne with filter - /// - /// The type representing a Document. - /// - /// - /// - /// - public async Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) where TDocument : IDocument - { - return await GetCollection().FindOneAndUpdateAsync(filter, update, options); - } - - /// - /// GetAndUpdateOne with filter - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// - /// - /// - /// - public async Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) - where TDocument : IDocument - where TKey : IEquatable - { - return await GetCollection().FindOneAndUpdateAsync(filter, update, options); - } - - #endregion Find And Update - - #region Private Methods - - private IMongoCollection GetCollection(string partitionKey) where TDocument : IDocument - { - return MongoDbContext.GetCollection(partitionKey); - } - - private IMongoCollection GetCollection() where TDocument : IDocument - { - return MongoDbContext.GetCollection(); - } - - private IMongoCollection HandlePartitioned(TDocument document) where TDocument : IDocument - { - if (document is IPartitionedDocument) - { - return GetCollection(((IPartitionedDocument)document).PartitionKey); - } - return GetCollection(); - } - - private IMongoCollection HandlePartitioned(TDocument document) - where TDocument : IDocument - where TKey : IEquatable - { - if (document is IPartitionedDocument) - { - return GetCollection(((IPartitionedDocument)document).PartitionKey); - } - return GetCollection(); - } - - private IMongoCollection HandlePartitioned(string partitionKey) where TDocument : IDocument - { - if (!string.IsNullOrEmpty(partitionKey)) - { - return GetCollection(partitionKey); - } - return GetCollection(); - } - - private void FormatDocument(TDocument document) where TDocument : IDocument - { - if (document == null) - { - throw new ArgumentNullException(nameof(document)); - } - if (document.Id == default(Guid)) - { - document.Id = Guid.NewGuid(); - } - } - - - private IMongoCollection GetCollection(string partitionKey) - where TDocument : IDocument - where TKey : IEquatable - { - return MongoDbContext.GetCollection(partitionKey); - } - - private IMongoCollection GetCollection() - where TDocument : IDocument - where TKey : IEquatable - { - return MongoDbContext.GetCollection(); - } - - private IMongoCollection HandlePartitioned(string partitionKey) - where TDocument : IDocument - where TKey : IEquatable - { - if (!string.IsNullOrEmpty(partitionKey)) - { - return GetCollection(partitionKey); - } - return GetCollection(); - } - - private void FormatDocument(TDocument document) - where TDocument : IDocument - where TKey : IEquatable - { - if (document == null) - { - throw new ArgumentNullException(nameof(document)); - } - } - - #endregion - } +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Linq.Expressions; +using MongoDbGenericRepository.Models; +using System.Linq; + +namespace MongoDbGenericRepository +{ + /// + /// The IBaseMongoRepository exposes the functionality of the BaseMongoRepository. + /// + public interface IBaseMongoRepository + { + /// + /// The connection string. + /// + string ConnectionString { get; set; } + /// + /// The database name. + /// + string DatabaseName { get; set; } + + #region Create + + /// + /// Asynchronously adds a document to the collection. + /// + /// The type representing a Document. + /// The document you want to add. + Task AddOneAsync(TDocument document) where TDocument : IDocument; + + /// + /// Asynchronously adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + Task AddOneAsync(TDocument document) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + void AddOne(TDocument document) where TDocument : IDocument; + + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + void AddOne(TDocument document) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + Task AddManyAsync(IEnumerable documents) where TDocument : IDocument; + + /// + /// Adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + void AddMany(IEnumerable documents) where TDocument : IDocument; + + #endregion + + #region Read + + /// + /// Asynchronously returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns a collection cursor. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + #endregion + + #region Update + + /// + /// Asynchronously Updates a document. + /// + /// The type representing a Document. + /// The document with the modifications you want to persist. + Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument; + + /// + /// Updates a document. + /// + /// The type representing a Document. + /// The document with the modifications you want to persist. + bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument; + + #endregion + + #region Delete + + /// + /// Asynchronously deletes a document. + /// + /// The type representing a Document. + /// The document you want to delete. + /// The number of documents deleted. + Task DeleteOneAsync(TDocument document) where TDocument : IDocument; + + /// + /// Asynchronously deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + Task DeleteOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Deletes a document. + /// + /// The type representing a Document. + /// The document you want to delete. + /// The number of documents deleted. + long DeleteOne(TDocument document) where TDocument : IDocument; + + /// + /// Deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + Task DeleteManyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously deletes a list of documents. + /// + /// The type representing a Document. + /// The list of documents to delete. + /// The number of documents deleted. + Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument; + + /// + /// Deletes a list of documents. + /// + /// The type representing a Document. + /// The list of documents to delete. + /// The number of documents deleted. + long DeleteMany(IEnumerable documents) where TDocument : IDocument; + + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteMany(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + #endregion + + #region Project + + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + #endregion + + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument; + + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// + /// + /// + /// + Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + where TDocument : IDocument; + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// + /// + /// + Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + where TDocument : IDocument + where TKey : IEquatable; + + } + + /// + /// The base Repository, it is meant to be inherited from by your custom custom MongoRepository implementation. + /// Its constructor must be given a connection string and a database name. + /// + public abstract class BaseMongoRepository : IBaseMongoRepository + { + /// + /// The connection string. + /// + public string ConnectionString { get; set; } + + /// + /// The database name. + /// + public string DatabaseName { get; set; } + + /// + /// The constructor taking a connection string and a database name. + /// + /// The connection string of the MongoDb server. + /// The name of the database against which you want to perform operations. + protected BaseMongoRepository(string connectionString, string databaseName) + { + MongoDbContext = new MongoDbContext(connectionString, databaseName); + } + + /// + /// The contructor taking a . + /// + /// A mongodb context implementing + protected BaseMongoRepository(IMongoDbContext mongoDbContext) + { + MongoDbContext = mongoDbContext; + } + + /// + /// The MongoDbContext + /// + protected IMongoDbContext MongoDbContext = null; + + #region Create + + /// + /// Asynchronously adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + public async Task AddOneAsync(TDocument document) where TDocument : IDocument + { + FormatDocument(document); + await HandlePartitioned(document).InsertOneAsync(document); + } + + /// + /// Asynchronously adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + public async Task AddOneAsync(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + FormatDocument(document); + await HandlePartitioned(document).InsertOneAsync(document); + } + + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + public void AddOne(TDocument document) where TDocument : IDocument + { + FormatDocument(document); + HandlePartitioned(document).InsertOne(document); + } + + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + public void AddOne(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + FormatDocument(document); + HandlePartitioned(document).InsertOne(document); + } + + /// + /// Asynchronously adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The documents you want to add. + public async Task AddManyAsync(IEnumerable documents) where TDocument : IDocument + { + if (!documents.Any()) + { + return; + } + foreach (var doc in documents) + { + FormatDocument(doc); + } + await HandlePartitioned(documents.FirstOrDefault()).InsertManyAsync(documents); + } + + /// + /// Asynchronously adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The documents you want to add. + public async Task AddManyAsync(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable + { + if (!documents.Any()) + { + return; + } + foreach (var doc in documents) + { + FormatDocument(doc); + } + await HandlePartitioned(documents.FirstOrDefault()).InsertManyAsync(documents); + } + + /// + /// Adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The documents you want to add. + public void AddMany(IEnumerable documents) where TDocument : IDocument + { + if (!documents.Any()) + { + return; + } + foreach (var document in documents) + { + FormatDocument(document); + } + HandlePartitioned(documents.FirstOrDefault()).InsertMany(documents.ToList()); + } + + #endregion Create + + #region Read + + /// + /// Asynchronously returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public async Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument + { + var filter = Builders.Filter.Eq("Id", id); + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument + { + var filter = Builders.Filter.Eq("Id", id); + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Asynchronously returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Returns a collection cursor. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + var count = await HandlePartitioned(partitionKey).CountAsync(filter); + return (count > 0); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + var count = HandlePartitioned(partitionKey).Count(filter); + return (count > 0); + } + + /// + /// Asynchronously returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(); + } + + /// + /// Returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter).ToList(); + } + + /// + /// Asynchronously counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public async Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).CountAsync(filter); + } + + /// + /// Counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter).Count(); + } + + #endregion + + #region Read TKey + + /// + /// Asynchronously returns one document given its id. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public async Task GetByIdAsync(Guid id, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", id); + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given its id. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public TDocument GetById(Guid id, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", id); + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Asynchronously returns one document given an expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task GetOneAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given an expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public TDocument GetOne(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Returns a collection cursor. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public IFindFluent GetCursor(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task AnyAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + var count = await HandlePartitioned(partitionKey).CountAsync(filter); + return (count > 0); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public bool Any(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + var count = HandlePartitioned(partitionKey).Count(filter); + return (count > 0); + } + + /// + /// Asynchronously returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task> GetAllAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(); + } + + /// + /// Returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public List GetAll(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter).ToList(); + } + + /// + /// Asynchronously counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public async Task CountAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).CountAsync(filter); + } + + /// + /// Counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public long Count(Expression> filter, string partitionKey = null) + where TDocument : IDocument where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter).Count(); + } + + #endregion + + #region Update + + /// + /// Asynchronously Updates a document. + /// + /// The type representing a Document. + /// The document with the modifications you want to persist. + public async Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument + { + var updateRes = await HandlePartitioned(modifiedDocument).ReplaceOneAsync(x => x.Id == modifiedDocument.Id, modifiedDocument); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates a document. + /// + /// The type representing a Document. + /// The document with the modifications you want to persist. + public bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument + { + var updateRes = HandlePartitioned(modifiedDocument).ReplaceOne(x => x.Id == modifiedDocument.Id, modifiedDocument); + return updateRes.ModifiedCount == 1; + } + + #endregion Update + + #region Update TKey + + /// + /// Asynchronously Updates a document. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document with the modifications you want to persist. + public async Task UpdateOneAsync(TDocument modifiedDocument) + where TDocument : IDocument where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", modifiedDocument.Id); + var updateRes = await HandlePartitioned(modifiedDocument).ReplaceOneAsync(filter, modifiedDocument); + return updateRes.ModifiedCount == 1; + } + + /// + /// Updates a document. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document with the modifications you want to persist. + public bool UpdateOne(TDocument modifiedDocument) + where TDocument : IDocument where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", modifiedDocument.Id); + var updateRes = HandlePartitioned(modifiedDocument).ReplaceOne(filter, modifiedDocument); + return updateRes.ModifiedCount == 1; + } + + #endregion Update + + #region Delete + + /// + /// Asynchronously deletes a document. + /// + /// The type representing a Document. + /// The document you want to delete. + /// The number of documents deleted. + public async Task DeleteOneAsync(TDocument document) where TDocument : IDocument + { + return (await HandlePartitioned(document).DeleteOneAsync(x => x.Id == document.Id)).DeletedCount; + } + + /// + /// Deletes a document. + /// + /// The type representing a Document. + /// The document you want to delete. + /// The number of documents deleted. + public long DeleteOne(TDocument document) where TDocument : IDocument + { + return HandlePartitioned(document).DeleteOne(x => x.Id == document.Id).DeletedCount; + } + + /// + /// Deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public long DeleteOne(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).DeleteOne(filter).DeletedCount; + } + + /// + /// Asynchronously deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public async Task DeleteOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return (await HandlePartitioned(partitionKey).DeleteOneAsync(filter)).DeletedCount; + } + + /// + /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public async Task DeleteManyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return (await HandlePartitioned(partitionKey).DeleteManyAsync(filter)).DeletedCount; + } + + /// + /// Asynchronously deletes a list of documents. + /// + /// The type representing a Document. + /// The list of documents to delete. + /// The number of documents deleted. + public async Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument + { + if (!documents.Any()) + { + return 0; + } + var idsTodelete = documents.Select(e => e.Id).ToArray(); + return (await HandlePartitioned(documents.FirstOrDefault()).DeleteManyAsync(x => idsTodelete.Contains(x.Id))).DeletedCount; + } + + /// + /// Deletes a list of documents. + /// + /// The type representing a Document. + /// The list of documents to delete. + /// The number of documents deleted. + public long DeleteMany(IEnumerable documents) where TDocument : IDocument + { + if (!documents.Any()) + { + return 0; + } + var idsTodelete = documents.Select(e => e.Id).ToArray(); + return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; + } + + /// + /// Deletes a list of documents. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The list of documents to delete. + /// The number of documents deleted. + public long DeleteMany(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable + { + if (!documents.Any()) + { + return 0; + } + var idsTodelete = documents.Select(e => e.Id).ToArray(); + return HandlePartitioned(documents.FirstOrDefault()).DeleteMany(x => idsTodelete.Contains(x.Id)).DeletedCount; + } + + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; + } + + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + public long DeleteMany(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return HandlePartitioned(partitionKey).DeleteMany(filter).DeletedCount; + } + + #endregion Delete + + #region Project + + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class + { + return await HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .FirstOrDefaultAsync(); + } + + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return await HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .FirstOrDefaultAsync(); + } + + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class + { + return HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .FirstOrDefault(); + } + + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .FirstOrDefault(); + } + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public async Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class + { + return await HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .ToListAsync(); + } + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public async Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return await HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .ToListAsync(); + } + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class + { + return HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .ToList(); + } + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + public List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class + { + return HandlePartitioned(partitionKey).Find(filter) + .Project(projection) + .ToList(); + } + + #endregion + + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).Find(filter).Skip(skipNumber).Limit(takeNumber).ToListAsync(); + } + + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + public async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).Find(filter).Skip(skipNumber).Limit(takeNumber).ToListAsync(); + } + + #region Find And Update + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// + /// + /// + /// + public async Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) where TDocument : IDocument + { + return await GetCollection().FindOneAndUpdateAsync(filter, update, options); + } + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// + /// + /// + public async Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + where TDocument : IDocument + where TKey : IEquatable + { + return await GetCollection().FindOneAndUpdateAsync(filter, update, options); + } + + #endregion Find And Update + + #region Private Methods + + private IMongoCollection GetCollection(string partitionKey) where TDocument : IDocument + { + return MongoDbContext.GetCollection(partitionKey); + } + + private IMongoCollection GetCollection() where TDocument : IDocument + { + return MongoDbContext.GetCollection(); + } + + private IMongoCollection HandlePartitioned(TDocument document) where TDocument : IDocument + { + if (document is IPartitionedDocument) + { + return GetCollection(((IPartitionedDocument)document).PartitionKey); + } + return GetCollection(); + } + + private IMongoCollection HandlePartitioned(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + if (document is IPartitionedDocument) + { + return GetCollection(((IPartitionedDocument)document).PartitionKey); + } + return GetCollection(); + } + + private IMongoCollection HandlePartitioned(string partitionKey) where TDocument : IDocument + { + if (!string.IsNullOrEmpty(partitionKey)) + { + return GetCollection(partitionKey); + } + return GetCollection(); + } + + private void FormatDocument(TDocument document) where TDocument : IDocument + { + if (document == null) + { + throw new ArgumentNullException(nameof(document)); + } + if (document.Id == default(Guid)) + { + document.Id = Guid.NewGuid(); + } + } + + + private IMongoCollection GetCollection(string partitionKey) + where TDocument : IDocument + where TKey : IEquatable + { + return MongoDbContext.GetCollection(partitionKey); + } + + private IMongoCollection GetCollection() + where TDocument : IDocument + where TKey : IEquatable + { + return MongoDbContext.GetCollection(); + } + + private IMongoCollection HandlePartitioned(string partitionKey) + where TDocument : IDocument + where TKey : IEquatable + { + if (!string.IsNullOrEmpty(partitionKey)) + { + return GetCollection(partitionKey); + } + return GetCollection(); + } + + private void FormatDocument(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + if (document == null) + { + throw new ArgumentNullException(nameof(document)); + } + } + + #endregion + } } \ No newline at end of file