From 1c40c08924b2e0bc3987d213f7405aaa9807c867 Mon Sep 17 00:00:00 2001 From: alexandre-spieser Date: Sun, 27 Aug 2017 22:07:59 +0000 Subject: [PATCH] projection functionality --- IntegrationTests/IntegrationTests.csproj | 1 + IntegrationTests/ProjectTests.cs | 148 ++++++++++++++++++ MongoDbGenericRepository/MongoDbRepository.cs | 112 ++++++++++++- 3 files changed, 256 insertions(+), 5 deletions(-) create mode 100644 IntegrationTests/ProjectTests.cs diff --git a/IntegrationTests/IntegrationTests.csproj b/IntegrationTests/IntegrationTests.csproj index a3ec14a..81ca024 100644 --- a/IntegrationTests/IntegrationTests.csproj +++ b/IntegrationTests/IntegrationTests.csproj @@ -63,6 +63,7 @@ + diff --git a/IntegrationTests/ProjectTests.cs b/IntegrationTests/ProjectTests.cs new file mode 100644 index 0000000..971fd22 --- /dev/null +++ b/IntegrationTests/ProjectTests.cs @@ -0,0 +1,148 @@ +using IntegrationTests.Infrastructure; +using MongoDbGenericRepository.Models; +using NUnit.Framework; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace IntegrationTests +{ + public class Nested + { + public DateTime SomeDate { get; set; } + + } + + public class ProjectTestsDocument : Document + { + public ProjectTestsDocument() + { + Version = 2; + Nested = new Nested + { + SomeDate = DateTime.UtcNow + }; + } + + public string SomeContent { get; set; } + + public Nested Nested { get; set; } + } + + public class ProjectTests : BaseMongoDbRepositoryTests + { + private class MyProjection + { + public DateTime SomeDate { get; set; } + public string SomeContent { get; set; } + } + + [Test] + public async Task ProjectOneAsync() + { + // Arrange + const string someContent = "ProjectOneAsyncContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocument(); + document.SomeContent = someContent; + document.Nested.SomeDate = someDate; + SUT.AddOne(document); + // Act + var result = await SUT.ProjectOneAsync( + x => x.Id == document.Id, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }); + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(someContent, result.SomeContent); + Assert.AreEqual(someDate.Minute, result.SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.SomeDate.Second); + } + + [Test] + public void ProjectOne() + { + // Arrange + const string someContent = "ProjectOneContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocument(); + document.SomeContent = someContent; + document.Nested.SomeDate = someDate; + SUT.AddOne(document); + // Act + var result = SUT.ProjectOne( + x => x.Id == document.Id, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }); + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(someContent, result.SomeContent); + Assert.AreEqual(someDate.Minute, result.SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.SomeDate.Second); + } + + [Test] + public async Task ProjectManyAsync() + { + // Arrange + const string someContent = "ProjectManyAsyncContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocuments(5); + document.ForEach(e => + { + e.SomeContent = someContent; + e.Nested.SomeDate = someDate; + }); + + SUT.AddMany(document); + // Act + var result = await SUT.ProjectManyAsync( + x => x.SomeContent == someContent, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }); + // Assert + Assert.AreEqual(5, result.Count); + Assert.AreEqual(someContent, result.First().SomeContent); + Assert.AreEqual(someDate.Minute, result.First().SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.First().SomeDate.Second); + } + + [Test] + public void ProjectMany() + { + // Arrange + const string someContent = "ProjectManyContent"; + var someDate = DateTime.UtcNow; + var document = CreateTestDocuments(5); + document.ForEach(e => + { + e.SomeContent = someContent; + e.Nested.SomeDate = someDate; + }); + + SUT.AddMany(document); + // Act + var result = SUT.ProjectMany( + x => x.SomeContent == someContent, + x => new MyProjection + { + SomeContent = x.SomeContent, + SomeDate = x.Nested.SomeDate + }); + // Assert + Assert.AreEqual(5, result.Count); + Assert.AreEqual(someContent, result.First().SomeContent); + Assert.AreEqual(someDate.Minute, result.First().SomeDate.Minute); + Assert.AreEqual(someDate.Second, result.First().SomeDate.Second); + } + } +} diff --git a/MongoDbGenericRepository/MongoDbRepository.cs b/MongoDbGenericRepository/MongoDbRepository.cs index f00ff93..ba44ee4 100644 --- a/MongoDbGenericRepository/MongoDbRepository.cs +++ b/MongoDbGenericRepository/MongoDbRepository.cs @@ -227,6 +227,58 @@ namespace MongoDbGenericRepository #endregion + #region Project + + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// + /// + /// + /// The projection expression. + /// An optional partition key. + Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Returns a projected document matching the filter condition. + /// + /// + /// + /// + /// The projection expression. + /// An optional partition key. + TProjection ProjectOne(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 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 projection expression. + /// An optional partition key. + List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + #endregion + } /// @@ -577,27 +629,77 @@ namespace MongoDbGenericRepository #endregion Delete - #region Projection + #region Project /// - /// Asynchronously returns a list of projected document matching the filter condition. + /// Asynchronously returns a projected document matching the filter condition. /// /// /// /// /// The projection expression. /// An optional partition key. - public async Task GetProjectedAsync(Expression> filter, Expression> projection, string partitionKey = null) + public async Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) where TDocument : IDocument - where TProjection : class, new() + where TProjection : class { return await HandlePartitioned(partitionKey).Find(filter) .Project(projection) .FirstOrDefaultAsync(); } - #endregion + /// + /// Returns a projected document matching the filter condition. + /// + /// + /// + /// + /// 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(); + } + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// + /// + /// + /// 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 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(); + } + + #endregion /// /// Asynchronously returns a paginated list of the documents matching the filter condition.