mirror of
https://github.com/Biarity/Sieve.git
synced 2024-11-23 05:52:45 +01:00
Merge branch 'master' into add-license-1
This commit is contained in:
commit
4c977ee4ca
@ -1,16 +1,16 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.14">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.3">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.14" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.3" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.14" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\SieveUnitTests\SieveUnitTests.csproj" />
|
<ProjectReference Include="..\SieveUnitTests\SieveUnitTests.csproj" />
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.4.1" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.4.1" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
<PackageReference Include="Xunit.Combinatorial" Version="1.5.25" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="coverlet.collector" Version="1.3.0">
|
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
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,4 +1,4 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GlobExpressions;
|
using GlobExpressions;
|
||||||
using Nuke.Common;
|
using Nuke.Common;
|
||||||
using Nuke.Common.CI;
|
using Nuke.Common.CI;
|
||||||
@ -13,7 +13,6 @@ using Nuke.Common.Utilities.Collections;
|
|||||||
using static Nuke.Common.IO.FileSystemTasks;
|
using static Nuke.Common.IO.FileSystemTasks;
|
||||||
using static Nuke.Common.Tools.DotNet.DotNetTasks;
|
using static Nuke.Common.Tools.DotNet.DotNetTasks;
|
||||||
|
|
||||||
[CheckBuildProjectConfigurations]
|
|
||||||
[ShutdownDotNetAfterServerBuild]
|
[ShutdownDotNetAfterServerBuild]
|
||||||
[GitHubActions("ci", GitHubActionsImage.UbuntuLatest,
|
[GitHubActions("ci", GitHubActionsImage.UbuntuLatest,
|
||||||
OnPullRequestBranches = new[] {"master", "releases/*"},
|
OnPullRequestBranches = new[] {"master", "releases/*"},
|
||||||
@ -34,7 +33,7 @@ class Build : NukeBuild
|
|||||||
|
|
||||||
[GitRepository] readonly GitRepository GitRepository;
|
[GitRepository] readonly GitRepository GitRepository;
|
||||||
|
|
||||||
[GitVersion(Framework = "netcoreapp3.1")] readonly GitVersion GitVersion;
|
[GitVersion] readonly GitVersion GitVersion;
|
||||||
|
|
||||||
[Solution] readonly Solution Solution;
|
[Solution] readonly Solution Solution;
|
||||||
|
|
||||||
@ -102,8 +101,14 @@ class Build : NukeBuild
|
|||||||
.Requires(() => Configuration.Equals(Configuration.Release))
|
.Requires(() => Configuration.Equals(Configuration.Release))
|
||||||
.Executes(() =>
|
.Executes(() =>
|
||||||
{
|
{
|
||||||
Glob.Files(OutputDirectory, "*.nupkg")
|
var files = Glob
|
||||||
.NotEmpty()
|
.Files(OutputDirectory, "*.nupkg")
|
||||||
|
.NotNull()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
Assert.NotEmpty(files);
|
||||||
|
|
||||||
|
files
|
||||||
.ForEach(x =>
|
.ForEach(x =>
|
||||||
{
|
{
|
||||||
DotNetNuGetPush(s => s
|
DotNetNuGetPush(s => s
|
||||||
|
@ -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>))]
|
||||||
|
Loading…
Reference in New Issue
Block a user