using MongoDB.Driver; using MongoDB.Driver.Linq; using MongoDbGenericRepository.DataAccess.Read; using MongoDbGenericRepository.Models; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; namespace MongoDbGenericRepository { public interface IBaseReadOnlyRepository { /// /// The connection string. /// string ConnectionString { get; } /// /// The database name. /// string DatabaseName { get; } #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. Task GetByIdAsync(TKey id, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// 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. TDocument GetById(TKey id, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// 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. Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// 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. TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// 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. IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// 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. Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// 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. bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// 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. Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// 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. List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// 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 Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// 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 long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; #endregion #region Min / Max /// /// Gets the document with the maximum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by descending. /// An optional partitionKey. Task GetByMaxAsync(Expression> filter, Expression> orderByDescending, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// Gets the document with the maximum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by descending. /// An optional partitionKey. TDocument GetByMax(Expression> filter, Expression> orderByDescending, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// Gets the document with the minimum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. Task GetByMinAsync(Expression> filter, Expression> orderByAscending, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// Gets the document with the minimum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. TDocument GetByMin(Expression> filter, Expression> orderByAscending, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// Gets the maximum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. Task GetMaxValueAsync(Expression> filter, Expression> maxValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// Gets the maximum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. TValue GetMaxValue(Expression> filter, Expression> orderByDescending, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// Gets the minimum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// The type of the value used to order the query. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partition key. Task GetMinValueAsync(Expression> filter, Expression> minValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// Gets the minimum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// The type of the value used to order the query. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partition key. TValue GetMinValue(Expression> filter, Expression> minValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; #endregion #region Sum /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. Task SumByAsync(Expression> filter, Expression> selector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. int SumBy(Expression> filter, Expression> selector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. Task SumByAsync(Expression> filter, Expression> selector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. decimal SumBy(Expression> filter, Expression> selector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable; #endregion Sum } public class BaseReadOnlyRepository : IBaseReadOnlyRepository { /// /// The connection string. /// public string ConnectionString { get; } /// /// The database name. /// public string DatabaseName { get; } /// /// The MongoDbContext /// protected IMongoDbContext MongoDbContext = null; /// /// A MongoDb Reader for read operations /// protected MongoDbReader MongoDbReader = null; /// /// 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 BaseReadOnlyRepository(string connectionString, string databaseName = null) { if (databaseName == null) { var mongoUrl = new MongoUrl(connectionString); databaseName = databaseName ?? mongoUrl.DatabaseName; } ConnectionString = connectionString; DatabaseName = databaseName; SetupMongoDbContext(new MongoDbContext(connectionString, databaseName)); } /// /// The contructor taking a . /// /// A mongodb context implementing protected BaseReadOnlyRepository(IMongoDbContext mongoDbContext) { SetupMongoDbContext(mongoDbContext); } /// /// The contructor taking a . /// /// A mongodb context implementing protected BaseReadOnlyRepository(IMongoDatabase mongoDatabase) { SetupMongoDbContext(new MongoDbContext(mongoDatabase)); } protected void SetupMongoDbContext(IMongoDbContext mongoDbContext) { MongoDbContext = mongoDbContext; MongoDbReader = new MongoDbReader(MongoDbContext); } #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 virtual Task GetByIdAsync(TKey id, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return await MongoDbReader.GetByIdAsync(id, partitionKey); } /// /// 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 virtual TDocument GetById(TKey id, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.GetById(id, partitionKey); } /// /// 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 virtual Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return await MongoDbReader.GetOneAsync(filter, partitionKey); } /// /// 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 virtual TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.GetOne(filter, partitionKey); } /// /// 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 virtual IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.GetCursor(filter, partitionKey); } /// /// 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 virtual Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return await MongoDbReader.AnyAsync(filter, partitionKey); } /// /// 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 virtual bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.Any(filter, partitionKey); } /// /// 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 virtual Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return await MongoDbReader.GetAllAsync(filter, partitionKey); } /// /// 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 virtual List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.GetAll(filter, partitionKey); } /// /// 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 virtual Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return await MongoDbReader.CountAsync(filter, partitionKey); } /// /// 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 virtual long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.Count(filter, partitionKey); } /// /// Gets the document with the maximum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by descending. /// An optional partitionKey. public async virtual Task GetByMaxAsync(Expression> filter, Expression> maxValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return await MongoDbReader.GetByMaxAsync(filter, maxValueSelector, partitionKey); } /// /// Gets the document with the maximum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by descending. /// An optional partitionKey. public virtual TDocument GetByMax(Expression> filter, Expression> maxValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.GetByMax(filter, maxValueSelector, partitionKey); } /// /// Gets the document with the minimum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. public async virtual Task GetByMinAsync(Expression> filter, Expression> minValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return await MongoDbReader.GetByMinAsync(filter, minValueSelector, partitionKey); } /// /// Gets the document with the minimum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. public virtual TDocument GetByMin(Expression> filter, Expression> minValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.GetByMin(filter, minValueSelector, partitionKey); } /// /// Gets the maximum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. public async virtual Task GetMaxValueAsync(Expression> filter, Expression> maxValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return await MongoDbReader.GetMaxValueAsync(filter, maxValueSelector, partitionKey); } /// /// Gets the maximum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// The type of the value used to order the query. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. public virtual TValue GetMaxValue(Expression> filter, Expression> maxValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.GetMaxValue(filter, maxValueSelector, partitionKey); } /// /// Gets the minimum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// The type of the value used to order the query. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partition key. public virtual async Task GetMinValueAsync(Expression> filter, Expression> minValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return await MongoDbReader.GetMinValueAsync(filter, minValueSelector, partitionKey); } /// /// Gets the minimum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// The type of the value used to order the query. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partition key. public virtual TValue GetMinValue(Expression> filter, Expression> minValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.GetMinValue(filter, minValueSelector, partitionKey); } #endregion #region Sum TKey /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. public virtual async Task SumByAsync(Expression> filter, Expression> selector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return await MongoDbReader.SumByAsync(filter, selector, partitionKey); } /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. public virtual int SumBy(Expression> filter, Expression> selector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.SumBy(filter, selector, partitionKey); } /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. public virtual async Task SumByAsync(Expression> filter, Expression> selector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return await MongoDbReader.SumByAsync(filter, selector, partitionKey); } /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. public virtual decimal SumBy(Expression> filter, Expression> selector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbReader.SumBy(filter, selector, partitionKey); } #endregion Sum TKey #region Utility Methods protected virtual IMongoQueryable GetQuery(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return GetCollection(partitionKey).AsQueryable().Where(filter); } /// /// Gets a collections for a potentially partitioned document type. /// /// The document type. /// The type of the primary key. /// The document. /// protected virtual IMongoCollection HandlePartitioned(TDocument document) where TDocument : IDocument where TKey : IEquatable { if (document is IPartitionedDocument) { return GetCollection(((IPartitionedDocument)document).PartitionKey); } return GetCollection(); } /// /// Gets a collections for the type TDocument with a partition key. /// /// The document type. /// The type of the primary key. /// The collection partition key. /// protected virtual IMongoCollection GetCollection(string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return MongoDbContext.GetCollection(partitionKey); } /// /// Gets a collections for a potentially partitioned document type. /// /// The document type. /// The type of the primary key. /// The collection partition key. /// protected virtual IMongoCollection HandlePartitioned(string partitionKey) where TDocument : IDocument where TKey : IEquatable { if (!string.IsNullOrEmpty(partitionKey)) { return GetCollection(partitionKey); } return GetCollection(); } /// /// Converts a LINQ expression of TDocument, TValue to a LINQ expression of TDocument, object /// /// The document type. /// The type of the value. /// The expression to convert protected virtual Expression> ConvertExpression(Expression> expression) { var param = expression.Parameters[0]; Expression body = expression.Body; var convert = Expression.Convert(body, typeof(object)); return Expression.Lambda>(convert, param); } /// /// Maps a IndexCreationOptions object to a MongoDB.Driver.CreateIndexOptions object /// /// The options for creating an index. /// protected virtual CreateIndexOptions MapIndexOptions(IndexCreationOptions indexCreationOptions) { return new CreateIndexOptions { Unique = indexCreationOptions.Unique, TextIndexVersion = indexCreationOptions.TextIndexVersion, SphereIndexVersion = indexCreationOptions.SphereIndexVersion, Sparse = indexCreationOptions.Sparse, Name = indexCreationOptions.Name, Min = indexCreationOptions.Min, Max = indexCreationOptions.Max, LanguageOverride = indexCreationOptions.LanguageOverride, ExpireAfter = indexCreationOptions.ExpireAfter, DefaultLanguage = indexCreationOptions.DefaultLanguage, BucketSize = indexCreationOptions.BucketSize, Bits = indexCreationOptions.Bits, Background = indexCreationOptions.Background, Version = indexCreationOptions.Version }; } /// /// Gets the minimum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// The type of the value used to order the query. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partition key. protected virtual IFindFluent GetMinMongoQuery(Expression> filter, Expression> minValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return GetCollection(partitionKey).Find(Builders.Filter.Where(filter)) .SortBy(ConvertExpression(minValueSelector)) .Limit(1); } /// /// Gets the minimum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// The type of the value used to order the query. /// A LINQ expression filter. /// A property selector to order by descending. /// An optional partition key. protected virtual IFindFluent GetMaxMongoQuery(Expression> filter, Expression> maxValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return GetCollection(partitionKey).Find(Builders.Filter.Where(filter)) .SortByDescending(ConvertExpression(maxValueSelector)) .Limit(1); } #endregion } }