diff --git a/src/DotNetToolkit.Repository/Queries/IQueryOptions.cs b/src/DotNetToolkit.Repository/Queries/IQueryOptions.cs new file mode 100644 index 00000000..6e3f8604 --- /dev/null +++ b/src/DotNetToolkit.Repository/Queries/IQueryOptions.cs @@ -0,0 +1,18 @@ +namespace DotNetToolkit.Repository.Queries +{ + using System.Linq; + + /// + /// Represents a query options which can be used for sorting or paging on queries. + /// + /// The entity type of the repository. + public interface IQueryOptions + { + /// + /// Applies the current options to the specified query. + /// + /// The query. + /// The new query with the defined options applied. + IQueryable Apply(IQueryable query); + } +} diff --git a/src/DotNetToolkit.Repository/Queries/PagingOptions.cs b/src/DotNetToolkit.Repository/Queries/PagingOptions.cs new file mode 100644 index 00000000..110097a5 --- /dev/null +++ b/src/DotNetToolkit.Repository/Queries/PagingOptions.cs @@ -0,0 +1,113 @@ +namespace DotNetToolkit.Repository.Queries +{ + using System; + using System.Linq; + using System.Linq.Expressions; + + /// + /// Represents a paging option. + /// + /// The entity type of the repository. + /// The type of the property that is being sorted. + public class PagingOptions : SortingOptions + { + #region Fields + + private const int DefaultPageSize = 100; + private int _pageIndex; + private int _pageSize; + + #endregion + + #region Properties + + /// + /// Gets or sets the number of rows of the data page to retrieve. + /// + public int PageSize + { + get { return _pageSize; } + set + { + if (value <= 0) + throw new ArgumentException($"{nameof(PageSize)} cannot be lower than zero."); + + _pageSize = value; + } + } + + /// + /// Gets or sets the zero-based index of the data page to retrieve. + /// + public int PageIndex + { + get { return _pageIndex; } + set + { + if (value < 1) + throw new ArgumentOutOfRangeException(nameof(PageIndex), "Cannot be lower than 1."); + + _pageIndex = value; + } + } + + /// + /// Gets the page count. + /// + public int PageCount { get; private set; } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The zero-based index of the data page to retrieve. + /// The sorting expression. + /// if set to true use descending order; otherwise, use ascending. + public PagingOptions(int pageIndex, Expression> sorting, bool isDescending = false) : base(sorting, isDescending) + { + PageIndex = pageIndex; + PageSize = DefaultPageSize; + } + + /// + /// Initializes a new instance of the class. + /// + /// The zero-based index of the data page to retrieve. + /// The number of rows of the data page to retrieve. + /// The sorting expression. + /// if set to true use descending order; otherwise, use ascending. + public PagingOptions(int pageIndex, int pageSize, Expression> sorting, bool isDescending = false) : base(sorting, isDescending) + { + PageIndex = pageIndex; + PageSize = pageSize; + } + + #endregion + + #region Overrides of SortingOptions + + /// + /// Applies the current options to the specified query. + /// + /// The query. + /// The new query with the defined options applied. + public override IQueryable Apply(IQueryable query) + { + var pageCount = (int)Math.Ceiling(query.Count() / (decimal)PageSize); + + if (PageIndex > pageCount) + throw new ArgumentOutOfRangeException(nameof(PageIndex), "Cannot be greater than the total number of pages."); + + PageCount = pageCount; + + query = base.Apply(query); + + return query.Skip((PageIndex - 1) * PageSize).Take(PageSize); + } + + #endregion + } +} diff --git a/src/DotNetToolkit.Repository/Queries/SortingOptions.cs b/src/DotNetToolkit.Repository/Queries/SortingOptions.cs new file mode 100644 index 00000000..dc0cc27c --- /dev/null +++ b/src/DotNetToolkit.Repository/Queries/SortingOptions.cs @@ -0,0 +1,69 @@ +namespace DotNetToolkit.Repository.Queries +{ + using System; + using System.Linq; + using System.Linq.Expressions; + + /// + /// Represents a sorting option. + /// + /// The entity type of the repository. + /// The type of the property that is being sorted. + public class SortingOptions : IQueryOptions + { + #region Fields + + private readonly Expression> _sorting; + + #endregion + + #region Properties + + /// + /// Gets or sets a value indicating whether this sorting option is descending. + /// + /// + /// true if this sorting option is descending; otherwise, false. + /// + public bool IsDescending { get; set; } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The sorting expression. + /// if set to true use descending order; otherwise, use ascending. + public SortingOptions(Expression> sorting, bool isDescending = false) + { + _sorting = sorting; + + IsDescending = isDescending; + } + + #endregion + + #region Implementation of IQueryOptions + + /// + /// Applies the current options to the specified query. + /// + /// The query. + /// The new query with the defined options applied. + public virtual IQueryable Apply(IQueryable query) + { + if (_sorting != null) + { + query = IsDescending + ? query.OrderByDescending(_sorting) + : query.OrderBy(_sorting); + } + + return query; + } + + #endregion + } +} diff --git a/src/DotNetToolkit.Repository/RepositoryBase.cs b/src/DotNetToolkit.Repository/RepositoryBase.cs index a98c5549..31b57f08 100644 --- a/src/DotNetToolkit.Repository/RepositoryBase.cs +++ b/src/DotNetToolkit.Repository/RepositoryBase.cs @@ -2,6 +2,7 @@ { using FetchStrategies; using Helpers; + using Queries; using Specifications; using System; using System.Collections.Generic; @@ -62,13 +63,13 @@ protected virtual IQueryable AsQueryable() /// protected virtual TEntity GetQuery(TKey key, IFetchStrategy fetchStrategy) { - return (TEntity)GetQuery(ByPrimaryKeySpecification(key, fetchStrategy)); + return GetQuery(ByPrimaryKeySpecification(key, fetchStrategy)); } /// /// Gets an entity query with the given primary key value from the repository. /// - protected virtual TEntity GetQuery(TKey key) + protected TEntity GetQuery(TKey key) { return Get(key, (IFetchStrategy)null); } @@ -76,23 +77,40 @@ protected virtual TEntity GetQuery(TKey key) /// /// Gets an entity query that satisfies the criteria specified by the from the repository. /// - protected virtual IQueryable GetQuery(ISpecification criteria) + protected TEntity GetQuery(ISpecification criteria) + { + var query = GetQuery(criteria.FetchStrategy); + + return criteria.SatisfyingEntityFrom(query); + } + + /// + /// Gets an entity query that satisfies the criteria specified by the from the repository. + /// + protected IQueryable GetQuery(ISpecification criteria, IQueryOptions options) { if (criteria == null) throw new ArgumentNullException(nameof(criteria)); - return GetQuery(criteria.FetchStrategy); + var query = GetQuery(criteria.FetchStrategy); + + query = criteria.SatisfyingEntitiesFrom(query); + + if (options != null) + query = options.Apply(query); + + return query; } /// /// Gets an entity query that satisfies the criteria specified by the from the repository. /// - protected virtual IQueryable GetQuery(Expression> predicate) + protected IQueryable GetQuery(Expression> predicate, IQueryOptions options) { if (predicate == null) throw new ArgumentNullException(nameof(predicate)); - return GetQuery(new Specification(predicate)); + return GetQuery(new Specification(predicate), options); } /// @@ -134,7 +152,7 @@ protected virtual ISpecification ByPrimaryKeySpecification(TKey key, IF /// The number of entities contained in the repository. public int Count() { - return GetQuery().Count(); + return Count((ISpecification)null); } /// @@ -144,7 +162,9 @@ public int Count() /// The number of entities that satisfied the criteria specified by the in the repository. public int Count(ISpecification criteria) { - return GetQuery(criteria).Count(); + var predicate = criteria?.Predicate?.Compile(); + + return predicate == null ? GetQuery().Count() : GetQuery().Count(predicate); } /// @@ -154,7 +174,7 @@ public int Count(ISpecification criteria) /// The number of entities that satisfied the criteria specified by the in the repository. public int Count(Expression> predicate) { - return GetQuery(predicate == null ? null : new Specification(predicate)).Count(); + return Count(predicate == null ? null : new Specification(predicate)); } #endregion @@ -390,26 +410,28 @@ public bool Exists(TKey key) /// Finds the first entity in the repository that satisfies the criteria specified by the in the repository. /// /// A function to filter each entity. + /// The options to apply to the query. /// The entity that satisfied the criteria specified by the in the repository. - public TEntity Find(Expression> predicate) + public TEntity Find(Expression> predicate, IQueryOptions options = null) { if (predicate == null) throw new ArgumentNullException(nameof(predicate)); - return GetQuery(predicate).FirstOrDefault(); + return GetQuery(predicate, options).FirstOrDefault(); } /// /// Finds the first entity in the repository that satisfies the criteria specified by the in the repository. /// /// The specification criteria that is used for matching entities against. + /// The options to apply to the query. /// The entity that satisfied the criteria specified by the in the repository. - public TEntity Find(ISpecification criteria) + public TEntity Find(ISpecification criteria, IQueryOptions options = null) { if (criteria == null) throw new ArgumentNullException(nameof(criteria)); - return GetQuery(criteria).FirstOrDefault(); + return GetQuery(criteria, options).FirstOrDefault(); } /// @@ -417,8 +439,9 @@ public TEntity Find(ISpecification criteria) /// /// A function to filter each entity. /// A function to project each entity into a new form. + /// The options to apply to the query. /// The projected entity result that satisfied the criteria specified by the in the repository. - public TResult Find(Expression> predicate, Expression> selector) + public TResult Find(Expression> predicate, Expression> selector, IQueryOptions options = null) { if (predicate == null) throw new ArgumentNullException(nameof(predicate)); @@ -426,7 +449,7 @@ public TResult Find(Expression> predicate, Expressi if (selector == null) throw new ArgumentNullException(nameof(selector)); - return GetQuery(predicate).Select(selector).FirstOrDefault(); + return GetQuery(predicate, options).Select(selector).FirstOrDefault(); } /// @@ -434,8 +457,9 @@ public TResult Find(Expression> predicate, Expressi /// /// The specification criteria that is used for matching entities against. /// A function to project each entity into a new form. + /// The options to apply to the query. /// The projected entity result that satisfied the criteria specified by the in the repository. - public TResult Find(ISpecification criteria, Expression> selector) + public TResult Find(ISpecification criteria, Expression> selector, IQueryOptions options = null) { if (criteria == null) throw new ArgumentNullException(nameof(criteria)); @@ -443,33 +467,35 @@ public TResult Find(ISpecification criteria, Expression /// Finds the collection of entities in the repository that satisfied the criteria specified by the . /// /// A function to filter each entity. + /// The options to apply to the query. /// The collection of entities in the repository that satisfied the criteria specified by the . - public IEnumerable FindAll(Expression> predicate) + public IEnumerable FindAll(Expression> predicate, IQueryOptions options = null) { if (predicate == null) throw new ArgumentNullException(nameof(predicate)); - return GetQuery(predicate).ToList(); + return GetQuery(predicate, options).ToList(); } /// /// Finds the collection of entities in the repository that satisfied the criteria specified by the . /// /// The specification criteria that is used for matching entities against. + /// The options to apply to the query. /// The collection of entities in the repository that satisfied the criteria specified by the . - public IEnumerable FindAll(ISpecification criteria) + public IEnumerable FindAll(ISpecification criteria, IQueryOptions options = null) { if (criteria == null) throw new ArgumentNullException(nameof(criteria)); - return GetQuery(criteria).ToList(); + return GetQuery(criteria, options).ToList(); } /// @@ -477,8 +503,9 @@ public IEnumerable FindAll(ISpecification criteria) /// /// A function to filter each entity. /// A function to project each entity into a new form. + /// The options to apply to the query. /// The collection of projected entity results in the repository that satisfied the criteria specified by the . - public IEnumerable FindAll(Expression> predicate, Expression> selector) + public IEnumerable FindAll(Expression> predicate, Expression> selector, IQueryOptions options = null) { if (predicate == null) throw new ArgumentNullException(nameof(predicate)); @@ -486,7 +513,7 @@ public IEnumerable FindAll(Expression> pre if (selector == null) throw new ArgumentNullException(nameof(selector)); - return GetQuery(predicate).Select(selector).ToList(); + return GetQuery(predicate, options).Select(selector).ToList(); } /// @@ -494,8 +521,9 @@ public IEnumerable FindAll(Expression> pre /// /// The specification criteria that is used for matching entities against. /// A function to project each entity into a new form. + /// The options to apply to the query. /// The collection of projected entity results in the repository that satisfied the criteria specified by the . - public IEnumerable FindAll(ISpecification criteria, Expression> selector) + public IEnumerable FindAll(ISpecification criteria, Expression> selector, IQueryOptions options = null) { if (criteria == null) throw new ArgumentNullException(nameof(criteria)); @@ -503,7 +531,7 @@ public IEnumerable FindAll(ISpecification criteria, E if (selector == null) throw new ArgumentNullException(nameof(selector)); - return GetQuery(criteria).Select(selector).ToList(); + return GetQuery(criteria, options).Select(selector).ToList(); } /// diff --git a/src/DotNetToolkit.Repository/Traits/ICanFind.cs b/src/DotNetToolkit.Repository/Traits/ICanFind.cs index a2b4ebb0..72f1b1e2 100644 --- a/src/DotNetToolkit.Repository/Traits/ICanFind.cs +++ b/src/DotNetToolkit.Repository/Traits/ICanFind.cs @@ -1,5 +1,6 @@ namespace DotNetToolkit.Repository.Traits { + using Queries; using Specifications; using System; using System.Collections.Generic; @@ -15,61 +16,69 @@ public interface ICanFind where TEntity : class /// Finds the first entity in the repository that satisfies the criteria specified by the in the repository. /// /// A function to filter each entity. + /// The options to apply to the query. /// The entity that satisfied the criteria specified by the in the repository. - TEntity Find(Expression> predicate); + TEntity Find(Expression> predicate, IQueryOptions options = null); /// /// Finds the first entity in the repository that satisfies the criteria specified by the in the repository. /// /// The specification criteria that is used for matching entities against. + /// The options to apply to the query. /// The entity that satisfied the criteria specified by the in the repository. - TEntity Find(ISpecification criteria); + TEntity Find(ISpecification criteria, IQueryOptions options = null); /// /// Finds the first projected entity result in the repository that satisfies the criteria specified by the in the repository. /// /// A function to filter each entity. /// A function to project each entity into a new form. + /// The options to apply to the query. /// The projected entity result that satisfied the criteria specified by the in the repository. - TResult Find(Expression> predicate, Expression> selector); + TResult Find(Expression> predicate, Expression> selector, IQueryOptions options = null); /// /// Finds the first projected entity result in the repository that satisfies the criteria specified by the in the repository. /// /// The specification criteria that is used for matching entities against. /// A function to project each entity into a new form. + /// The options to apply to the query. /// The projected entity result that satisfied the criteria specified by the in the repository. - TResult Find(ISpecification criteria, Expression> selector); + TResult Find(ISpecification criteria, Expression> selector, IQueryOptions options = null); /// /// Finds the collection of entities in the repository that satisfied the criteria specified by the . /// /// A function to filter each entity. + /// The options to apply to the query. /// The collection of entities in the repository that satisfied the criteria specified by the . - IEnumerable FindAll(Expression> predicate); + IEnumerable FindAll(Expression> predicate, IQueryOptions options = null); /// /// Finds the collection of entities in the repository that satisfied the criteria specified by the . /// /// The specification criteria that is used for matching entities against. + /// The options to apply to the query. /// The collection of entities in the repository that satisfied the criteria specified by the . - IEnumerable FindAll(ISpecification criteria); + IEnumerable FindAll(ISpecification criteria, IQueryOptions options = null); /// /// Finds the collection of projected entity results in the repository that satisfied the criteria specified by the . /// /// A function to filter each entity. /// A function to project each entity into a new form. + /// The options to apply to the query. /// The collection of projected entity results in the repository that satisfied the criteria specified by the . - IEnumerable FindAll(Expression> predicate, Expression> selector); + IEnumerable FindAll(Expression> predicate, Expression> selector, IQueryOptions options = null); /// /// Finds the collection of projected entity results in the repository that satisfied the criteria specified by the . /// /// The specification criteria that is used for matching entities against. /// A function to project each entity into a new form. + /// The options to apply to the query. /// The collection of projected entity results in the repository that satisfied the criteria specified by the . - IEnumerable FindAll(ISpecification criteria, Expression> selector); + IEnumerable FindAll(ISpecification criteria, Expression> selector, IQueryOptions options = null); /// /// Determines whether the repository contains an entity that match the conditions defined by the specified by the . diff --git a/test/DotNetToolkit.Repository.Integration.Test/EfRepositoryTests.cs b/test/DotNetToolkit.Repository.Integration.Test/EfRepositoryTests.cs index 40e7b82d..d13199fc 100644 --- a/test/DotNetToolkit.Repository.Integration.Test/EfRepositoryTests.cs +++ b/test/DotNetToolkit.Repository.Integration.Test/EfRepositoryTests.cs @@ -2,8 +2,10 @@ { using Data; using EntityFramework; + using Queries; using Specifications; using System.Collections.Generic; + using System.Linq; using Xunit; public class EfRepositoryTests @@ -177,6 +179,64 @@ public void Find() } } + [Fact] + public void Find_With_Sorting_Options_Ascending() + { + using (var context = TestDbContextFactory.Create()) + { + var entities = new List + { + new Customer { Name = "Random Name 2" }, + new Customer { Name = "Random Name 1" } + }; + + var spec = new Specification(x => x.Name.Contains("Random Name")); + var queryOptions = new SortingOptions(x => x.Name, true); + var repo = new EfRepository(context); + + Assert.Null(repo.Find(x => x.Name.Contains("Random Name"), queryOptions)?.Name); + Assert.Null(repo.Find(spec, queryOptions)?.Name); + Assert.Null(repo.Find(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions)); + Assert.Null(repo.Find(spec, x => x.Name, queryOptions)); + + repo.Add(entities); + + Assert.Equal("Random Name 2", repo.Find(x => x.Name.Contains("Random Name"), queryOptions).Name); + Assert.Equal("Random Name 2", repo.Find(spec, queryOptions).Name); + Assert.Equal("Random Name 2", repo.Find(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions)); + Assert.Equal("Random Name 2", repo.Find(spec, x => x.Name, queryOptions)); + } + } + + [Fact] + public void Find_With_Sorting_Options_Descending() + { + using (var context = TestDbContextFactory.Create()) + { + var entities = new List + { + new Customer { Name = "Random Name 2" }, + new Customer { Name = "Random Name 1" } + }; + + var spec = new Specification(x => x.Name.Contains("Random Name")); + var queryOptions = new SortingOptions(x => x.Name); + var repo = new EfRepository(context); + + Assert.Null(repo.Find(x => x.Name.Contains("Random Name"), queryOptions)?.Name); + Assert.Null(repo.Find(spec, queryOptions)?.Name); + Assert.Null(repo.Find(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions)); + Assert.Null(repo.Find(spec, x => x.Name, queryOptions)); + + repo.Add(entities); + + Assert.Equal("Random Name 1", repo.Find(x => x.Name.Contains("Random Name"), queryOptions).Name); + Assert.Equal("Random Name 1", repo.Find(spec, queryOptions).Name); + Assert.Equal("Random Name 1", repo.Find(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions)); + Assert.Equal("Random Name 1", repo.Find(spec, x => x.Name, queryOptions)); + } + } + [Fact] public void FindAll() { @@ -202,6 +262,200 @@ public void FindAll() } } + [Fact] + public void FindAll_With_Sorting_Options_Ascending() + { + using (var context = TestDbContextFactory.Create()) + { + var entities = new List + { + new Customer { Name = "Random Name 2" }, + new Customer { Name = "Random Name 1" } + }; + + var spec = new Specification(x => x.Name.Contains("Random Name")); + var queryOptions = new SortingOptions(x => x.Name, true); + var repo = new EfRepository(context); + + Assert.Null(repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions).FirstOrDefault()?.Name); + Assert.Null(repo.FindAll(spec, queryOptions).FirstOrDefault()?.Name); + Assert.Null(repo.FindAll(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions).FirstOrDefault()); + Assert.Null(repo.FindAll(spec, x => x.Name, queryOptions).FirstOrDefault()); + + repo.Add(entities); + + Assert.Equal("Random Name 2", repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions).First().Name); + Assert.Equal("Random Name 2", repo.FindAll(spec, queryOptions).First().Name); + Assert.Equal("Random Name 2", repo.FindAll(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions).First()); + Assert.Equal("Random Name 2", repo.FindAll(spec, x => x.Name, queryOptions).First()); + } + } + + [Fact] + public void FindAll_With_Sorting_Options_Descending() + { + using (var context = TestDbContextFactory.Create()) + { + var entities = new List + { + new Customer { Name = "Random Name 2" }, + new Customer { Name = "Random Name 1" } + }; + + var spec = new Specification(x => x.Name.Contains("Random Name")); + var queryOptions = new SortingOptions(x => x.Name); + var repo = new EfRepository(context); + + Assert.Null(repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions).FirstOrDefault()?.Name); + Assert.Null(repo.FindAll(spec, queryOptions).FirstOrDefault()?.Name); + Assert.Null(repo.FindAll(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions).FirstOrDefault()); + Assert.Null(repo.FindAll(spec, x => x.Name, queryOptions).FirstOrDefault()); + + repo.Add(entities); + + Assert.Equal("Random Name 1", repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions).First().Name); + Assert.Equal("Random Name 1", repo.FindAll(spec, queryOptions).First().Name); + Assert.Equal("Random Name 1", repo.FindAll(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions).First()); + Assert.Equal("Random Name 1", repo.FindAll(spec, x => x.Name, queryOptions).First()); + } + } + + [Fact] + public void FindAll_With_Paging_Options_Sort_Ascending() + { + using (var context = TestDbContextFactory.Create()) + { + var entities = new List(); + + for (var i = 0; i < 21; i++) + { + entities.Add(new Customer { Name = "Random Name " + i }); + } + + var repo = new EfRepository(context); + + repo.Add(entities); + + var queryOptions = new PagingOptions(1, 5, x => x.Id); + var entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions); + + Assert.Equal(5, entitiesInDb.Count()); + Assert.Equal("Random Name 0", entitiesInDb.ElementAt(0).Name); + Assert.Equal("Random Name 1", entitiesInDb.ElementAt(1).Name); + Assert.Equal("Random Name 2", entitiesInDb.ElementAt(2).Name); + Assert.Equal("Random Name 3", entitiesInDb.ElementAt(3).Name); + Assert.Equal("Random Name 4", entitiesInDb.ElementAt(4).Name); + + queryOptions.PageIndex = 2; + + entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions); + + Assert.Equal(5, entitiesInDb.Count()); + Assert.Equal("Random Name 5", entitiesInDb.ElementAt(0).Name); + Assert.Equal("Random Name 6", entitiesInDb.ElementAt(1).Name); + Assert.Equal("Random Name 7", entitiesInDb.ElementAt(2).Name); + Assert.Equal("Random Name 8", entitiesInDb.ElementAt(3).Name); + Assert.Equal("Random Name 9", entitiesInDb.ElementAt(4).Name); + + queryOptions.PageIndex = 3; + + entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions); + + Assert.Equal(5, entitiesInDb.Count()); + Assert.Equal("Random Name 10", entitiesInDb.ElementAt(0).Name); + Assert.Equal("Random Name 11", entitiesInDb.ElementAt(1).Name); + Assert.Equal("Random Name 12", entitiesInDb.ElementAt(2).Name); + Assert.Equal("Random Name 13", entitiesInDb.ElementAt(3).Name); + Assert.Equal("Random Name 14", entitiesInDb.ElementAt(4).Name); + + queryOptions.PageIndex = 4; + + entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions); + + Assert.Equal(5, entitiesInDb.Count()); + Assert.Equal("Random Name 15", entitiesInDb.ElementAt(0).Name); + Assert.Equal("Random Name 16", entitiesInDb.ElementAt(1).Name); + Assert.Equal("Random Name 17", entitiesInDb.ElementAt(2).Name); + Assert.Equal("Random Name 18", entitiesInDb.ElementAt(3).Name); + Assert.Equal("Random Name 19", entitiesInDb.ElementAt(4).Name); + + queryOptions.PageIndex = 5; + + entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions); + + Assert.Single(entitiesInDb); + Assert.Equal("Random Name 20", entitiesInDb.ElementAt(0).Name); + } + } + + [Fact] + public void FindAll_With_Paging_Options_Sort_Descending() + { + using (var context = TestDbContextFactory.Create()) + { + var entities = new List(); + + for (var i = 0; i < 21; i++) + { + entities.Add(new Customer { Name = "Random Name " + i }); + } + + var repo = new EfRepository(context); + + repo.Add(entities); + + var queryOptions = new PagingOptions(1, 5, x => x.Id, true); + var entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions); + + Assert.Equal(5, entitiesInDb.Count()); + Assert.Equal("Random Name 20", entitiesInDb.ElementAt(0).Name); + Assert.Equal("Random Name 19", entitiesInDb.ElementAt(1).Name); + Assert.Equal("Random Name 18", entitiesInDb.ElementAt(2).Name); + Assert.Equal("Random Name 17", entitiesInDb.ElementAt(3).Name); + Assert.Equal("Random Name 16", entitiesInDb.ElementAt(4).Name); + + queryOptions.PageIndex = 2; + + entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions); + + Assert.Equal(5, entitiesInDb.Count()); + Assert.Equal("Random Name 15", entitiesInDb.ElementAt(0).Name); + Assert.Equal("Random Name 14", entitiesInDb.ElementAt(1).Name); + Assert.Equal("Random Name 13", entitiesInDb.ElementAt(2).Name); + Assert.Equal("Random Name 12", entitiesInDb.ElementAt(3).Name); + Assert.Equal("Random Name 11", entitiesInDb.ElementAt(4).Name); + + queryOptions.PageIndex = 3; + + entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions); + + Assert.Equal(5, entitiesInDb.Count()); + Assert.Equal("Random Name 10", entitiesInDb.ElementAt(0).Name); + Assert.Equal("Random Name 9", entitiesInDb.ElementAt(1).Name); + Assert.Equal("Random Name 8", entitiesInDb.ElementAt(2).Name); + Assert.Equal("Random Name 7", entitiesInDb.ElementAt(3).Name); + Assert.Equal("Random Name 6", entitiesInDb.ElementAt(4).Name); + + queryOptions.PageIndex = 4; + + entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions); + + Assert.Equal(5, entitiesInDb.Count()); + Assert.Equal("Random Name 5", entitiesInDb.ElementAt(0).Name); + Assert.Equal("Random Name 4", entitiesInDb.ElementAt(1).Name); + Assert.Equal("Random Name 3", entitiesInDb.ElementAt(2).Name); + Assert.Equal("Random Name 2", entitiesInDb.ElementAt(3).Name); + Assert.Equal("Random Name 1", entitiesInDb.ElementAt(4).Name); + + queryOptions.PageIndex = 5; + + entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions); + + Assert.Single(entitiesInDb); + Assert.Equal("Random Name 0", entitiesInDb.ElementAt(0).Name); + } + } + [Fact] public void Get() { diff --git a/test/DotNetToolkit.Repository.Test/PagingOptionsTests.cs b/test/DotNetToolkit.Repository.Test/PagingOptionsTests.cs new file mode 100644 index 00000000..b274d2c9 --- /dev/null +++ b/test/DotNetToolkit.Repository.Test/PagingOptionsTests.cs @@ -0,0 +1,133 @@ +namespace DotNetToolkit.Repository.Test +{ + using Data; + using Queries; + using System.Collections.Generic; + using System.Linq; + using Xunit; + + public class PagingOptionsTests + { + [Fact] + public void Page_With_Sort__Ascending() + { + var entities = new List(); + + for (var i = 0; i < 21; i++) + { + entities.Add(new Customer { Id = i, Name = "Random Name " + i }); + } + + var queryOptions = new PagingOptions(1, 5, x => x.Id); + var queryable = queryOptions.Apply(entities.AsQueryable()); + + Assert.Equal(5, queryable.Count()); + Assert.Equal("Random Name 0", queryable.ElementAt(0).Name); + Assert.Equal("Random Name 1", queryable.ElementAt(1).Name); + Assert.Equal("Random Name 2", queryable.ElementAt(2).Name); + Assert.Equal("Random Name 3", queryable.ElementAt(3).Name); + Assert.Equal("Random Name 4", queryable.ElementAt(4).Name); + + queryOptions.PageIndex = 2; + + queryable = queryOptions.Apply(entities.AsQueryable()); + + Assert.Equal(5, queryable.Count()); + Assert.Equal("Random Name 5", queryable.ElementAt(0).Name); + Assert.Equal("Random Name 6", queryable.ElementAt(1).Name); + Assert.Equal("Random Name 7", queryable.ElementAt(2).Name); + Assert.Equal("Random Name 8", queryable.ElementAt(3).Name); + Assert.Equal("Random Name 9", queryable.ElementAt(4).Name); + + queryOptions.PageIndex = 3; + + queryable = queryOptions.Apply(entities.AsQueryable()); + + Assert.Equal(5, queryable.Count()); + Assert.Equal("Random Name 10", queryable.ElementAt(0).Name); + Assert.Equal("Random Name 11", queryable.ElementAt(1).Name); + Assert.Equal("Random Name 12", queryable.ElementAt(2).Name); + Assert.Equal("Random Name 13", queryable.ElementAt(3).Name); + Assert.Equal("Random Name 14", queryable.ElementAt(4).Name); + + queryOptions.PageIndex = 4; + + queryable = queryOptions.Apply(entities.AsQueryable()); + + Assert.Equal(5, queryable.Count()); + Assert.Equal("Random Name 15", queryable.ElementAt(0).Name); + Assert.Equal("Random Name 16", queryable.ElementAt(1).Name); + Assert.Equal("Random Name 17", queryable.ElementAt(2).Name); + Assert.Equal("Random Name 18", queryable.ElementAt(3).Name); + Assert.Equal("Random Name 19", queryable.ElementAt(4).Name); + + queryOptions.PageIndex = 5; + + queryable = queryOptions.Apply(entities.AsQueryable()); + + Assert.Single(queryable); + Assert.Equal("Random Name 20", queryable.ElementAt(0).Name); + } + + [Fact] + public void Page_With_Sort_Descending() + { + var entities = new List(); + + for (var i = 0; i < 21; i++) + { + entities.Add(new Customer { Id = i, Name = "Random Name " + i }); + } + + var queryOptions = new PagingOptions(1, 5, x => x.Id, true); + var queryable = queryOptions.Apply(entities.AsQueryable()); + + Assert.Equal(5, queryable.Count()); + Assert.Equal("Random Name 20", queryable.ElementAt(0).Name); + Assert.Equal("Random Name 19", queryable.ElementAt(1).Name); + Assert.Equal("Random Name 18", queryable.ElementAt(2).Name); + Assert.Equal("Random Name 17", queryable.ElementAt(3).Name); + Assert.Equal("Random Name 16", queryable.ElementAt(4).Name); + + queryOptions.PageIndex = 2; + + queryable = queryOptions.Apply(entities.AsQueryable()); + + Assert.Equal(5, queryable.Count()); + Assert.Equal("Random Name 15", queryable.ElementAt(0).Name); + Assert.Equal("Random Name 14", queryable.ElementAt(1).Name); + Assert.Equal("Random Name 13", queryable.ElementAt(2).Name); + Assert.Equal("Random Name 12", queryable.ElementAt(3).Name); + Assert.Equal("Random Name 11", queryable.ElementAt(4).Name); + + queryOptions.PageIndex = 3; + + queryable = queryOptions.Apply(entities.AsQueryable()); + + Assert.Equal(5, queryable.Count()); + Assert.Equal("Random Name 10", queryable.ElementAt(0).Name); + Assert.Equal("Random Name 9", queryable.ElementAt(1).Name); + Assert.Equal("Random Name 8", queryable.ElementAt(2).Name); + Assert.Equal("Random Name 7", queryable.ElementAt(3).Name); + Assert.Equal("Random Name 6", queryable.ElementAt(4).Name); + + queryOptions.PageIndex = 4; + + queryable = queryOptions.Apply(entities.AsQueryable()); + + Assert.Equal(5, queryable.Count()); + Assert.Equal("Random Name 5", queryable.ElementAt(0).Name); + Assert.Equal("Random Name 4", queryable.ElementAt(1).Name); + Assert.Equal("Random Name 3", queryable.ElementAt(2).Name); + Assert.Equal("Random Name 2", queryable.ElementAt(3).Name); + Assert.Equal("Random Name 1", queryable.ElementAt(4).Name); + + queryOptions.PageIndex = 5; + + queryable = queryOptions.Apply(entities.AsQueryable()); + + Assert.Single(queryable); + Assert.Equal("Random Name 0", queryable.ElementAt(0).Name); + } + } +} diff --git a/test/DotNetToolkit.Repository.Test/SortingOptionsTests.cs b/test/DotNetToolkit.Repository.Test/SortingOptionsTests.cs new file mode 100644 index 00000000..5f6f826c --- /dev/null +++ b/test/DotNetToolkit.Repository.Test/SortingOptionsTests.cs @@ -0,0 +1,45 @@ +namespace DotNetToolkit.Repository.Test +{ + using Data; + using Queries; + using System.Collections.Generic; + using System.Linq; + using Xunit; + + public class SortingOptionsTests + { + [Fact] + public void Descending_Sort() + { + var entities = new List(); + for (var i = 10; i >= 1; i--) + { + entities.Add(new Customer { Name = "Random Name " + i }); + } + + var sortingOptions = new SortingOptions(x => x.Name); + var queryable = sortingOptions.Apply(entities.AsQueryable()); + + Assert.Equal("Random Name 1", queryable.First().Name); + + Assert.Equal(10, queryable.Count()); + } + + [Fact] + public void Ascending_Sort() + { + var entities = new List(); + for (var i = 10; i >= 1; i--) + { + entities.Add(new Customer { Name = "Random Name " + i }); + } + + var sortingOptions = new SortingOptions(x => x.Name, true); + var queryable = sortingOptions.Apply(entities.AsQueryable()); + + Assert.Equal("Random Name 9", queryable.First().Name); + + Assert.Equal(10, queryable.Count()); + } + } +}