Superfilter

Une bibliothèque C# .NET 9.0 légère avec une API ConfigurationBuilder fluide pour le filtrage et tri dynamique

Superfilter est une bibliothèque C# puissante et légère qui permet le filtrage et tri dynamique sur les sources IQueryable. Construite pour les applications .NET 9.0 modernes, elle propose une nouvelle API ConfigurationBuilder fluide qui élimine le casting manuel, offrant des capacités de requête type-safe avec support IntelliSense pour les API web avec une intégration transparente d'Entity Framework.

C#
.NET 9.0
ConfigurationBuilder
Entity Framework
LINQ
Type-Safe

Fonctionnalités Clés

ConfigurationBuilder Fluide

Nouvelle API fluide qui élimine le casting manuel avec des mappings de propriétés type-safe

Type-Safe & IntelliSense

Vérification complète des types à la compilation avec support IntelliSense pour une meilleure DX

Opérateurs Riches

Support pour Equals, Contains, StartsWith, comparaisons de dates et plus

Intégration EF

Intégration transparente avec Entity Framework Core et LINQ-to-Objects

Comment ça Fonctionne

Superfilter transforme les expressions de filtre JSON en requêtes LINQ, ce qui le rend parfait pour les API REST qui ont besoin de capacités de filtrage flexibles.

1

Définissez vos critères de filtre au format JSON

2

Passez les critères à Superfilter

3

Obtenez un résultat IQueryable filtré

1// ConfigurationBuilder API - Complete Example
2using Superfilter;
3
4[HttpPost("search")]
5public async Task<IActionResult> SearchUsers([FromBody] UserSearchRequest request)
6{
7    // 1. Create configuration with fluent, type-safe API
8    var superfilter = SuperfilterBuilder.For<User>()
9        .MapProperty("id", u => u.Id)                            // Required filter
10        .MapProperty("name", u => u.Name)                        // Simple property
11        .MapProperty("carBrandName", u => u.Car.Brand.Name)      // Nested navigation
12        .MapProperty("bornDate", u => u.BornDate)                // DateTime support
13        .MapProperty("isActive", u => u.IsActive)                // Boolean support
14        .WithFilters(request.Filters)                            // Dynamic from client
15        .WithSorts(request.Sorts)                                // Dynamic from client
16        .Build();
17
18    // 2. Apply filtering and sorting
19    var query = _context.Users.AsQueryable();
20    query = superfilter.ApplyConfiguredFilters(query);
21    query = query.ApplySorting(superfilter);
22    
23    // 3. Execute query
24    return Ok(await query.ToListAsync());
25}
26
27// Key Benefits:
28// ✅ No manual casting required
29// ✅ Type safety with compile-time checking  
30// ✅ IntelliSense support
31// ✅ Handles any property type automatically
32// ✅ Support for nested navigation properties

Avec vs Sans Superfilter

Sans Superfilter

Manual casting required with verbose syntax

1// Sans Superfilter - Code verbeux et répétitif
2var query = dbContext.Users.AsQueryable();
3
4if (!string.IsNullOrEmpty(nameFilter))
5{
6    query = nameOperator switch
7    {
8        "contains"     => query.Where(u => u.Name.Contains(nameFilter)),
9        "equals"       => query.Where(u => u.Name == nameFilter),
10        "startsWith"   => query.Where(u => u.Name.StartsWith(nameFilter)),
11        "endsWith"     => query.Where(u => u.Name.EndsWith(nameFilter)),
12        "notEquals"    => query.Where(u => u.Name != nameFilter),
13        "notContains"  => query.Where(u => !u.Name.Contains(nameFilter)),
14        "isEmpty"      => query.Where(u => string.IsNullOrEmpty(u.Name)),
15        "isNotEmpty"   => query.Where(u => !string.IsNullOrEmpty(u.Name)),
16        _              => query
17    };
18}
19
20if (!string.IsNullOrEmpty(emailFilter))
21{
22    query = emailOperator switch
23    {
24        "contains"     => query.Where(u => u.Email.Contains(emailFilter)),
25        "equals"       => query.Where(u => u.Email == emailFilter),
26        "startsWith"   => query.Where(u => u.Email.StartsWith(emailFilter)),
27        "endsWith"     => query.Where(u => u.Email.EndsWith(emailFilter)),
28        "notEquals"    => query.Where(u => u.Email != emailFilter),
29        "notContains"  => query.Where(u => !u.Email.Contains(emailFilter)),
30        "isEmpty"      => query.Where(u => string.IsNullOrEmpty(u.Email)),
31        "isNotEmpty"   => query.Where(u => !string.IsNullOrEmpty(u.Email)),
32        _              => query
33    };
34}
35
36if (!string.IsNullOrEmpty(countryFilter))
37{
38    query = countryOperator switch
39    {
40        "equals"       => query.Where(u => u.Country == countryFilter),
41        "notEquals"    => query.Where(u => u.Country != countryFilter),
42        "contains"     => query.Where(u => u.Country.Contains(countryFilter)),
43        _              => query
44    };
45}
46
47if (ageFilter.HasValue)
48{
49    query = ageOperator switch
50    {
51        "equals"        => query.Where(u => u.Age == ageFilter.Value),
52        "notEquals"     => query.Where(u => u.Age != ageFilter.Value),
53        "greater"       => query.Where(u => u.Age > ageFilter.Value),
54        "greaterOrEquals" => query.Where(u => u.Age >= ageFilter.Value),
55        "less"          => query.Where(u => u.Age < ageFilter.Value),
56        "lessOrEquals"  => query.Where(u => u.Age <= ageFilter.Value),
57        "between"       => query.Where(u => u.Age >= minAge && u.Age <= maxAge),
58        "notBetween"    => query.Where(u => u.Age < minAge || u.Age > maxAge),
59        _               => query
60    };
61}
62
63if (loginCountFilter.HasValue)
64{
65    query = loginCountOperator switch
66    {
67        "equals"    => query.Where(u => u.LoginCount == loginCountFilter.Value),
68        "greater"   => query.Where(u => u.LoginCount > loginCountFilter.Value),
69        "less"      => query.Where(u => u.LoginCount < loginCountFilter.Value),
70        _           => query
71    };
72}
73
74if (scoreFilter.HasValue)
75{
76    query = scoreOperator switch
77    {
78        "equals"    => query.Where(u => u.Score == scoreFilter.Value),
79        "notEquals" => query.Where(u => u.Score != scoreFilter.Value),
80        _           => query
81    };
82}
83
84if (isActiveFilter.HasValue)
85{
86    query = query.Where(u => u.IsActive == isActiveFilter.Value);
87}
88
89if (isAdminFilter.HasValue)
90{
91    query = query.Where(u => u.IsAdmin == isAdminFilter.Value);
92}
93
94if (createdAtFilter.HasValue)
95{
96    query = createdAtOperator switch
97    {
98        "before"       => query.Where(u => u.CreatedAt < createdAtFilter.Value),
99        "after"        => query.Where(u => u.CreatedAt > createdAtFilter.Value),
100        "equals"       => query.Where(u => u.CreatedAt.Date == createdAtFilter.Value.Date),
101        "notEquals"    => query.Where(u => u.CreatedAt.Date != createdAtFilter.Value.Date),
102        "between"      => query.Where(u => u.CreatedAt >= minCreatedAt && u.CreatedAt <= maxCreatedAt),
103        _              => query
104    };
105}
106
107if (moneyAmountFilter.HasValue)
108{
109    query = moneyAmountOperator switch
110    {
111        "equals"       => query.Where(u => u.MoneyAmount == moneyAmountFilter.Value),
112        "greater"      => query.Where(u => u.MoneyAmount > moneyAmountFilter.Value),
113        "less"         => query.Where(u => u.MoneyAmount < moneyAmountFilter.Value),
114        "between"      => query.Where(u => u.MoneyAmount >= minAmount && u.MoneyAmount <= maxAmount),
115        _              => query
116    };
117}
118
119// ... répéter pour chaque propriété
120var result = query.ToList();

Avec Superfilter

Clean, type-safe ConfigurationBuilder API

1// New ConfigurationBuilder API - Type-safe & Clean
2[HttpPost("search")]
3public async Task<IActionResult> SearchUsers([FromBody] UserSearchRequest request)
4{
5    // 1. Create configuration with clean, type-safe property mappings
6    var superfilter = SuperfilterBuilder.For<User>()
7        .MapRequiredProperty(u => u.Id)                  // No casting required!
8        .MapProperty(u => u.Car.Brand.Name)              // Nested navigation supported
9        .MapProperty(u => u.Name)                        // IntelliSense support
10        .MapProperty(u => u.isAdmin)
11        // Add for each property you want it to be filterable
12        .WithFilters(request.Filters)                    // Dynamic filters from client
13        .WithSorts(request.Sorts)                        // Dynamic sorts from client
14        .Build();
15
16    // 2. Apply filtering and sorting
17    var query = _context.Users.AsQueryable();
18    query = superfilter.ApplyConfiguredFilters(query);
19    query = query.ApplySorting(superfilter);
20
21    // 3. Execute query
22    return Ok(await query.ToListAsync());
23}

Pourquoi Superfilter ?

Performance d'Abord

Génère des expressions LINQ optimisées qui se traduisent en requêtes SQL efficaces

Flexible & Intuitif

Syntaxe simple basée sur JSON qui est facile à comprendre et à implémenter

Léger

Dépendances minimales et empreinte réduite pour vos applications

Type Safe

Intellisense complet et sécurité à la compilation