diff --git a/CoreIntegrationTests/CoreIntegrationTests.csproj b/CoreIntegrationTests/CoreIntegrationTests.csproj
index a3ba78f..720179b 100644
--- a/CoreIntegrationTests/CoreIntegrationTests.csproj
+++ b/CoreIntegrationTests/CoreIntegrationTests.csproj
@@ -9,13 +9,16 @@
-
+
+
+
+
..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Configuration.dll
diff --git a/CoreIntegrationTests/Infrastructure/MongoDbDocumentTestBase.cs b/CoreIntegrationTests/Infrastructure/MongoDbDocumentTestBase.cs
index 8c6fc2e..c70056c 100644
--- a/CoreIntegrationTests/Infrastructure/MongoDbDocumentTestBase.cs
+++ b/CoreIntegrationTests/Infrastructure/MongoDbDocumentTestBase.cs
@@ -1075,6 +1075,33 @@ namespace CoreIntegrationTests.Infrastructure
#endregion Index Management
+ #region Math
+
+ [Fact]
+ public async Task SumByAsync()
+ {
+ // Arrange
+ var criteria = $"{GetTestName()}.{DocumentTypeName}.{Guid.NewGuid()}";
+ var documents = CreateTestDocuments(5);
+ var i = 1;
+ documents.ForEach(e =>
+ {
+ e.Nested.SomeDate = e.Nested.SomeDate.AddDays(i++);
+ e.Nested.SomeAmount = 5m;
+ e.SomeContent = criteria;
+ });
+ SUT.AddMany(documents);
+ var expectedSum = documents.Sum(e => e.Nested.SomeAmount);
+
+ // Act
+ var result = await SUT.SumByAsync(e => e.SomeContent == criteria, e => e.Nested.SomeAmount, PartitionKey);
+
+ // Assert
+ Assert.Equal(expectedSum, result);
+ }
+
+ #endregion Math
+
#region Test Utils
[MethodImpl(MethodImplOptions.NoInlining)]
diff --git a/CoreIntegrationTests/Infrastructure/MongoDbTKeyDocumentTestBase.cs b/CoreIntegrationTests/Infrastructure/MongoDbTKeyDocumentTestBase.cs
index 98376f5..9d99665 100644
--- a/CoreIntegrationTests/Infrastructure/MongoDbTKeyDocumentTestBase.cs
+++ b/CoreIntegrationTests/Infrastructure/MongoDbTKeyDocumentTestBase.cs
@@ -1068,6 +1068,33 @@ namespace CoreIntegrationTests.Infrastructure
#endregion Index Management
+ #region Math
+
+ [Fact]
+ public async Task SumByAsync()
+ {
+ // Arrange
+ var criteria = $"{GetTestName()}.{DocumentTypeName}.{Guid.NewGuid()}";
+ var documents = CreateTestDocuments(5);
+ var i = 1;
+ documents.ForEach(e =>
+ {
+ e.Nested.SomeDate = e.Nested.SomeDate.AddDays(i++);
+ e.Nested.SomeAmount = 5m;
+ e.SomeContent = criteria;
+ });
+ SUT.AddMany(documents);
+ var expectedSum = documents.Sum(e => e.Nested.SomeAmount);
+
+ // Act
+ var result = await SUT.SumByAsync(e => e.SomeContent == criteria, e => e.Nested.SomeAmount, PartitionKey);
+
+ // Assert
+ Assert.Equal(expectedSum, result);
+ }
+
+ #endregion Math
+
#region Test Utils
[MethodImpl(MethodImplOptions.NoInlining)]
private string GetCurrentMethod()
diff --git a/CoreIntegrationTests/Infrastructure/TestClasses.cs b/CoreIntegrationTests/Infrastructure/TestClasses.cs
index 20b7fc2..c9ad2b9 100644
--- a/CoreIntegrationTests/Infrastructure/TestClasses.cs
+++ b/CoreIntegrationTests/Infrastructure/TestClasses.cs
@@ -1,4 +1,5 @@
-using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization.Attributes;
using MongoDbGenericRepository.Models;
using MongoDbGenericRepository.Utils;
using System;
@@ -21,6 +22,8 @@ namespace CoreIntegrationTests.Infrastructure
public class Nested
{
public DateTime SomeDate { get; set; }
+ [BsonRepresentation(BsonType.Decimal128)]
+ public decimal SomeAmount { get; set; }
}
public class Child
diff --git a/MongoDbGenericRepository/Abstractions/IReadOnlyMongoRepository.cs b/MongoDbGenericRepository/Abstractions/IReadOnlyMongoRepository.cs
index 2632d66..a79d3e9 100644
--- a/MongoDbGenericRepository/Abstractions/IReadOnlyMongoRepository.cs
+++ b/MongoDbGenericRepository/Abstractions/IReadOnlyMongoRepository.cs
@@ -425,6 +425,34 @@ namespace MongoDbGenericRepository
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;
+
+ ///
+ /// 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;
+ #endregion Sum
}
}
diff --git a/MongoDbGenericRepository/BaseMongoDbRepository.cs b/MongoDbGenericRepository/BaseMongoDbRepository.cs
index 7a3a76e..f8c9c75 100644
--- a/MongoDbGenericRepository/BaseMongoDbRepository.cs
+++ b/MongoDbGenericRepository/BaseMongoDbRepository.cs
@@ -822,7 +822,7 @@ namespace MongoDbGenericRepository
///
/// The type representing a Document.
/// The type representing the model you want to project to.
- ///
+ /// A LINQ expression filter.
/// The projection expression.
/// An optional partition key.
public virtual async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null)
@@ -840,7 +840,7 @@ namespace MongoDbGenericRepository
/// The type representing a Document.
/// The type of the primary key for a Document.
/// The type representing the model you want to project to.
- ///
+ /// A LINQ expression filter.
/// The projection expression.
/// An optional partition key.
public virtual async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null)
@@ -849,8 +849,8 @@ namespace MongoDbGenericRepository
where TProjection : class
{
return await HandlePartitioned(partitionKey).Find(filter)
- .Project(projection)
- .FirstOrDefaultAsync();
+ .Project(projection)
+ .FirstOrDefaultAsync();
}
///
@@ -858,7 +858,7 @@ namespace MongoDbGenericRepository
///
/// The type representing a Document.
/// The type representing the model you want to project to.
- ///
+ /// A LINQ expression filter.
/// The projection expression.
/// An optional partition key.
public virtual TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null)
@@ -876,7 +876,7 @@ namespace MongoDbGenericRepository
/// The type representing a Document.
/// The type of the primary key for a Document.
/// The type representing the model you want to project to.
- ///
+ /// A LINQ expression filter.
/// The projection expression.
/// An optional partition key.
public virtual TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null)
@@ -885,8 +885,8 @@ namespace MongoDbGenericRepository
where TProjection : class
{
return HandlePartitioned(partitionKey).Find(filter)
- .Project(projection)
- .FirstOrDefault();
+ .Project(projection)
+ .FirstOrDefault();
}
///
@@ -894,7 +894,7 @@ namespace MongoDbGenericRepository
///
/// The type representing a Document.
/// The type representing the model you want to project to.
- ///
+ /// A LINQ expression filter.
/// The projection expression.
/// An optional partition key.
public virtual async Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null)
@@ -912,7 +912,7 @@ namespace MongoDbGenericRepository
/// The type representing a Document.
/// The type of the primary key for a Document.
/// The type representing the model you want to project to.
- ///
+ /// A LINQ expression filter.
/// The projection expression.
/// An optional partition key.
public virtual async Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null)
@@ -930,7 +930,7 @@ namespace MongoDbGenericRepository
///
/// The type representing a Document.
/// The type representing the model you want to project to.
- ///
+ /// A LINQ expression filter.
/// The projection expression.
/// An optional partition key.
public virtual List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null)
@@ -996,7 +996,7 @@ namespace MongoDbGenericRepository
/// The type representing a Document.
/// The type of the grouping criteria.
/// The type of the projected group.
- ///
+ /// A LINQ expression filter.
/// The grouping criteria.
/// The projected group result.
/// The partition key of your document, if any.
@@ -1021,11 +1021,47 @@ namespace MongoDbGenericRepository
/// Asynchronously returns a paginated list of the documents matching the filter condition.
///
/// The type representing a Document.
- ///
+ /// A LINQ expression filter.
+ /// The property selector.
+ /// Order of the sorting.
/// 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 virtual async Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null)
+ public virtual async Task> GetSortedPaginatedAsync(
+ Expression> filter,
+ Expression> sortSelector,
+ bool ascending = true,
+ int skipNumber = 0,
+ int takeNumber = 50,
+ string partitionKey = null)
+ where TDocument : IDocument
+ {
+ var sorting = ascending
+ ? Builders.Sort.Ascending(sortSelector)
+ : Builders.Sort.Descending(sortSelector);
+
+ return await HandlePartitioned(partitionKey)
+ .Find(filter)
+ .Sort(sorting)
+ .Skip(skipNumber)
+ .Limit(takeNumber)
+ .ToListAsync();
+ }
+
+
+ ///
+ /// Asynchronously returns a paginated list of the documents matching the filter condition.
+ ///
+ /// The type representing a Document.
+ /// A LINQ expression filter.
+ /// 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 virtual 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();
@@ -1036,7 +1072,7 @@ namespace MongoDbGenericRepository
///
/// The type representing a Document.
/// The type of the primary key for a Document.
- ///
+ /// A LINQ expression filter.
/// 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.
@@ -1053,7 +1089,7 @@ namespace MongoDbGenericRepository
/// GetAndUpdateOne with filter
///
/// The type representing a Document.
- ///
+ /// A LINQ expression filter.
///
///
///
@@ -1067,7 +1103,7 @@ namespace MongoDbGenericRepository
///
/// The type representing a Document.
/// The type of the primary key for a Document.
- ///
+ /// A LINQ expression filter.
///
///
///
diff --git a/MongoDbGenericRepository/ReadOnlyMongoRepository.Maths.cs b/MongoDbGenericRepository/ReadOnlyMongoRepository.Maths.cs
new file mode 100644
index 0000000..b75fe11
--- /dev/null
+++ b/MongoDbGenericRepository/ReadOnlyMongoRepository.Maths.cs
@@ -0,0 +1,52 @@
+using MongoDB.Driver;
+using MongoDB.Driver.Linq;
+using MongoDbGenericRepository.Models;
+using System;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+
+namespace MongoDbGenericRepository
+{
+ ///
+ /// 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 partial class ReadOnlyMongoRepository
+ {
+ ///
+ /// 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
+ {
+ return await 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 async Task SumByAsync(Expression> filter,
+ Expression> selector,
+ string partitionKey = null)
+ where TDocument : IDocument
+ where TKey : IEquatable
+ {
+ return await GetCollection(partitionKey)
+ .AsQueryable()
+ .Where(filter)
+ .SumAsync(selector);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/MongoDbGenericRepository/ReadOnlyMongoRepository.cs b/MongoDbGenericRepository/ReadOnlyMongoRepository.cs
index 0a8adb9..7638cdb 100644
--- a/MongoDbGenericRepository/ReadOnlyMongoRepository.cs
+++ b/MongoDbGenericRepository/ReadOnlyMongoRepository.cs
@@ -11,7 +11,7 @@ namespace MongoDbGenericRepository
///
/// The ReadOnlyMongoRepository implements the readonly functionality of the IReadOnlyMongoRepository.
///
- public class ReadOnlyMongoRepository : IReadOnlyMongoRepository
+ public abstract partial class ReadOnlyMongoRepository : IReadOnlyMongoRepository
{
///
/// The connection string.
@@ -578,7 +578,7 @@ namespace MongoDbGenericRepository
/// A LINQ expression filter.
/// A property selector to order by ascending.
/// An optional partition key.
- public async Task GetMinValueAsync(Expression> filter, Expression> minValueSelector, string partitionKey = null)
+ public virtual async Task GetMinValueAsync(Expression> filter, Expression> minValueSelector, string partitionKey = null)
where TDocument : IDocument
{
return await GetMinValueAsync(filter, minValueSelector, partitionKey);
@@ -593,7 +593,7 @@ namespace MongoDbGenericRepository
/// A LINQ expression filter.
/// A property selector to order by ascending.
/// An optional partition key.
- public async Task GetMinValueAsync(Expression> filter, Expression> minValueSelector, string partitionKey = null)
+ public virtual async Task GetMinValueAsync(Expression> filter, Expression> minValueSelector, string partitionKey = null)
where TDocument : IDocument
where TKey : IEquatable
{
@@ -608,7 +608,7 @@ namespace MongoDbGenericRepository
/// A LINQ expression filter.
/// A property selector to order by ascending.
/// An optional partition key.
- public TValue GetMinValue(Expression> filter, Expression> minValueSelector, string partitionKey = null)
+ public virtual TValue GetMinValue(Expression> filter, Expression> minValueSelector, string partitionKey = null)
where TDocument : IDocument
{
return GetMinValue(filter, minValueSelector, partitionKey);
@@ -623,7 +623,7 @@ namespace MongoDbGenericRepository
/// A LINQ expression filter.
/// A property selector to order by ascending.
/// An optional partition key.
- public TValue GetMinValue(Expression> filter, Expression> minValueSelector, string partitionKey = null)
+ public virtual TValue GetMinValue(Expression> filter, Expression> minValueSelector, string partitionKey = null)
where TDocument : IDocument
where TKey : IEquatable
{
@@ -640,7 +640,7 @@ namespace MongoDbGenericRepository
/// The document type.
/// An optional partition key.
/// An
- protected IMongoCollection GetCollection(string partitionKey = null) where TDocument : IDocument
+ protected virtual IMongoCollection GetCollection(string partitionKey = null) where TDocument : IDocument
{
return MongoDbContext.GetCollection(partitionKey);
}
@@ -651,7 +651,7 @@ namespace MongoDbGenericRepository
/// The document type.
/// The document.
///
- protected IMongoCollection HandlePartitioned(TDocument document) where TDocument : IDocument
+ protected virtual IMongoCollection HandlePartitioned(TDocument document) where TDocument : IDocument
{
if (document is IPartitionedDocument)
{
@@ -667,7 +667,7 @@ namespace MongoDbGenericRepository
/// The type of the primary key.
/// The document.
///
- protected IMongoCollection HandlePartitioned(TDocument document)
+ protected virtual IMongoCollection HandlePartitioned(TDocument document)
where TDocument : IDocument
where TKey : IEquatable
{
@@ -684,7 +684,7 @@ namespace MongoDbGenericRepository
/// The document type.
/// The collection partition key.
///
- protected IMongoCollection HandlePartitioned(string partitionKey) where TDocument : IDocument
+ protected virtual IMongoCollection HandlePartitioned(string partitionKey) where TDocument : IDocument
{
if (!string.IsNullOrEmpty(partitionKey))
{
@@ -700,7 +700,7 @@ namespace MongoDbGenericRepository
/// The type of the primary key.
/// The collection partition key.
///
- protected IMongoCollection GetCollection(string partitionKey = null)
+ protected virtual IMongoCollection GetCollection(string partitionKey = null)
where TDocument : IDocument
where TKey : IEquatable
{
@@ -714,7 +714,7 @@ namespace MongoDbGenericRepository
/// The type of the primary key.
/// The collection partition key.
///
- protected IMongoCollection HandlePartitioned(string partitionKey)
+ protected virtual IMongoCollection HandlePartitioned(string partitionKey)
where TDocument : IDocument
where TKey : IEquatable
{