mirror of
				https://github.com/Biarity/Sieve.git
				synced 2025-11-04 02:39:00 +01:00 
			
		
		
		
	Merge pull request #60 from skolmer/generics
Added support for generic filter and sort methods
This commit is contained in:
		
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
								
							@@ -84,6 +84,15 @@ public class SieveCustomSortMethods : ISieveCustomSortMethods
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return result; // Must return modified IQueryable<TEntity>
 | 
					        return result; // Must return modified IQueryable<TEntity>
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public IQueryable<T> Oldest<T>(IQueryable<T> source, bool useThenBy, bool desc) where T : BaseEntity // Generic functions are allowed too
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var result = useThenBy ?
 | 
				
			||||||
 | 
					            ((IOrderedQueryable<T>)source).ThenByDescending(p => p.DateCreated) :
 | 
				
			||||||
 | 
					            source.OrderByDescending(p => p.DateCreated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
And `SieveCustomFilterMethods`:
 | 
					And `SieveCustomFilterMethods`:
 | 
				
			||||||
@@ -97,6 +106,12 @@ public class SieveCustomFilterMethods : ISieveCustomFilterMethods
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return result; // Must return modified IQueryable<TEntity>
 | 
					        return result; // Must return modified IQueryable<TEntity>
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public IQueryable<T> Latest<T>(IQueryable<T> source, string op, string[] values) where T : BaseEntity // Generic functions are allowed too
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var result = source.Where(c => c.DateCreated > DateTimeOffset.UtcNow.AddDays(-14));
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -389,6 +389,28 @@ namespace Sieve.Services
 | 
				
			|||||||
                _options.Value.CaseSensitive ? BindingFlags.Default : BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance,
 | 
					                _options.Value.CaseSensitive ? BindingFlags.Default : BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance,
 | 
				
			||||||
                typeof(IQueryable<TEntity>));
 | 
					                typeof(IQueryable<TEntity>));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (customMethod == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // Find generic methods `public IQueryable<T> Filter<T>(IQueryable<T> source, ...)`
 | 
				
			||||||
 | 
					                var genericCustomMethod = parent?.GetType()
 | 
				
			||||||
 | 
					                .GetMethodExt(name,
 | 
				
			||||||
 | 
					                _options.Value.CaseSensitive ? BindingFlags.Default : BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance,
 | 
				
			||||||
 | 
					                typeof(IQueryable<>));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (genericCustomMethod != null &&
 | 
				
			||||||
 | 
					                    genericCustomMethod.ReturnType.IsGenericType &&
 | 
				
			||||||
 | 
					                    genericCustomMethod.ReturnType.GetGenericTypeDefinition() == typeof(IQueryable<>))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var genericBaseType = genericCustomMethod.ReturnType.GenericTypeArguments[0];
 | 
				
			||||||
 | 
					                    var constraints = genericBaseType.GetGenericParameterConstraints();
 | 
				
			||||||
 | 
					                    if (constraints == null || constraints.Length == 0 || constraints.All((t) => t.IsAssignableFrom(typeof(TEntity))))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        customMethod = genericCustomMethod.MakeGenericMethod(typeof(TEntity));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (customMethod != null)
 | 
					            if (customMethod != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                try
 | 
					                try
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								SieveUnitTests/Entities/BaseEntity.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								SieveUnitTests/Entities/BaseEntity.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using Sieve.Attributes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace SieveUnitTests.Entities
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public class BaseEntity
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public int Id { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Sieve(CanFilter = true, CanSort = true)]
 | 
				
			||||||
 | 
					        public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -3,13 +3,8 @@ using Sieve.Attributes;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace SieveUnitTests.Entities
 | 
					namespace SieveUnitTests.Entities
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public class Comment
 | 
						public class Comment : BaseEntity
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public int Id { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        [Sieve(CanFilter = true, CanSort = true)]
 | 
					 | 
				
			||||||
        public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        [Sieve(CanFilter = true)]
 | 
					        [Sieve(CanFilter = true)]
 | 
				
			||||||
        public string Text { get; set; }
 | 
					        public string Text { get; set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,8 @@ using Sieve.Attributes;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace SieveUnitTests.Entities
 | 
					namespace SieveUnitTests.Entities
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public class Post
 | 
						public class Post : BaseEntity
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public int Id { get; set; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Sieve(CanFilter = true, CanSort = true)]
 | 
					        [Sieve(CanFilter = true, CanSort = true)]
 | 
				
			||||||
        public string Title { get; set; } = Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, 8);
 | 
					        public string Title { get; set; } = Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, 8);
 | 
				
			||||||
@@ -16,9 +15,6 @@ namespace SieveUnitTests.Entities
 | 
				
			|||||||
        [Sieve(CanFilter = true, CanSort = true)]
 | 
					        [Sieve(CanFilter = true, CanSort = true)]
 | 
				
			||||||
        public int CommentCount { get; set; } = new Random().Next(0, 1000);
 | 
					        public int CommentCount { get; set; } = new Random().Next(0, 1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Sieve(CanFilter = true, CanSort = true)]
 | 
					 | 
				
			||||||
        public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        [Sieve(CanFilter = true, CanSort = true)]
 | 
					        [Sieve(CanFilter = true, CanSort = true)]
 | 
				
			||||||
        public int? CategoryId { get; set; } = new Random().Next(0, 4);
 | 
					        public int? CategoryId { get; set; } = new Random().Next(0, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -207,6 +207,20 @@ namespace SieveUnitTests
 | 
				
			|||||||
            Assert.IsTrue(result.Count() == 3);
 | 
					            Assert.IsTrue(result.Count() == 3);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [TestMethod]
 | 
				
			||||||
 | 
					        public void CustomGenericFiltersWork()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var model = new SieveModel()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Filters = "Latest",
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var result = _processor.Apply(model, _comments);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.IsFalse(result.Any(p => p.Id == 0));
 | 
				
			||||||
 | 
					            Assert.IsTrue(result.Count() == 2);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [TestMethod]
 | 
					        [TestMethod]
 | 
				
			||||||
        public void CustomFiltersWithOperatorsWork()
 | 
					        public void CustomFiltersWithOperatorsWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -286,6 +300,19 @@ namespace SieveUnitTests
 | 
				
			|||||||
            Assert.IsFalse(result.First().Id == 0);
 | 
					            Assert.IsFalse(result.First().Id == 0);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [TestMethod]
 | 
				
			||||||
 | 
					        public void CustomGenericSortsWork()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var model = new SieveModel()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Sorts = "Oldest",
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var result = _processor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.IsTrue(result.Last().Id == 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [TestMethod]
 | 
					        [TestMethod]
 | 
				
			||||||
        public void MethodNotFoundExceptionWork()
 | 
					        public void MethodNotFoundExceptionWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,5 +32,11 @@ namespace SieveUnitTests.Services
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            return source;
 | 
					            return source;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IQueryable<T> Latest<T>(IQueryable<T> source, string op, string[] values) where T : BaseEntity
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var result = source.Where(c => c.DateCreated > DateTimeOffset.UtcNow.AddDays(-14));
 | 
				
			||||||
 | 
					            return result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,5 +16,14 @@ namespace SieveUnitTests.Services
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            return result;
 | 
					            return result;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IQueryable<T> Oldest<T>(IQueryable<T> source, bool useThenBy, bool desc) where T : BaseEntity
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var result = useThenBy ?
 | 
				
			||||||
 | 
					                ((IOrderedQueryable<T>)source).ThenByDescending(p => p.DateCreated) :
 | 
				
			||||||
 | 
					                source.OrderByDescending(p => p.DateCreated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user