mirror of
				https://github.com/Biarity/Sieve.git
				synced 2025-11-04 02:39:00 +01:00 
			
		
		
		
	interface type fixes & unit test improvements
This commit is contained in:
		@@ -1,21 +1,76 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
using System.Reflection;
 | 
					using Sieve.Exceptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Sieve.Extensions
 | 
					namespace Sieve.Extensions
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public static partial class LinqExtensions
 | 
					    public static partial class LinqExtensions
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        internal static Expression GeneratePropertyAccess
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            this Expression parameterExpression,
 | 
				
			||||||
 | 
					            string propertyName
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var propertyAccessor = parameterExpression;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                propertyAccessor = Expression.PropertyOrField(propertyAccessor, propertyName);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (ArgumentException)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // propertyName is not a direct property of field of propertyAccessor expression's type.
 | 
				
			||||||
 | 
					                // when propertyAccessor.Type is directly an interface, say typeof(ISomeEntity) and ISomeEntity is interfaced to IBaseEntity
 | 
				
			||||||
 | 
					                // in which `propertyName` is defined in the first place.
 | 
				
			||||||
 | 
					                // To solve this, search `propertyName` in all other implemented interfaces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var possibleInterfaceType = propertyAccessor.Type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!possibleInterfaceType.IsInterface)
 | 
				
			||||||
 | 
					                    throw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // get all implemented interface types
 | 
				
			||||||
 | 
					                var implementedInterfaces = possibleInterfaceType.GetInterfaces();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    // search propertyName in all interfaces
 | 
				
			||||||
 | 
					                    var interfacedExpression = implementedInterfaces
 | 
				
			||||||
 | 
					                        .Where
 | 
				
			||||||
 | 
					                        (
 | 
				
			||||||
 | 
					                            implementedInterface => implementedInterface
 | 
				
			||||||
 | 
					                                .GetProperties()
 | 
				
			||||||
 | 
					                                .Any(info => info.Name == propertyName)
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                        .Select(implementedInterface => Expression.TypeAs(propertyAccessor, implementedInterface))
 | 
				
			||||||
 | 
					                        .SingleOrDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (interfacedExpression != null)
 | 
				
			||||||
 | 
					                        propertyAccessor = Expression.PropertyOrField(interfacedExpression, propertyName);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch (InvalidOperationException ioe)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    throw new SieveException
 | 
				
			||||||
 | 
					                    (
 | 
				
			||||||
 | 
					                        $"{propertyName} is repeated in interface hierarchy. Try renaming.",
 | 
				
			||||||
 | 
					                        ioe
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return propertyAccessor;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public static IQueryable<TEntity> OrderByDynamic<TEntity>(
 | 
					        public static IQueryable<TEntity> OrderByDynamic<TEntity>(
 | 
				
			||||||
            this IQueryable<TEntity> source,
 | 
					            this IQueryable<TEntity> source,
 | 
				
			||||||
            string fullPropertyName,
 | 
					            string fullPropertyName,
 | 
				
			||||||
            PropertyInfo propertyInfo,
 | 
					 | 
				
			||||||
            bool desc,
 | 
					            bool desc,
 | 
				
			||||||
            bool useThenBy, 
 | 
					            bool useThenBy, 
 | 
				
			||||||
            bool disableNullableTypeExpression = false)
 | 
					            bool disableNullableTypeExpression = false)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var lambda = GenerateLambdaWithSafeMemberAccess<TEntity>(fullPropertyName, propertyInfo, disableNullableTypeExpression);
 | 
					            var lambda = GenerateLambdaWithSafeMemberAccess<TEntity>(fullPropertyName, disableNullableTypeExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var command = desc
 | 
					            var command = desc
 | 
				
			||||||
                ? (useThenBy ? "ThenByDescending" : "OrderByDescending")
 | 
					                ? (useThenBy ? "ThenByDescending" : "OrderByDescending")
 | 
				
			||||||
@@ -34,7 +89,6 @@ namespace Sieve.Extensions
 | 
				
			|||||||
        private static Expression<Func<TEntity, object>> GenerateLambdaWithSafeMemberAccess<TEntity>
 | 
					        private static Expression<Func<TEntity, object>> GenerateLambdaWithSafeMemberAccess<TEntity>
 | 
				
			||||||
        (
 | 
					        (
 | 
				
			||||||
            string fullPropertyName,
 | 
					            string fullPropertyName,
 | 
				
			||||||
            PropertyInfo propertyInfo,
 | 
					 | 
				
			||||||
            bool disableNullableTypeExpression
 | 
					            bool disableNullableTypeExpression
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -44,15 +98,7 @@ namespace Sieve.Extensions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            foreach (var name in fullPropertyName.Split('.'))
 | 
					            foreach (var name in fullPropertyName.Split('.'))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                try
 | 
					                propertyValue = propertyValue.GeneratePropertyAccess(name);
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    propertyValue = Expression.PropertyOrField(propertyValue, name);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                catch (ArgumentException)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    // name is not a direct property of field of propertyValue expression. construct a memberAccess then.
 | 
					 | 
				
			||||||
                    propertyValue = Expression.MakeMemberAccess(propertyValue, propertyInfo);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (propertyValue.Type.IsNullable() && !disableNullableTypeExpression)
 | 
					                if (propertyValue.Type.IsNullable() && !disableNullableTypeExpression)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -289,7 +289,7 @@ namespace Sieve.Services
 | 
				
			|||||||
            var names = fullPropertyName.Split('.');
 | 
					            var names = fullPropertyName.Split('.');
 | 
				
			||||||
            for (var i = 0; i < names.Length; i++)
 | 
					            for (var i = 0; i < names.Length; i++)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                propertyValue = Expression.PropertyOrField(propertyValue, names[i]);
 | 
					                propertyValue = propertyValue.GeneratePropertyAccess(names[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (i != names.Length - 1 && propertyValue.Type.IsNullable())
 | 
					                if (i != names.Length - 1 && propertyValue.Type.IsNullable())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -368,7 +368,7 @@ namespace Sieve.Services
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (property != null)
 | 
					                if (property != null)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    result = result.OrderByDynamic(fullName, property, sortTerm.Descending, useThenBy, Options.Value.DisableNullableTypeExpressionForSorting);
 | 
					                    result = result.OrderByDynamic(fullName, sortTerm.Descending, useThenBy, Options.Value.DisableNullableTypeExpressionForSorting);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,9 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					using SieveUnitTests.Abstractions.Strategy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace SieveUnitTests.Abstractions.Entity
 | 
					namespace SieveUnitTests.Abstractions.Entity
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public interface IBaseEntity
 | 
					    public interface IBaseEntity: ISupportSoftDelete
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int Id { get; set; }
 | 
					        int Id { get; set; }
 | 
				
			||||||
        DateTimeOffset DateCreated { get; set; }
 | 
					        DateTimeOffset DateCreated { get; set; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,10 @@
 | 
				
			|||||||
using Sieve.Attributes;
 | 
					using Sieve.Attributes;
 | 
				
			||||||
 | 
					using SieveUnitTests.Abstractions.Strategy;
 | 
				
			||||||
using SieveUnitTests.Entities;
 | 
					using SieveUnitTests.Entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace SieveUnitTests.Abstractions.Entity
 | 
					namespace SieveUnitTests.Abstractions.Entity
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public interface IPost: IBaseEntity
 | 
					    public interface IPost: IBaseEntity, IAudit
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        [Sieve(CanFilter = true, CanSort = true)]
 | 
					        [Sieve(CanFilter = true, CanSort = true)]
 | 
				
			||||||
        string Title { get; set; }
 | 
					        string Title { get; set; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,8 +4,12 @@ namespace SieveUnitTests.Abstractions.Entity
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class SieveConfigurationForIPost : ISieveConfiguration
 | 
					    public class SieveConfigurationForIPost : ISieveConfiguration
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public void Configure(SievePropertyMapper mapper)
 | 
					        public static void ConfigureStatic(SievePropertyMapper mapper)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            mapper
 | 
				
			||||||
 | 
					                .Property<IPost>(p => p.Id)
 | 
				
			||||||
 | 
					                .CanSort();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            mapper.Property<IPost>(p => p.ThisHasNoAttributeButIsAccessible)
 | 
					            mapper.Property<IPost>(p => p.ThisHasNoAttributeButIsAccessible)
 | 
				
			||||||
                .CanSort()
 | 
					                .CanSort()
 | 
				
			||||||
                .CanFilter()
 | 
					                .CanFilter()
 | 
				
			||||||
@@ -32,6 +36,21 @@ namespace SieveUnitTests.Abstractions.Entity
 | 
				
			|||||||
                .Property<IPost>(p => p.DateCreated)
 | 
					                .Property<IPost>(p => p.DateCreated)
 | 
				
			||||||
                .CanSort()
 | 
					                .CanSort()
 | 
				
			||||||
                .HasName("CreateDate");
 | 
					                .HasName("CreateDate");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            mapper
 | 
				
			||||||
 | 
					                .Property<IPost>(post => post.DeletedBy)
 | 
				
			||||||
 | 
					                .CanSort()
 | 
				
			||||||
 | 
					                .HasName("DeletedBy");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            mapper
 | 
				
			||||||
 | 
					                .Property<IPost>(post => post.UpdatedBy)
 | 
				
			||||||
 | 
					                .CanFilter()
 | 
				
			||||||
 | 
					                .HasName("UpdatedBy");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void Configure(SievePropertyMapper mapper)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ConfigureStatic(mapper);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								SieveUnitTests/Abstractions/Strategy/IAudit.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								SieveUnitTests/Abstractions/Strategy/IAudit.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace SieveUnitTests.Abstractions.Strategy
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface IAudit
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        string CreatedBy { get; }
 | 
				
			||||||
 | 
					        DateTime? CreatedAt { get; }
 | 
				
			||||||
 | 
					        string UpdatedBy { get; }
 | 
				
			||||||
 | 
					        DateTime? UpdatedAt { get; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								SieveUnitTests/Abstractions/Strategy/ISupportSoftDelete.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								SieveUnitTests/Abstractions/Strategy/ISupportSoftDelete.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace SieveUnitTests.Abstractions.Strategy
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface ISupportSoftDelete
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        string DeletedBy { get; }
 | 
				
			||||||
 | 
					        DateTime? DeletedAt { get; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -10,5 +10,8 @@ namespace SieveUnitTests.Entities
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        [Sieve(CanFilter = true, CanSort = true)]
 | 
					        [Sieve(CanFilter = true, CanSort = true)]
 | 
				
			||||||
        public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;
 | 
					        public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public string DeletedBy { get; set; }
 | 
				
			||||||
 | 
					        public DateTime? DeletedAt { get; set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,5 +30,10 @@ namespace SieveUnitTests.Entities
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public Comment TopComment { get; set; }
 | 
					        public Comment TopComment { get; set; }
 | 
				
			||||||
        public Comment FeaturedComment { get; set; }
 | 
					        public Comment FeaturedComment { get; set; }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        public string CreatedBy { get; set; }
 | 
				
			||||||
 | 
					        public DateTime? CreatedAt { get; set; }
 | 
				
			||||||
 | 
					        public string UpdatedBy { get; set; }
 | 
				
			||||||
 | 
					        public DateTime? UpdatedAt { get; set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,8 +4,12 @@ namespace SieveUnitTests.Entities
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class SieveConfigurationForPost : ISieveConfiguration
 | 
					    public class SieveConfigurationForPost : ISieveConfiguration
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public void Configure(SievePropertyMapper mapper)
 | 
					        public static void ConfigureStatic(SievePropertyMapper mapper)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            mapper
 | 
				
			||||||
 | 
					                .Property<Post>(p => p.Id)
 | 
				
			||||||
 | 
					                .CanSort();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            mapper.Property<Post>(p => p.ThisHasNoAttributeButIsAccessible)
 | 
					            mapper.Property<Post>(p => p.ThisHasNoAttributeButIsAccessible)
 | 
				
			||||||
                .CanSort()
 | 
					                .CanSort()
 | 
				
			||||||
                .CanFilter()
 | 
					                .CanFilter()
 | 
				
			||||||
@@ -32,6 +36,21 @@ namespace SieveUnitTests.Entities
 | 
				
			|||||||
                .Property<Post>(p => p.DateCreated)
 | 
					                .Property<Post>(p => p.DateCreated)
 | 
				
			||||||
                .CanSort()
 | 
					                .CanSort()
 | 
				
			||||||
                .HasName("CreateDate");
 | 
					                .HasName("CreateDate");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            mapper
 | 
				
			||||||
 | 
					                .Property<Post>(post => post.DeletedBy)
 | 
				
			||||||
 | 
					                .CanSort()
 | 
				
			||||||
 | 
					                .HasName("DeletedBy");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            mapper
 | 
				
			||||||
 | 
					                .Property<Post>(post => post.UpdatedBy)
 | 
				
			||||||
 | 
					                .CanFilter()
 | 
				
			||||||
 | 
					                .HasName("UpdatedBy");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void Configure(SievePropertyMapper mapper)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ConfigureStatic(mapper);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
 | 
				
			|||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using Sieve.Exceptions;
 | 
					using Sieve.Exceptions;
 | 
				
			||||||
using Sieve.Models;
 | 
					using Sieve.Models;
 | 
				
			||||||
using Sieve.Services;
 | 
					 | 
				
			||||||
using SieveUnitTests.Entities;
 | 
					using SieveUnitTests.Entities;
 | 
				
			||||||
using SieveUnitTests.Services;
 | 
					using SieveUnitTests.Services;
 | 
				
			||||||
using Xunit;
 | 
					using Xunit;
 | 
				
			||||||
@@ -11,28 +10,14 @@ using Xunit.Abstractions;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace SieveUnitTests
 | 
					namespace SieveUnitTests
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class General
 | 
					    public class General: TestBase
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly ITestOutputHelper _testOutputHelper;
 | 
					 | 
				
			||||||
        private readonly SieveProcessor _processor;
 | 
					 | 
				
			||||||
        private readonly SieveProcessor _nullableProcessor;
 | 
					 | 
				
			||||||
        private readonly IQueryable<Post> _posts;
 | 
					        private readonly IQueryable<Post> _posts;
 | 
				
			||||||
        private readonly IQueryable<Comment> _comments;
 | 
					        private readonly IQueryable<Comment> _comments;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public General(ITestOutputHelper testOutputHelper)
 | 
					        public General(ITestOutputHelper testOutputHelper)
 | 
				
			||||||
 | 
					        : base(testOutputHelper)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var nullableAccessor = new SieveOptionsAccessor();
 | 
					 | 
				
			||||||
            nullableAccessor.Value.IgnoreNullsOnNotEqual = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _testOutputHelper = testOutputHelper;
 | 
					 | 
				
			||||||
            _processor = new ApplicationSieveProcessor(new SieveOptionsAccessor(),
 | 
					 | 
				
			||||||
                new SieveCustomSortMethods(),
 | 
					 | 
				
			||||||
                new SieveCustomFilterMethods());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _nullableProcessor = new ApplicationSieveProcessor(nullableAccessor,
 | 
					 | 
				
			||||||
                new SieveCustomSortMethods(),
 | 
					 | 
				
			||||||
                new SieveCustomFilterMethods());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _posts = new List<Post>
 | 
					            _posts = new List<Post>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                new Post
 | 
					                new Post
 | 
				
			||||||
@@ -77,6 +62,16 @@ namespace SieveUnitTests
 | 
				
			|||||||
                new Post
 | 
					                new Post
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    Id = 4,
 | 
					                    Id = 4,
 | 
				
			||||||
 | 
					                    Title = "E",
 | 
				
			||||||
 | 
					                    LikeCount = 5,
 | 
				
			||||||
 | 
					                    IsDraft = false,
 | 
				
			||||||
 | 
					                    CategoryId = null,
 | 
				
			||||||
 | 
					                    TopComment = new Comment { Id = 4, Text = "E1" },
 | 
				
			||||||
 | 
					                    UpdatedBy = "You"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                new Post
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Id = 5,
 | 
				
			||||||
                    Title = "Yen",
 | 
					                    Title = "Yen",
 | 
				
			||||||
                    LikeCount = 5,
 | 
					                    LikeCount = 5,
 | 
				
			||||||
                    IsDraft = true,
 | 
					                    IsDraft = true,
 | 
				
			||||||
@@ -117,11 +112,14 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "Title@=*a"
 | 
					                Filters = "Title@=*a"
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.Equal(0, result.First().Id);
 | 
					                Assert.Equal(0, result.First().Id);
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void NotEqualsCanBeCaseInsensitive()
 | 
					        public void NotEqualsCanBeCaseInsensitive()
 | 
				
			||||||
@@ -131,10 +129,13 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "Title!=*a"
 | 
					                Filters = "Title!=*a"
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.Equal(1, result.First().Id);
 | 
					                Assert.Equal(1, result.First().Id);
 | 
				
			||||||
            Assert.True(result.Count() == 4);
 | 
					                Assert.True(result.Count() == _posts.Count(post => !post.Title.Contains("a", StringComparison.OrdinalIgnoreCase)));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
@@ -145,15 +146,18 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "Title_-=n"
 | 
					                Filters = "Title_-=n"
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Assert.Equal(4, result.First().Id);
 | 
					                Assert.Equal(_posts.First(post => post.Title.EndsWith("n")).Id, result.First().Id);
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void EndsWithCanBeCaseInsensitive()
 | 
					        public void EndsWithCanBeCaseInsensitive()
 | 
				
			||||||
@@ -163,28 +167,31 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "Title_-=*N"
 | 
					                Filters = "Title_-=*N"
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Assert.Equal(4, result.First().Id);
 | 
					                Assert.Equal(_posts.First(post => post.Title.EndsWith("N", StringComparison.OrdinalIgnoreCase)).Id, result.First().Id);
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void ContainsIsCaseSensitive()
 | 
					        public void ContainsIsCaseSensitive()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Title@=a", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Title@=a",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(!result.Any());
 | 
					                Assert.True(!result.Any());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void NotContainsWorks()
 | 
					        public void NotContainsWorks()
 | 
				
			||||||
@@ -194,65 +201,70 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "Title!@=D",
 | 
					                Filters = "Title!@=D",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Assert.True(result.Count() == 4);
 | 
					                Assert.True(result.Count() == _posts.Count(post => !post.Title.Contains("D")));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CanFilterBools()
 | 
					        public void CanFilterBools()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "IsDraft==false" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "IsDraft==false"
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					                Assert.True(result.Count() == _posts.Count(post => !post.IsDraft));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            Assert.True(result.Count() == 2);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CanSortBools()
 | 
					        public void CanSortBools()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Sorts = "-IsDraft" };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Sorts = "-IsDraft"
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.Equal(0, result.First().Id);
 | 
					                Assert.Equal(0, result.First().Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CanFilterNullableInts()
 | 
					        public void CanFilterNullableInts()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "CategoryId==1" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "CategoryId==1"
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					                Assert.True(result.Count() == _posts.Count(post => post.CategoryId == 1));
 | 
				
			||||||
            var nullableResult = _nullableProcessor.Apply(model, _posts);
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            Assert.True(result.Count() == 2);
 | 
					 | 
				
			||||||
            Assert.True(nullableResult.Count() == 2);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CanFilterNullableIntsWithNotEqual()
 | 
					        public void CanFilterNullableIntsWithNotEqual()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel()
 | 
					            var model = new SieveModel() { Filters = "CategoryId!=1" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "CategoryId!=1"
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					                Assert.Equal
 | 
				
			||||||
            var nullableResult = _nullableProcessor.Apply(model, _posts);
 | 
					                (
 | 
				
			||||||
 | 
					                    (sieveProcessor as ApplicationSieveProcessor)?.ExposedOptions.IgnoreNullsOnNotEqual ?? true
 | 
				
			||||||
            Assert.True(result.Count() == 2);
 | 
					                        ? _posts.Count(post => post.CategoryId != null && post.CategoryId != 1)
 | 
				
			||||||
            Assert.True(nullableResult.Count() == 3);
 | 
					                        : _posts.Count(post => post.CategoryId != 1),
 | 
				
			||||||
 | 
					                    result.Count()
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Theory]
 | 
					        [Theory]
 | 
				
			||||||
@@ -267,98 +279,101 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = filter
 | 
					                Filters = filter
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _comments);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _comments);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void EqualsDoesntFailWithNonStringTypes()
 | 
					        public void EqualsDoesntFailWithNonStringTypes()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "LikeCount==50", };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
 | 
				
			||||||
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
 | 
				
			||||||
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "LikeCount==50",
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
 | 
					 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
 | 
					 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.Equal(1, result.First().Id);
 | 
					                Assert.Equal(1, result.First().Id);
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomFiltersWork()
 | 
					        public void CustomFiltersWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Isnew", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Isnew",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.False(result.Any(p => p.Id == 0));
 | 
					                Assert.False(result.Any(p => p.Id == 0));
 | 
				
			||||||
            Assert.True(result.Count() == 4);
 | 
					                Assert.True(result.Count() == _posts.Count(SieveCustomFilterMethods.IsNewFilterForPost));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomGenericFiltersWork()
 | 
					        public void CustomGenericFiltersWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Latest", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Latest",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _comments);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _comments);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.False(result.Any(p => p.Id == 0));
 | 
					                Assert.False(result.Any(p => p.Id == 0));
 | 
				
			||||||
                Assert.True(result.Count() == 2);
 | 
					                Assert.True(result.Count() == 2);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomFiltersWithOperatorsWork()
 | 
					        public void CustomFiltersWithOperatorsWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "HasInTitle==A", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "HasInTitle==A",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(result.Any(p => p.Id == 0));
 | 
					                Assert.True(result.Any(p => p.Id == 0));
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomFiltersMixedWithUsualWork1()
 | 
					        public void CustomFiltersMixedWithUsualWork1()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Isnew,CategoryId==2", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Isnew,CategoryId==2",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(result.Any(p => p.Id == 3));
 | 
					                Assert.True(result.Any(p => p.Id == 3));
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomFiltersMixedWithUsualWork2()
 | 
					        public void CustomFiltersMixedWithUsualWork2()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "CategoryId==2,Isnew", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "CategoryId==2,Isnew",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(result.Any(p => p.Id == 3));
 | 
					                Assert.True(result.Any(p => p.Id == 3));
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomFiltersOnDifferentSourcesCanShareName()
 | 
					        public void CustomFiltersOnDifferentSourcesCanShareName()
 | 
				
			||||||
@@ -368,79 +383,84 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "CategoryId==2,Isnew",
 | 
					                Filters = "CategoryId==2,Isnew",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var postResult = _processor.Apply(postModel, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var postResult = sieveProcessor.Apply(postModel, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(postResult.Any(p => p.Id == 3));
 | 
					                Assert.True(postResult.Any(p => p.Id == 3));
 | 
				
			||||||
                Assert.Equal(1, postResult.Count());
 | 
					                Assert.Equal(1, postResult.Count());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var commentModel = new SieveModel
 | 
					            var commentModel = new SieveModel
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "Isnew",
 | 
					                Filters = "Isnew",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var commentResult = _processor.Apply(commentModel, _comments);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var commentResult = sieveProcessor.Apply(commentModel, _comments);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(commentResult.Any(c => c.Id == 2));
 | 
					                Assert.True(commentResult.Any(c => c.Id == 2));
 | 
				
			||||||
                Assert.Equal(2, commentResult.Count());
 | 
					                Assert.Equal(2, commentResult.Count());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomSortsWork()
 | 
					        public void CustomSortsWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Sorts = "Popularity", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Sorts = "Popularity",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.False(result.First().Id == 0);
 | 
					                Assert.False(result.First().Id == 0);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomGenericSortsWork()
 | 
					        public void CustomGenericSortsWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Sorts = "Oldest", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Sorts = "Oldest",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(result.Last().Id == 0);
 | 
					                Assert.True(result.Last().Id == 0);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void MethodNotFoundExceptionWork()
 | 
					        public void MethodNotFoundExceptionWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "does not exist", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "does not exist",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Assert.Throws<SieveMethodNotFoundException>(() => _processor.Apply(model, _posts));
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Assert.Throws<SieveMethodNotFoundException>(() => sieveProcessor.Apply(model, _posts));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void IncompatibleMethodExceptionsWork()
 | 
					        public void IncompatibleMethodExceptionsWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "TestComment", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "TestComment",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Assert.Throws<SieveIncompatibleMethodException>(() => _processor.Apply(model, _posts));
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Assert.Throws<SieveIncompatibleMethodException>(() => sieveProcessor.Apply(model, _posts));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void OrNameFilteringWorks()
 | 
					        public void OrNameFilteringWorks()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "(Title|LikeCount)==3", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "(Title|LikeCount)==3",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                var entry = result.FirstOrDefault();
 | 
					                var entry = result.FirstOrDefault();
 | 
				
			||||||
                var resultCount = result.Count();
 | 
					                var resultCount = result.Count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -448,34 +468,34 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Assert.Equal(1, resultCount);
 | 
					                Assert.Equal(1, resultCount);
 | 
				
			||||||
                Assert.Equal(3, entry.Id);
 | 
					                Assert.Equal(3, entry.Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Theory]
 | 
					        [Theory]
 | 
				
			||||||
        [InlineData("CategoryId==1,(CategoryId|LikeCount)==50")]
 | 
					        [InlineData("CategoryId==1,(CategoryId|LikeCount)==50")]
 | 
				
			||||||
        [InlineData("(CategoryId|LikeCount)==50,CategoryId==1")]
 | 
					        [InlineData("(CategoryId|LikeCount)==50,CategoryId==1")]
 | 
				
			||||||
        public void CombinedAndOrFilterIndependentOfOrder(string filter)
 | 
					        public void CombinedAndOrFilterIndependentOfOrder(string filter)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = filter, };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = filter,
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                var entry = result.FirstOrDefault();
 | 
					                var entry = result.FirstOrDefault();
 | 
				
			||||||
                var resultCount = result.Count();
 | 
					                var resultCount = result.Count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.NotNull(entry);
 | 
					                Assert.NotNull(entry);
 | 
				
			||||||
                Assert.Equal(1, resultCount);
 | 
					                Assert.Equal(1, resultCount);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CombinedAndOrWithSpaceFilteringWorks()
 | 
					        public void CombinedAndOrWithSpaceFilteringWorks()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Title==D, (Title|LikeCount)==3", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Title==D, (Title|LikeCount)==3",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                var entry = result.FirstOrDefault();
 | 
					                var entry = result.FirstOrDefault();
 | 
				
			||||||
                var resultCount = result.Count();
 | 
					                var resultCount = result.Count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -483,67 +503,77 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Assert.Equal(1, resultCount);
 | 
					                Assert.Equal(1, resultCount);
 | 
				
			||||||
                Assert.Equal(3, entry.Id);
 | 
					                Assert.Equal(3, entry.Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void OrValueFilteringWorks()
 | 
					        public void OrValueFilteringWorks()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Title==C|D", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Title==C|D",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                Assert.Equal(2, result.Count());
 | 
					                Assert.Equal(2, result.Count());
 | 
				
			||||||
                Assert.True(result.Any(p => p.Id == 2));
 | 
					                Assert.True(result.Any(p => p.Id == 2));
 | 
				
			||||||
                Assert.True(result.Any(p => p.Id == 3));
 | 
					                Assert.True(result.Any(p => p.Id == 3));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void OrValueFilteringWorks2()
 | 
					        public void OrValueFilteringWorks2()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Text@=(|)", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Text@=(|)",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _comments);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _comments);
 | 
				
			||||||
                Assert.Equal(1, result.Count());
 | 
					                Assert.Equal(1, result.Count());
 | 
				
			||||||
                Assert.Equal(2, result.FirstOrDefault()?.Id);
 | 
					                Assert.Equal(2, result.FirstOrDefault()?.Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void NestedFilteringWorks()
 | 
					        public void NestedFilteringWorks()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "TopComment.Text!@=A", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "TopComment.Text!@=A",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            Assert.Equal(4, result.Count());
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					                Assert.Equal(_posts.Count(post => !post.TopComment.Text.Contains("A")), result.Count());
 | 
				
			||||||
                var posts = result.ToList();
 | 
					                var posts = result.ToList();
 | 
				
			||||||
                Assert.Contains("B", posts[0].TopComment.Text);
 | 
					                Assert.Contains("B", posts[0].TopComment.Text);
 | 
				
			||||||
                Assert.Contains("C", posts[1].TopComment.Text);
 | 
					                Assert.Contains("C", posts[1].TopComment.Text);
 | 
				
			||||||
                Assert.Contains("D", posts[2].TopComment.Text);
 | 
					                Assert.Contains("D", posts[2].TopComment.Text);
 | 
				
			||||||
            Assert.Contains("Yen", posts[3].TopComment.Text);
 | 
					                Assert.Contains("E1", posts[3].TopComment.Text);
 | 
				
			||||||
 | 
					                Assert.Contains("Yen", posts[4].TopComment.Text);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void NestedSortingWorks()
 | 
					        public void NestedSortingWorks()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Sorts = "TopComment.Id", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Sorts = "TopComment.Id",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            Assert.Equal(5, result.Count());
 | 
					            {
 | 
				
			||||||
            var posts = result.ToList();
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
            Assert.Equal(0, posts[0].Id);
 | 
					                Assert.Equal(_posts.Count(), result.Count());
 | 
				
			||||||
            Assert.Equal(3, posts[1].Id);
 | 
					                var posts = result
 | 
				
			||||||
            Assert.Equal(2, posts[2].Id);
 | 
					                    .Select(post => post.Id)
 | 
				
			||||||
            Assert.Equal(1, posts[3].Id);
 | 
					                    .ToList();
 | 
				
			||||||
            Assert.Equal(4, posts[4].Id);
 | 
					
 | 
				
			||||||
 | 
					                Assert.True
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    posts.SequenceEqual
 | 
				
			||||||
 | 
					                    (
 | 
				
			||||||
 | 
					                        _posts
 | 
				
			||||||
 | 
					                            .AsEnumerable()
 | 
				
			||||||
 | 
					                            .OrderBy(post => post.TopComment.Id)
 | 
				
			||||||
 | 
					                            .Select(post => post.Id)
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
@@ -554,17 +584,23 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "(topc|featc)@=*2",
 | 
					                Filters = "(topc|featc)@=*2",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                Assert.Equal(4, result.Count());
 | 
					                Assert.Equal(4, result.Count());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            model = new SieveModel
 | 
					            model = new SieveModel
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "(topc|featc)@=*B",
 | 
					                Filters = "(topc|featc)@=*B",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                Assert.Equal(1, result.Count());
 | 
					                Assert.Equal(1, result.Count());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void FilteringNullsWorks()
 | 
					        public void FilteringNullsWorks()
 | 
				
			||||||
@@ -583,14 +619,14 @@ namespace SieveUnitTests
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            }.AsQueryable();
 | 
					            }.AsQueryable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "FeaturedComment.Text!@=Some value", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "FeaturedComment.Text!@=Some value",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, posts);
 | 
				
			||||||
                Assert.Equal(0, result.Count());
 | 
					                Assert.Equal(0, result.Count());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void SortingNullsWorks()
 | 
					        public void SortingNullsWorks()
 | 
				
			||||||
@@ -624,12 +660,15 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Sorts = "TopComment.Id",
 | 
					                Sorts = "TopComment.Id",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, posts);
 | 
				
			||||||
                Assert.Equal(2, result.Count());
 | 
					                Assert.Equal(2, result.Count());
 | 
				
			||||||
                var sortedPosts = result.ToList();
 | 
					                var sortedPosts = result.ToList();
 | 
				
			||||||
                Assert.Equal(2, sortedPosts[0].Id);
 | 
					                Assert.Equal(2, sortedPosts[0].Id);
 | 
				
			||||||
                Assert.Equal(1, sortedPosts[1].Id);
 | 
					                Assert.Equal(1, sortedPosts[1].Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void FilteringOnNullWorks()
 | 
					        public void FilteringOnNullWorks()
 | 
				
			||||||
@@ -663,11 +702,14 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "FeaturedComment.Text==null",
 | 
					                Filters = "FeaturedComment.Text==null",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, posts);
 | 
				
			||||||
                Assert.Equal(1, result.Count());
 | 
					                Assert.Equal(1, result.Count());
 | 
				
			||||||
                var filteredPosts = result.ToList();
 | 
					                var filteredPosts = result.ToList();
 | 
				
			||||||
                Assert.Equal(2, filteredPosts[0].Id);
 | 
					                Assert.Equal(2, filteredPosts[0].Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void BaseDefinedPropertyMappingSortingWorks_WithCustomName()
 | 
					        public void BaseDefinedPropertyMappingSortingWorks_WithCustomName()
 | 
				
			||||||
@@ -677,16 +719,25 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Sorts = "-CreateDate"
 | 
					                Sorts = "-CreateDate"
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            Assert.Equal(5, result.Count());
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					                Assert.Equal(_posts.Count(), result.Count());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var posts = result.ToList();
 | 
					                var posts = result
 | 
				
			||||||
            Assert.Equal(4, posts[0].Id);
 | 
					                    .Select(post => post.Id)
 | 
				
			||||||
            Assert.Equal(3,posts[1].Id);
 | 
					                    .ToList();
 | 
				
			||||||
            Assert.Equal(2,posts[2].Id);
 | 
					 | 
				
			||||||
            Assert.Equal(1,posts[3].Id);
 | 
					 | 
				
			||||||
            Assert.Equal(0,posts[4].Id);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Assert.True
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    posts.SequenceEqual
 | 
				
			||||||
 | 
					                    (
 | 
				
			||||||
 | 
					                        _posts
 | 
				
			||||||
 | 
					                            .OrderByDescending(post => post.DateCreated)
 | 
				
			||||||
 | 
					                            .Select(post => post.Id)
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
@@ -713,9 +764,12 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "Text==Here is\\, another comment"
 | 
					                Filters = "Text==Here is\\, another comment"
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, comments);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, comments);
 | 
				
			||||||
                Assert.Equal(1, result.Count());
 | 
					                Assert.Equal(1, result.Count());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void OrEscapedPipeValueFilteringWorks()
 | 
					        public void OrEscapedPipeValueFilteringWorks()
 | 
				
			||||||
@@ -747,9 +801,12 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = @"Text==Here is \| a comment|Here is \| another comment|Here is \\\| another comment(1)",
 | 
					                Filters = @"Text==Here is \| a comment|Here is \| another comment|Here is \\\| another comment(1)",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, comments);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, comments);
 | 
				
			||||||
                Assert.Equal(3, result.Count());
 | 
					                Assert.Equal(3, result.Count());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        [Theory]
 | 
					        [Theory]
 | 
				
			||||||
        [InlineData("CategoryId==1,(CategoryId|LikeCount)==50")]
 | 
					        [InlineData("CategoryId==1,(CategoryId|LikeCount)==50")]
 | 
				
			||||||
@@ -761,13 +818,16 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = filter
 | 
					                Filters = filter
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                var entry = result.FirstOrDefault();
 | 
					                var entry = result.FirstOrDefault();
 | 
				
			||||||
                var resultCount = result.Count();
 | 
					                var resultCount = result.Count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.NotNull(entry);
 | 
					                Assert.NotNull(entry);
 | 
				
			||||||
                Assert.Equal(1, resultCount);
 | 
					                Assert.Equal(1, resultCount);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        [Theory]
 | 
					        [Theory]
 | 
				
			||||||
        [InlineData(@"Title@=\\")]
 | 
					        [InlineData(@"Title@=\\")]
 | 
				
			||||||
@@ -792,13 +852,16 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = filter
 | 
					                Filters = filter
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, posts);
 | 
				
			||||||
                var entry = result.FirstOrDefault();
 | 
					                var entry = result.FirstOrDefault();
 | 
				
			||||||
                var resultCount = result.Count();
 | 
					                var resultCount = result.Count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.NotNull(entry);
 | 
					                Assert.NotNull(entry);
 | 
				
			||||||
                Assert.Equal(1, resultCount);
 | 
					                Assert.Equal(1, resultCount);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        [Theory]
 | 
					        [Theory]
 | 
				
			||||||
        [InlineData(@"Title@=\== ")]
 | 
					        [InlineData(@"Title@=\== ")]
 | 
				
			||||||
@@ -840,13 +903,15 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = filter,
 | 
					                Filters = filter,
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, posts);
 | 
				
			||||||
                var entry = result.FirstOrDefault();
 | 
					                var entry = result.FirstOrDefault();
 | 
				
			||||||
                var resultCount = result.Count();
 | 
					                var resultCount = result.Count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.NotNull(entry);
 | 
					                Assert.NotNull(entry);
 | 
				
			||||||
                Assert.Equal(1, resultCount);
 | 
					                Assert.Equal(1, resultCount);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
 | 
				
			|||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using Sieve.Exceptions;
 | 
					using Sieve.Exceptions;
 | 
				
			||||||
using Sieve.Models;
 | 
					using Sieve.Models;
 | 
				
			||||||
using Sieve.Services;
 | 
					 | 
				
			||||||
using SieveUnitTests.Abstractions.Entity;
 | 
					using SieveUnitTests.Abstractions.Entity;
 | 
				
			||||||
using SieveUnitTests.Entities;
 | 
					using SieveUnitTests.Entities;
 | 
				
			||||||
using SieveUnitTests.Services;
 | 
					using SieveUnitTests.Services;
 | 
				
			||||||
@@ -12,28 +11,14 @@ using Xunit.Abstractions;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace SieveUnitTests
 | 
					namespace SieveUnitTests
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class GeneralWithInterfaces
 | 
					    public class GeneralWithInterfaces: TestBase
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly ITestOutputHelper _testOutputHelper;
 | 
					 | 
				
			||||||
        private readonly SieveProcessor _processor;
 | 
					 | 
				
			||||||
        private readonly SieveProcessor _nullableProcessor;
 | 
					 | 
				
			||||||
        private readonly IQueryable<IPost> _posts;
 | 
					        private readonly IQueryable<IPost> _posts;
 | 
				
			||||||
        private readonly IQueryable<Comment> _comments;
 | 
					        private readonly IQueryable<Comment> _comments;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public GeneralWithInterfaces(ITestOutputHelper testOutputHelper)
 | 
					        public GeneralWithInterfaces(ITestOutputHelper testOutputHelper)
 | 
				
			||||||
 | 
					            : base(testOutputHelper)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var nullableAccessor = new SieveOptionsAccessor();
 | 
					 | 
				
			||||||
            nullableAccessor.Value.IgnoreNullsOnNotEqual = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _testOutputHelper = testOutputHelper;
 | 
					 | 
				
			||||||
            _processor = new ApplicationSieveProcessor(new SieveOptionsAccessor(),
 | 
					 | 
				
			||||||
                new SieveCustomSortMethods(),
 | 
					 | 
				
			||||||
                new SieveCustomFilterMethods());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _nullableProcessor = new ApplicationSieveProcessor(nullableAccessor,
 | 
					 | 
				
			||||||
                new SieveCustomSortMethods(),
 | 
					 | 
				
			||||||
                new SieveCustomFilterMethods());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _posts = new List<IPost>
 | 
					            _posts = new List<IPost>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                new Post
 | 
					                new Post
 | 
				
			||||||
@@ -44,7 +29,8 @@ namespace SieveUnitTests
 | 
				
			|||||||
                    IsDraft = true,
 | 
					                    IsDraft = true,
 | 
				
			||||||
                    CategoryId = null,
 | 
					                    CategoryId = null,
 | 
				
			||||||
                    TopComment = new Comment { Id = 0, Text = "A1" },
 | 
					                    TopComment = new Comment { Id = 0, Text = "A1" },
 | 
				
			||||||
                    FeaturedComment = new Comment { Id = 4, Text = "A2" }
 | 
					                    FeaturedComment = new Comment { Id = 4, Text = "A2" },
 | 
				
			||||||
 | 
					                    DeletedBy = "Me"
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                new Post
 | 
					                new Post
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -54,7 +40,9 @@ namespace SieveUnitTests
 | 
				
			|||||||
                    IsDraft = false,
 | 
					                    IsDraft = false,
 | 
				
			||||||
                    CategoryId = 1,
 | 
					                    CategoryId = 1,
 | 
				
			||||||
                    TopComment = new Comment { Id = 3, Text = "B1" },
 | 
					                    TopComment = new Comment { Id = 3, Text = "B1" },
 | 
				
			||||||
                    FeaturedComment = new Comment { Id = 5, Text = "B2" }
 | 
					                    FeaturedComment = new Comment { Id = 5, Text = "B2" },
 | 
				
			||||||
 | 
					                    DeletedBy = "You",
 | 
				
			||||||
 | 
					                    UpdatedBy = "Me"
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                new Post
 | 
					                new Post
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -63,7 +51,9 @@ namespace SieveUnitTests
 | 
				
			|||||||
                    LikeCount = 0,
 | 
					                    LikeCount = 0,
 | 
				
			||||||
                    CategoryId = 1,
 | 
					                    CategoryId = 1,
 | 
				
			||||||
                    TopComment = new Comment { Id = 2, Text = "C1" },
 | 
					                    TopComment = new Comment { Id = 2, Text = "C1" },
 | 
				
			||||||
                    FeaturedComment = new Comment { Id = 6, Text = "C2" }
 | 
					                    FeaturedComment = new Comment { Id = 6, Text = "C2" },
 | 
				
			||||||
 | 
					                    DeletedBy = "Not Me",
 | 
				
			||||||
 | 
					                    UpdatedBy = "Your highness"
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                new Post
 | 
					                new Post
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -73,8 +63,29 @@ namespace SieveUnitTests
 | 
				
			|||||||
                    IsDraft = true,
 | 
					                    IsDraft = true,
 | 
				
			||||||
                    CategoryId = 2,
 | 
					                    CategoryId = 2,
 | 
				
			||||||
                    TopComment = new Comment { Id = 1, Text = "D1" },
 | 
					                    TopComment = new Comment { Id = 1, Text = "D1" },
 | 
				
			||||||
                    FeaturedComment = new Comment { Id = 7, Text = "D2" }
 | 
					                    FeaturedComment = new Comment { Id = 7, Text = "D2" },
 | 
				
			||||||
 | 
					                    UpdatedBy = "Him"
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
					                new Post
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Id = 4,
 | 
				
			||||||
 | 
					                    Title = "E",
 | 
				
			||||||
 | 
					                    LikeCount = 5,
 | 
				
			||||||
 | 
					                    IsDraft = false,
 | 
				
			||||||
 | 
					                    CategoryId = null,
 | 
				
			||||||
 | 
					                    TopComment = new Comment { Id = 4, Text = "E1" },
 | 
				
			||||||
 | 
					                    UpdatedBy = "You"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                new Post
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Id = 5,
 | 
				
			||||||
 | 
					                    Title = "Yen",
 | 
				
			||||||
 | 
					                    LikeCount = 5,
 | 
				
			||||||
 | 
					                    IsDraft = true,
 | 
				
			||||||
 | 
					                    CategoryId = 5,
 | 
				
			||||||
 | 
					                    TopComment = new Comment { Id = 4, Text = "Yen3" },
 | 
				
			||||||
 | 
					                    FeaturedComment = new Comment { Id = 8, Text = "Yen4" }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }.AsQueryable();
 | 
					            }.AsQueryable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _comments = new List<Comment>
 | 
					            _comments = new List<Comment>
 | 
				
			||||||
@@ -108,11 +119,14 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "Title@=*a"
 | 
					                Filters = "Title@=*a"
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.Equal(0, result.First().Id);
 | 
					                Assert.Equal(0, result.First().Id);
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void NotEqualsCanBeCaseInsensitive()
 | 
					        public void NotEqualsCanBeCaseInsensitive()
 | 
				
			||||||
@@ -122,24 +136,27 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "Title!=*a"
 | 
					                Filters = "Title!=*a"
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.Equal(1, result.First().Id);
 | 
					                Assert.Equal(1, result.First().Id);
 | 
				
			||||||
            Assert.True(result.Count() == 3);
 | 
					                Assert.True(result.Count() == _posts.Count(post => !post.Title.Contains("a", StringComparison.OrdinalIgnoreCase)));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void ContainsIsCaseSensitive()
 | 
					        public void ContainsIsCaseSensitive()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Title@=a", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Title@=a",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(!result.Any());
 | 
					                Assert.True(!result.Any());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void NotContainsWorks()
 | 
					        public void NotContainsWorks()
 | 
				
			||||||
@@ -149,154 +166,159 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "Title!@=D",
 | 
					                Filters = "Title!@=D",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Assert.True(result.Count() == 3);
 | 
					                Assert.True(result.Count() == _posts.Count(post => !post.Title.Contains("D")));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CanFilterBools()
 | 
					        public void CanFilterBools()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "IsDraft==false" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "IsDraft==false"
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					                Assert.True(result.Count() == _posts.Count(post => !post.IsDraft));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            Assert.True(result.Count() == 2);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CanSortBools()
 | 
					        public void CanSortBools()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Sorts = "-IsDraft" };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Sorts = "-IsDraft"
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.Equal(0, result.First().Id);
 | 
					                Assert.Equal(0, result.First().Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CanFilterNullableInts()
 | 
					        public void CanFilterNullableInts()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "CategoryId==1" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "CategoryId==1"
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					                Assert.True(result.Count() == _posts.Count(post => post.CategoryId == 1));
 | 
				
			||||||
            var nullableResult = _nullableProcessor.Apply(model, _posts);
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            Assert.True(result.Count() == 2);
 | 
					 | 
				
			||||||
            Assert.True(nullableResult.Count() == 2);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CanFilterNullableIntsWithNotEqual()
 | 
					        public void CanFilterNullableIntsWithNotEqual()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel()
 | 
					            var model = new SieveModel() { Filters = "CategoryId!=1" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "CategoryId!=1"
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					                Assert.Equal
 | 
				
			||||||
            var nullableResult = _nullableProcessor.Apply(model, _posts);
 | 
					                (
 | 
				
			||||||
 | 
					                    (sieveProcessor as ApplicationSieveProcessor)?.ExposedOptions.IgnoreNullsOnNotEqual ?? true
 | 
				
			||||||
            Assert.True(result.Count() == 1);
 | 
					                        ? _posts.Count(post => post.CategoryId != null && post.CategoryId != 1)
 | 
				
			||||||
            Assert.True(nullableResult.Count() == 2);
 | 
					                        : _posts.Count(post => post.CategoryId != 1),
 | 
				
			||||||
 | 
					                    result.Count()
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void EqualsDoesntFailWithNonStringTypes()
 | 
					        public void EqualsDoesntFailWithNonStringTypes()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "LikeCount==50", };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
 | 
				
			||||||
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
 | 
				
			||||||
 | 
					            TestOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "LikeCount==50",
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Values.ToString());
 | 
					 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].Operator);
 | 
					 | 
				
			||||||
            _testOutputHelper.WriteLine(model.GetFiltersParsed()[0].OperatorParsed.ToString());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.Equal(1, result.First().Id);
 | 
					                Assert.Equal(1, result.First().Id);
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomFiltersWork()
 | 
					        public void CustomFiltersWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Isnew", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Isnew",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.False(result.Any(p => p.Id == 0));
 | 
					                Assert.False(result.Any(p => p.Id == 0));
 | 
				
			||||||
            Assert.True(result.Count() == 3);
 | 
					                Assert.True(result.Count() == _posts.Count(SieveCustomFilterMethods.IsNewFilterForIPost));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomGenericFiltersWork()
 | 
					        public void CustomGenericFiltersWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Latest", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Latest",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _comments);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _comments);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.False(result.Any(p => p.Id == 0));
 | 
					                Assert.False(result.Any(p => p.Id == 0));
 | 
				
			||||||
                Assert.True(result.Count() == 2);
 | 
					                Assert.True(result.Count() == 2);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomFiltersWithOperatorsWork()
 | 
					        public void CustomFiltersWithOperatorsWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "HasInTitle==A", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "HasInTitle==A",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(result.Any(p => p.Id == 0));
 | 
					                Assert.True(result.Any(p => p.Id == 0));
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomFiltersMixedWithUsualWork1()
 | 
					        public void CustomFiltersMixedWithUsualWork1()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Isnew,CategoryId==2", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Isnew,CategoryId==2",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(result.Any(p => p.Id == 3));
 | 
					                Assert.True(result.Any(p => p.Id == 3));
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomFiltersMixedWithUsualWork2()
 | 
					        public void CustomFiltersMixedWithUsualWork2()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "CategoryId==2,Isnew", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "CategoryId==2,Isnew",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(result.Any(p => p.Id == 3));
 | 
					                Assert.True(result.Any(p => p.Id == 3));
 | 
				
			||||||
                Assert.True(result.Count() == 1);
 | 
					                Assert.True(result.Count() == 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomFiltersOnDifferentSourcesCanShareName()
 | 
					        public void CustomFiltersOnDifferentSourcesCanShareName()
 | 
				
			||||||
@@ -306,79 +328,84 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "CategoryId==2,Isnew",
 | 
					                Filters = "CategoryId==2,Isnew",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var postResult = _processor.Apply(postModel, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var postResult = sieveProcessor.Apply(postModel, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(postResult.Any(p => p.Id == 3));
 | 
					                Assert.True(postResult.Any(p => p.Id == 3));
 | 
				
			||||||
                Assert.Equal(1, postResult.Count());
 | 
					                Assert.Equal(1, postResult.Count());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var commentModel = new SieveModel
 | 
					            var commentModel = new SieveModel
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "Isnew",
 | 
					                Filters = "Isnew",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var commentResult = _processor.Apply(commentModel, _comments);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var commentResult = sieveProcessor.Apply(commentModel, _comments);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(commentResult.Any(c => c.Id == 2));
 | 
					                Assert.True(commentResult.Any(c => c.Id == 2));
 | 
				
			||||||
                Assert.Equal(2, commentResult.Count());
 | 
					                Assert.Equal(2, commentResult.Count());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomSortsWork()
 | 
					        public void CustomSortsWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Sorts = "Popularity", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Sorts = "Popularity",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.False(result.First().Id == 0);
 | 
					                Assert.False(result.First().Id == 0);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CustomGenericSortsWork()
 | 
					        public void CustomGenericSortsWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Sorts = "Oldest", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Sorts = "Oldest",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.True(result.Last().Id == 0);
 | 
					                Assert.True(result.Last().Id == 0);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void MethodNotFoundExceptionWork()
 | 
					        public void MethodNotFoundExceptionWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "does not exist", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "does not exist",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Assert.Throws<SieveMethodNotFoundException>(() => _processor.Apply(model, _posts));
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Assert.Throws<SieveMethodNotFoundException>(() => sieveProcessor.Apply(model, _posts));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void IncompatibleMethodExceptionsWork()
 | 
					        public void IncompatibleMethodExceptionsWork()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "TestComment", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "TestComment",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Assert.Throws<SieveIncompatibleMethodException>(() => _processor.Apply(model, _posts));
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Assert.Throws<SieveIncompatibleMethodException>(() => sieveProcessor.Apply(model, _posts));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void OrNameFilteringWorks()
 | 
					        public void OrNameFilteringWorks()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "(Title|LikeCount)==3", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "(Title|LikeCount)==3",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                var entry = result.FirstOrDefault();
 | 
					                var entry = result.FirstOrDefault();
 | 
				
			||||||
                var resultCount = result.Count();
 | 
					                var resultCount = result.Count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -386,34 +413,34 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Assert.Equal(1, resultCount);
 | 
					                Assert.Equal(1, resultCount);
 | 
				
			||||||
                Assert.Equal(3, entry.Id);
 | 
					                Assert.Equal(3, entry.Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Theory]
 | 
					        [Theory]
 | 
				
			||||||
        [InlineData("CategoryId==1,(CategoryId|LikeCount)==50")]
 | 
					        [InlineData("CategoryId==1,(CategoryId|LikeCount)==50")]
 | 
				
			||||||
        [InlineData("(CategoryId|LikeCount)==50,CategoryId==1")]
 | 
					        [InlineData("(CategoryId|LikeCount)==50,CategoryId==1")]
 | 
				
			||||||
        public void CombinedAndOrFilterIndependentOfOrder(string filter)
 | 
					        public void CombinedAndOrFilterIndependentOfOrder(string filter)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = filter, };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = filter,
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                var entry = result.FirstOrDefault();
 | 
					                var entry = result.FirstOrDefault();
 | 
				
			||||||
                var resultCount = result.Count();
 | 
					                var resultCount = result.Count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Assert.NotNull(entry);
 | 
					                Assert.NotNull(entry);
 | 
				
			||||||
                Assert.Equal(1, resultCount);
 | 
					                Assert.Equal(1, resultCount);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void CombinedAndOrWithSpaceFilteringWorks()
 | 
					        public void CombinedAndOrWithSpaceFilteringWorks()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Title==D, (Title|LikeCount)==3", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Title==D, (Title|LikeCount)==3",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                var entry = result.FirstOrDefault();
 | 
					                var entry = result.FirstOrDefault();
 | 
				
			||||||
                var resultCount = result.Count();
 | 
					                var resultCount = result.Count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -421,65 +448,77 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Assert.Equal(1, resultCount);
 | 
					                Assert.Equal(1, resultCount);
 | 
				
			||||||
                Assert.Equal(3, entry.Id);
 | 
					                Assert.Equal(3, entry.Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void OrValueFilteringWorks()
 | 
					        public void OrValueFilteringWorks()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Title==C|D", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Title==C|D",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                Assert.Equal(2, result.Count());
 | 
					                Assert.Equal(2, result.Count());
 | 
				
			||||||
                Assert.True(result.Any(p => p.Id == 2));
 | 
					                Assert.True(result.Any(p => p.Id == 2));
 | 
				
			||||||
                Assert.True(result.Any(p => p.Id == 3));
 | 
					                Assert.True(result.Any(p => p.Id == 3));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void OrValueFilteringWorks2()
 | 
					        public void OrValueFilteringWorks2()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "Text@=(|)", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "Text@=(|)",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _comments);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _comments);
 | 
				
			||||||
                Assert.Equal(1, result.Count());
 | 
					                Assert.Equal(1, result.Count());
 | 
				
			||||||
                Assert.Equal(2, result.FirstOrDefault()?.Id);
 | 
					                Assert.Equal(2, result.FirstOrDefault()?.Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void NestedFilteringWorks()
 | 
					        public void NestedFilteringWorks()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "TopComment.Text!@=A", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "TopComment.Text!@=A",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            Assert.Equal(3, result.Count());
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					                Assert.Equal(_posts.Count(post => !post.TopComment.Text.Contains("A")), result.Count());
 | 
				
			||||||
                var posts = result.ToList();
 | 
					                var posts = result.ToList();
 | 
				
			||||||
                Assert.Contains("B", posts[0].TopComment.Text);
 | 
					                Assert.Contains("B", posts[0].TopComment.Text);
 | 
				
			||||||
                Assert.Contains("C", posts[1].TopComment.Text);
 | 
					                Assert.Contains("C", posts[1].TopComment.Text);
 | 
				
			||||||
                Assert.Contains("D", posts[2].TopComment.Text);
 | 
					                Assert.Contains("D", posts[2].TopComment.Text);
 | 
				
			||||||
 | 
					                Assert.Contains("E1", posts[3].TopComment.Text);
 | 
				
			||||||
 | 
					                Assert.Contains("Yen", posts[4].TopComment.Text);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void NestedSortingWorks()
 | 
					        public void NestedSortingWorks()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Sorts = "TopComment.Id", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Sorts = "TopComment.Id",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            Assert.Equal(4, result.Count());
 | 
					            {
 | 
				
			||||||
            var posts = result.ToList();
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
            Assert.Equal(0, posts[0].Id);
 | 
					                Assert.Equal(_posts.Count(), result.Count());
 | 
				
			||||||
            Assert.Equal(3, posts[1].Id);
 | 
					                var posts = result
 | 
				
			||||||
            Assert.Equal(2, posts[2].Id);
 | 
					                    .Select(post => post.Id)
 | 
				
			||||||
            Assert.Equal(1, posts[3].Id);
 | 
					                    .ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Assert.True
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    posts.SequenceEqual
 | 
				
			||||||
 | 
					                    (
 | 
				
			||||||
 | 
					                        _posts
 | 
				
			||||||
 | 
					                            .AsEnumerable()
 | 
				
			||||||
 | 
					                            .OrderBy(post => post.TopComment.Id)
 | 
				
			||||||
 | 
					                            .Select(post => post.Id)
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
@@ -490,17 +529,23 @@ namespace SieveUnitTests
 | 
				
			|||||||
                Filters = "(topc|featc)@=*2",
 | 
					                Filters = "(topc|featc)@=*2",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                Assert.Equal(4, result.Count());
 | 
					                Assert.Equal(4, result.Count());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            model = new SieveModel
 | 
					            model = new SieveModel
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Filters = "(topc|featc)@=*B",
 | 
					                Filters = "(topc|featc)@=*B",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            result = _processor.Apply(model, _posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
                Assert.Equal(1, result.Count());
 | 
					                Assert.Equal(1, result.Count());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void FilteringNullsWorks()
 | 
					        public void FilteringNullsWorks()
 | 
				
			||||||
@@ -519,14 +564,14 @@ namespace SieveUnitTests
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            }.AsQueryable();
 | 
					            }.AsQueryable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "FeaturedComment.Text!@=Some value", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "FeaturedComment.Text!@=Some value",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, posts);
 | 
				
			||||||
                Assert.Equal(0, result.Count());
 | 
					                Assert.Equal(0, result.Count());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void SortingNullsWorks()
 | 
					        public void SortingNullsWorks()
 | 
				
			||||||
@@ -555,17 +600,17 @@ namespace SieveUnitTests
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            }.AsQueryable();
 | 
					            }.AsQueryable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Sorts = "TopComment.Id", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Sorts = "TopComment.Id",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, posts);
 | 
				
			||||||
                Assert.Equal(2, result.Count());
 | 
					                Assert.Equal(2, result.Count());
 | 
				
			||||||
                var sortedPosts = result.ToList();
 | 
					                var sortedPosts = result.ToList();
 | 
				
			||||||
                Assert.Equal(2, sortedPosts[0].Id);
 | 
					                Assert.Equal(2, sortedPosts[0].Id);
 | 
				
			||||||
                Assert.Equal(1, sortedPosts[1].Id);
 | 
					                Assert.Equal(1, sortedPosts[1].Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void FilteringOnNullWorks()
 | 
					        public void FilteringOnNullWorks()
 | 
				
			||||||
@@ -594,33 +639,94 @@ namespace SieveUnitTests
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            }.AsQueryable();
 | 
					            }.AsQueryable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Filters = "FeaturedComment.Text==null", };
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Filters = "FeaturedComment.Text==null",
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, posts);
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, posts);
 | 
				
			||||||
                Assert.Equal(1, result.Count());
 | 
					                Assert.Equal(1, result.Count());
 | 
				
			||||||
                var filteredPosts = result.ToList();
 | 
					                var filteredPosts = result.ToList();
 | 
				
			||||||
                Assert.Equal(2, filteredPosts[0].Id);
 | 
					                Assert.Equal(2, filteredPosts[0].Id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void BaseDefinedPropertyMappingSortingWorks_WithCustomName()
 | 
					        public void BaseDefinedPropertyMappingSortingWorks_WithCustomName()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var model = new SieveModel
 | 
					            var model = new SieveModel { Sorts = "-CreateDate" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Sorts = "-CreateDate"
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
            };
 | 
					                Assert.Equal(_posts.Count(), result.Count());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var result = _processor.Apply(model, _posts);
 | 
					                var posts = result
 | 
				
			||||||
            Assert.Equal(4, result.Count());
 | 
					                    .Select(post => post.Id)
 | 
				
			||||||
 | 
					                    .ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var posts = result.ToList();
 | 
					                Assert.True
 | 
				
			||||||
            Assert.Equal(3,posts[0].Id);
 | 
					                (
 | 
				
			||||||
            Assert.Equal(2,posts[1].Id);
 | 
					                    posts.SequenceEqual
 | 
				
			||||||
            Assert.Equal(1,posts[2].Id);
 | 
					                    (
 | 
				
			||||||
            Assert.Equal(0,posts[3].Id);
 | 
					                        _posts
 | 
				
			||||||
 | 
					                            .OrderByDescending(post => post.DateCreated)
 | 
				
			||||||
 | 
					                            .Select(post => post.Id)
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Theory]
 | 
				
			||||||
 | 
					        [InlineData("DeletedBy")]
 | 
				
			||||||
 | 
					        [InlineData("-DeletedBy")]
 | 
				
			||||||
 | 
					        public void CanSortWithInterfaceProperties(string sort)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var model = new SieveModel { Sorts = sort };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					                var entry = result.FirstOrDefault();
 | 
				
			||||||
 | 
					                var resultCount = result.Count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Assert.NotNull(entry);
 | 
				
			||||||
 | 
					                Assert.Equal(_posts.Count(), resultCount);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Theory]
 | 
				
			||||||
 | 
					        [InlineData("UpdatedBy==Me", 1, 1, new [] {1})]
 | 
				
			||||||
 | 
					        [InlineData("UpdatedBy==Me|You", 2, 2, null)]
 | 
				
			||||||
 | 
					        [InlineData("UpdatedBy==You|Me", 2, 2, null)]
 | 
				
			||||||
 | 
					        [InlineData("UpdatedBy!=Him", 5, 3, null)]
 | 
				
			||||||
 | 
					        [InlineData("UpdatedBy_=*You", 2, 2, null)]
 | 
				
			||||||
 | 
					        public void CanFilterWithInterfaceProperties(string filters, int recordCount, int nullIgnoredRecordCount, int[] filteredIds)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var model = new SieveModel { Filters = filters, Sorts = "Id" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var sieveProcessor in GetProcessors())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = sieveProcessor.Apply(model, _posts);
 | 
				
			||||||
 | 
					                var resultCount = result.Count();
 | 
				
			||||||
 | 
					                Assert.Equal
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    (sieveProcessor as ApplicationSieveProcessor)?.ExposedOptions.IgnoreNullsOnNotEqual ?? true
 | 
				
			||||||
 | 
					                        ? nullIgnoredRecordCount
 | 
				
			||||||
 | 
					                        : recordCount,
 | 
				
			||||||
 | 
					                    resultCount
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (filteredIds != null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Assert.True
 | 
				
			||||||
 | 
					                    (
 | 
				
			||||||
 | 
					                        result
 | 
				
			||||||
 | 
					                            .Select(post => post.Id)
 | 
				
			||||||
 | 
					                            .SequenceEqual(filteredIds)
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,62 +16,20 @@ namespace SieveUnitTests.Services
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public SieveOptions ExposedOptions => new SieveOptions()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            IgnoreNullsOnNotEqual = Options.Value.IgnoreNullsOnNotEqual,
 | 
				
			||||||
 | 
					            CaseSensitive = Options.Value.CaseSensitive,
 | 
				
			||||||
 | 
					            DefaultPageSize = Options.Value.DefaultPageSize,
 | 
				
			||||||
 | 
					            DisableNullableTypeExpressionForSorting = Options.Value.DisableNullableTypeExpressionForSorting,
 | 
				
			||||||
 | 
					            MaxPageSize = Options.Value.MaxPageSize,
 | 
				
			||||||
 | 
					            ThrowExceptions = Options.Value.ThrowExceptions,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper)
 | 
					        protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            mapper.Property<Post>(p => p.ThisHasNoAttributeButIsAccessible)
 | 
					            SieveConfigurationForPost.ConfigureStatic(mapper);
 | 
				
			||||||
                .CanSort()
 | 
					            SieveConfigurationForIPost.ConfigureStatic(mapper);
 | 
				
			||||||
                .CanFilter()
 | 
					 | 
				
			||||||
                .HasName("shortname");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper.Property<Post>(p => p.TopComment.Text)
 | 
					 | 
				
			||||||
                .CanFilter();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper.Property<Post>(p => p.TopComment.Id)
 | 
					 | 
				
			||||||
                .CanSort();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper.Property<Post>(p => p.OnlySortableViaFluentApi)
 | 
					 | 
				
			||||||
                .CanSort();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper.Property<Post>(p => p.TopComment.Text)
 | 
					 | 
				
			||||||
                .CanFilter()
 | 
					 | 
				
			||||||
                .HasName("topc");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper.Property<Post>(p => p.FeaturedComment.Text)
 | 
					 | 
				
			||||||
                .CanFilter()
 | 
					 | 
				
			||||||
                .HasName("featc");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper
 | 
					 | 
				
			||||||
                .Property<Post>(p => p.DateCreated)
 | 
					 | 
				
			||||||
                .CanSort()
 | 
					 | 
				
			||||||
                .HasName("CreateDate");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // interfaces
 | 
					 | 
				
			||||||
            mapper.Property<IPost>(p => p.ThisHasNoAttributeButIsAccessible)
 | 
					 | 
				
			||||||
                .CanSort()
 | 
					 | 
				
			||||||
                .CanFilter()
 | 
					 | 
				
			||||||
                .HasName("shortname");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper.Property<IPost>(p => p.TopComment.Text)
 | 
					 | 
				
			||||||
                .CanFilter();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper.Property<IPost>(p => p.TopComment.Id)
 | 
					 | 
				
			||||||
                .CanSort();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper.Property<IPost>(p => p.OnlySortableViaFluentApi)
 | 
					 | 
				
			||||||
                .CanSort();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper.Property<IPost>(p => p.TopComment.Text)
 | 
					 | 
				
			||||||
                .CanFilter()
 | 
					 | 
				
			||||||
                .HasName("topc");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper.Property<IPost>(p => p.FeaturedComment.Text)
 | 
					 | 
				
			||||||
                .CanFilter()
 | 
					 | 
				
			||||||
                .HasName("featc");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            mapper
 | 
					 | 
				
			||||||
                .Property<IPost>(p => p.DateCreated)
 | 
					 | 
				
			||||||
                .CanSort()
 | 
					 | 
				
			||||||
                .HasName("CreateDate");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return mapper;
 | 
					            return mapper;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
using Sieve.Services;
 | 
					using Sieve.Services;
 | 
				
			||||||
using SieveUnitTests.Abstractions.Entity;
 | 
					using SieveUnitTests.Abstractions.Entity;
 | 
				
			||||||
using SieveUnitTests.Entities;
 | 
					using SieveUnitTests.Entities;
 | 
				
			||||||
@@ -8,9 +9,14 @@ namespace SieveUnitTests.Services
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class SieveCustomFilterMethods : ISieveCustomFilterMethods
 | 
					    public class SieveCustomFilterMethods : ISieveCustomFilterMethods
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        internal static readonly Expression<Func<Post, bool>> IsNewFilterForPost = post => post.LikeCount < 100;
 | 
				
			||||||
 | 
					        internal static readonly Expression<Func<IPost, bool>> IsNewFilterForIPost = post => post.LikeCount < 100;
 | 
				
			||||||
 | 
					        internal static readonly Expression<Func<Comment, bool>> IsNewFilterForComment = comment => comment.DateCreated > DateTimeOffset.UtcNow.AddDays(-2);
 | 
				
			||||||
 | 
					        internal static readonly Expression<Func<IComment, bool>> IsNewFilterForIComment = comment => comment.DateCreated > DateTimeOffset.UtcNow.AddDays(-2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IQueryable<Post> IsNew(IQueryable<Post> source, string op, string[] values)
 | 
					        public IQueryable<Post> IsNew(IQueryable<Post> source, string op, string[] values)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var result = source.Where(p => p.LikeCount < 100);
 | 
					            var result = source.Where(IsNewFilterForPost);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return result;
 | 
					            return result;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -24,7 +30,7 @@ namespace SieveUnitTests.Services
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public IQueryable<Comment> IsNew(IQueryable<Comment> source, string op, string[] values)
 | 
					        public IQueryable<Comment> IsNew(IQueryable<Comment> source, string op, string[] values)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var result = source.Where(c => c.DateCreated > DateTimeOffset.UtcNow.AddDays(-2));
 | 
					            var result = source.Where(IsNewFilterForComment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return result;
 | 
					            return result;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -42,7 +48,7 @@ namespace SieveUnitTests.Services
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public IQueryable<IPost> IsNew(IQueryable<IPost> source, string op, string[] values)
 | 
					        public IQueryable<IPost> IsNew(IQueryable<IPost> source, string op, string[] values)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var result = source.Where(p => p.LikeCount < 100);
 | 
					            var result = source.Where(IsNewFilterForIPost);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return result;
 | 
					            return result;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -56,7 +62,7 @@ namespace SieveUnitTests.Services
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public IQueryable<IComment> IsNew(IQueryable<IComment> source, string op, string[] values)
 | 
					        public IQueryable<IComment> IsNew(IQueryable<IComment> source, string op, string[] values)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var result = source.Where(c => c.DateCreated > DateTimeOffset.UtcNow.AddDays(-2));
 | 
					            var result = source.Where(IsNewFilterForIComment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return result;
 | 
					            return result;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@
 | 
				
			|||||||
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
 | 
					    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" />
 | 
					    <PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" />
 | 
				
			||||||
    <PackageReference Include="xunit" Version="2.4.1" />
 | 
					    <PackageReference Include="xunit" Version="2.4.1" />
 | 
				
			||||||
 | 
					    <PackageReference Include="Xunit.Combinatorial" Version="1.5.25" />
 | 
				
			||||||
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
 | 
					    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
 | 
				
			||||||
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
					      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
				
			||||||
      <PrivateAssets>all</PrivateAssets>
 | 
					      <PrivateAssets>all</PrivateAssets>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										48
									
								
								SieveUnitTests/TestBase.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								SieveUnitTests/TestBase.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using Sieve.Services;
 | 
				
			||||||
 | 
					using SieveUnitTests.Services;
 | 
				
			||||||
 | 
					using Xunit.Abstractions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace SieveUnitTests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public abstract class TestBase
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        protected TestBase(ITestOutputHelper testOutputHelper)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TestOutputHelper = testOutputHelper;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected ITestOutputHelper TestOutputHelper { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Processors with the same mappings but configured via a different method.
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        public static IEnumerable<ISieveProcessor> GetProcessors()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // normal processor
 | 
				
			||||||
 | 
					            yield return new ApplicationSieveProcessor(
 | 
				
			||||||
 | 
					                    new SieveOptionsAccessor(),
 | 
				
			||||||
 | 
					                    new SieveCustomSortMethods(),
 | 
				
			||||||
 | 
					                    new SieveCustomFilterMethods());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // nullable processor
 | 
				
			||||||
 | 
					            yield return new ApplicationSieveProcessor(
 | 
				
			||||||
 | 
					                new SieveOptionsAccessor() { Value = { IgnoreNullsOnNotEqual = false } },
 | 
				
			||||||
 | 
					                new SieveCustomSortMethods(),
 | 
				
			||||||
 | 
					                new SieveCustomFilterMethods());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // modular processor
 | 
				
			||||||
 | 
					            yield return new ModularConfigurationSieveProcessor(
 | 
				
			||||||
 | 
					                new SieveOptionsAccessor(),
 | 
				
			||||||
 | 
					                new SieveCustomSortMethods(),
 | 
				
			||||||
 | 
					                new SieveCustomFilterMethods());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // modular processor with scan
 | 
				
			||||||
 | 
					            yield return new ModularConfigurationWithScanSieveProcessor(
 | 
				
			||||||
 | 
					                new SieveOptionsAccessor(),
 | 
				
			||||||
 | 
					                new SieveCustomSortMethods(),
 | 
				
			||||||
 | 
					                new SieveCustomFilterMethods());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,6 +1,4 @@
 | 
				
			|||||||
using System;
 | 
					using System.ComponentModel;
 | 
				
			||||||
using System.ComponentModel;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using Nuke.Common.Tooling;
 | 
					using Nuke.Common.Tooling;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[TypeConverter(typeof(TypeConverter<Configuration>))]
 | 
					[TypeConverter(typeof(TypeConverter<Configuration>))]
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user