Biarity / Sieve

⚗️ Clean & extensible Sorting, Filtering, and Pagination for ASP.NET Core
Other
1.2k stars 132 forks source link

CustomFilterMethods and FluentAPI conflict #47

Open jasonycw opened 5 years ago

jasonycw commented 5 years ago

I found that Sieve will flow an error if I try to use CustomFilter and don't add Sieve attributes and no CustomSieveProcessor

e.g. I got this custom filter

public class SieveCustomFilterMethods : ISieveCustomFilterMethods
{
    public IQueryable<Domain.User.User> Roles(IQueryable<Domain.User.User> source, string op, string[] values) // The method is given the {Operator} & {Value}
    {
        var result = source;

        foreach (var v in values)
            result = source.Where(x => x.UserRoles.Any(r => r.Role == v));

        return result; // Must return modified IQueryable<TEntity>
    }
}

And this UserClass

public class User
{
    public Guid UserId { get; set; }
    public string Email { get; set; }
    public IEnumerable<UserRole> UserRoles { get; set; }
    public IEnumerable<string> Roles => UserRoles.Select(r => r.Role);
}

If I don't add [Sieve(CanFilter=true)] to the User.UserRoles, and call the API with ?filters=roles==admin The return result will be filter with UserRoles that contain "Admin"

BUT! processor.Apply will keep throwing the following exception without breaking the filter

System.Collections.Generic.KeyNotFoundException: 'The given key 'Domain.User.User' was not present in the dictionary.'

Then I tried adding a custom SieveProcessor while keeping my custom filter

public class ApplicationSieveProcessor : SieveProcessor
{
    public ApplicationSieveProcessor(
        IOptions<SieveOptions> options)
        : base(options)
    {
    }

    protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper)
    {
        mapper.Property<Domain.User.User>(x => x.UserRoles)
            .CanFilter();

        return mapper;
    }
}

Then, calling ?filters=roles==admin will cause another exception that break the filter

Sieve.Exceptions.SieveMethodNotFoundException: 'roles not found.'

If I change the MapProperties to

    protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper)
    {
        mapper.Property<Domain.User.User>(x => x.Roles)
            .CanFilter();

        return mapper;
    }

This will not trigger any filter at all.

Is there a way to keep CustomFilter while adding FluentAPI properly?

jasonycw commented 5 years ago

Further info: The exception is thrown from here

Sieve.dll!Sieve.Services.SievePropertyMapper.FindProperty<The class name>(bool canSortRequired, bool canFilterRequired, string name, bool isCaseSensitive)

bushuevzi commented 3 years ago

Sieve.Exceptions.SieveMethodNotFoundException: 'roles not found.'

May be you need add "ISieveCustomFilterMethods customFilterMethods" to constructor ApplicationSieveProcessor and send this arg to base() construstor. Like this:

public class ApplicationSieveProcessor : SieveProcessor
{
    public ApplicationSieveProcessor(
        IOptions<SieveOptions> options,
        ISieveCustomFilterMethods customFilterMethods)
        : base(options, customFilterMethods)
    {
    }
    protected override SievePropertyMapper MapProperties(SievePropertyMapper mapper)
    {
        mapper.Property<Domain.User.User>(x => x.UserRoles)
            .CanFilter();

        return mapper;
    }
}

And of couse your nead add this service to Startup.cs services.AddScoped<ISieveCustomFilterMethods, SieveCustomFilterMethods>();

Problem is in that your SieveCustomFilterMethods never instantiated, and sieve didn't know about your new method Roles(IQueryable<Domain.User.User> source, string op, string[] values)