Skip to content
/ Panner Public

Clean, customizable & extensible framework for the configuration, parsing and application of sorts and filters from a CSV.

License

Notifications You must be signed in to change notification settings

OSDKDev/Panner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ASP.NET Core WebAPI? You should start with Panner.AspNetCore!

Panner Nuget Coverage Status

Clean, customizable & extensible framework for the configuration, parsing and application of sorts and filters from a CSV.


Basic Usage - Sample

a. Configuration

Setting up your context to define your entities and rules.

var builder = new PContext();

// Entity wide configuration (Option 1)
builder.Entity<Post>()
    .AllPropertiesAreSortableByName();
    .AllPropertiesAreFilterableByName();

// A more granular approach (Option 2)
builder.Entity<Post>()
    .Property(x => x.Id, o => o
        .IsSortableByName()
        .IsFilterableByName()
    ).Property(x => x.Title, o => o
        .IsSortableByName()
        .IsFilterableByName()
    ).Property(x => x.CreatedOn, o => o
        .IsSortableAs("Creation")
        .IsFilterableAs("Creation")
    );

// And then we build our context.
IPContext context = builder.Build(); 

// Ta-daah! Now we have a context!

b. Parsing

Feeding Panner's context our CSV inputs and obtaining sort/filter particles

Sorts
var csvSort = "-Title, Id"; // Example

if (!context.TryParseCsv(
    input: csvSort,
    out IEnumerable<ISortParticle<TEntity>> sortParticles
)){
    // Parsing failed
    return;
}

// Ta-daah! Now we have sort particles!
Filters
var csvFilter = "Id<666, Id>13"; // Example

if (!context.TryParseCsv(
    input: csvFilter,
    out IEnumerable<IFilterParticle<TEntity>> filterParticles
)){
    // Parsing failed
    return;
}

// Ta-daah! Now we have filter particles!

c. Application

Using Panner's extension methods to apply our particles to any IEnumerable, IQueryable, DbSet, etc..

var pannedQueryable = posts
    .Apply(filterParticles)
    .Apply(sortParticles);

// Ta-daah! Now we have a filtered and sorted IQueryable!

Advanced Usage - Samples

Custom sort for a specific entity
Ability to sort our fake entity Post by "popularity", an arbritary concept and not a property of the entity.
Leveraging ISortParticle, ISortParticleGenerator and extending PEntityBuilder.

Particle - SortPostByPopularityParticle.cs
public class SortPostByPopularityParticle : ISortParticle<Post> // Panner's interface
{
    readonly bool Descending;

    public SortPostByPopularityParticle(bool descending)
    {
        this.Descending = descending;
    }

    public IOrderedQueryable<Post> ApplyTo(IOrderedQueryable<Post> source)
    {
        // Here's how the sorting is done when the particle is applied.
        if (this.Descending)
            return source
                .ThenByDescending(x => x.AmtLikes)
                .ThenByDescending(x => x.AmtComments);
        else
            return source
                .ThenBy(x => x.AmtLikes)
                .ThenBy(x => x.AmtComments);
    }
}
Particle Generator - SortPostsByPopularityParticleGenerator.cs
public class SortPostsByPopularityParticleGenerator : ISortParticleGenerator<Post> // Panner's interface
{
    public bool TryGenerate(IPContext context, string input, out ISortParticle<Post> particle)
    {
        var descending = input.StartsWith('-');
        var remaining = descending ? input.Substring(1) : input;

        if (!remaining.Trim().Equals("Popularity", System.StringComparison.OrdinalIgnoreCase))
        {
            // Not the input we're interested in.
            particle = null;
            return false;
        }

        particle = new SortPostByPopularityParticle(descending);
        return true;
    }
}
PEntityBuilder Extension - PEntityBuilder.Post.IsSortableByPopularity.cs
public static partial class PEntityBuilderExtensions
{
    /// <summary>Marks the entity as sortable by popularity.</summary>
    public static PEntityBuilder<Post> IsSortableByPopularity(this PEntityBuilder<Post> builder)
    {
        builder.GetOrCreateGenerator<ISortParticle<Post>, SortPostsByPopularityParticleGenerator>();
        return builder; // So we can chain calls!
    }
}
Setting it all up in the context builder
builder.Entity<Post>()
    .IsSortableByPopularity();

Frequently Asked Questions

Using different culture for filter value conversions?

You can change CurrentInfo.CurrentCulture before calling context.TryParseCsv([...])!

CurrentInfo.CultureInfo = new CultureInfo("es"); //So simple...!

About

Clean, customizable & extensible framework for the configuration, parsing and application of sorts and filters from a CSV.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages