(bugfix): paged request filter should be predicate
This commit is contained in:
parent
896bcba334
commit
39d97500e9
@ -1,10 +1,12 @@
|
|||||||
namespace MaksIT.Core.Tests.Webapi.Models;
|
using System.Linq;
|
||||||
|
using Xunit;
|
||||||
|
using MaksIT.Core.Webapi.Models; // Ensure namespace matches the actual namespace of PagedRequest
|
||||||
|
|
||||||
public class PagedRequestTests {
|
public class PagedRequestTests {
|
||||||
|
|
||||||
public class TestEntity {
|
public class TestEntity {
|
||||||
public string? Name { get; set; }
|
public required string Name { get; set; }
|
||||||
public int Age { get; set; }
|
public required int Age { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup a mock IQueryable to test against
|
// Setup a mock IQueryable to test against
|
||||||
@ -17,7 +19,7 @@ public class PagedRequestTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyFilters_ShouldHandleEqualsOperator() {
|
public void BuildFilterExpression_ShouldHandleEqualsOperator() {
|
||||||
// Arrange
|
// Arrange
|
||||||
var queryable = GetTestQueryable();
|
var queryable = GetTestQueryable();
|
||||||
var request = new PagedRequest {
|
var request = new PagedRequest {
|
||||||
@ -25,147 +27,131 @@ public class PagedRequestTests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var filtered = request.ApplyFilters(queryable);
|
var predicate = request.BuildFilterExpression<TestEntity>();
|
||||||
|
var filtered = queryable.Where(predicate).ToList();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Contains(filtered, t => t.Name == "John");
|
Assert.Contains(filtered, t => t.Name == "John");
|
||||||
Assert.Single(filtered);
|
Assert.Single(filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add similar changes for other tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyFilters_ShouldHandleNotEqualsOperator() {
|
public void BuildFilterExpression_ShouldHandleNotEqualsOperator() {
|
||||||
// Arrange
|
|
||||||
var queryable = GetTestQueryable();
|
var queryable = GetTestQueryable();
|
||||||
var request = new PagedRequest {
|
var request = new PagedRequest {
|
||||||
Filters = "Name != \"John\""
|
Filters = "Name != \"John\""
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
var predicate = request.BuildFilterExpression<TestEntity>();
|
||||||
var filtered = request.ApplyFilters(queryable);
|
var filtered = queryable.Where(predicate).ToList();
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.DoesNotContain(filtered, t => t.Name == "John");
|
Assert.DoesNotContain(filtered, t => t.Name == "John");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyFilters_ShouldHandleGreaterThanOperator() {
|
public void BuildFilterExpression_ShouldHandleGreaterThanOperator() {
|
||||||
// Arrange
|
|
||||||
var queryable = GetTestQueryable();
|
var queryable = GetTestQueryable();
|
||||||
var request = new PagedRequest {
|
var request = new PagedRequest {
|
||||||
Filters = "Age > 30"
|
Filters = "Age > 30"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
var predicate = request.BuildFilterExpression<TestEntity>();
|
||||||
var filtered = request.ApplyFilters(queryable);
|
var filtered = queryable.Where(predicate).ToList();
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.All(filtered, t => Assert.True(t.Age > 30));
|
Assert.All(filtered, t => Assert.True(t.Age > 30));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyFilters_ShouldHandleLessThanOperator() {
|
public void BuildFilterExpression_ShouldHandleLessThanOperator() {
|
||||||
// Arrange
|
|
||||||
var queryable = GetTestQueryable();
|
var queryable = GetTestQueryable();
|
||||||
var request = new PagedRequest {
|
var request = new PagedRequest {
|
||||||
Filters = "Age < 30"
|
Filters = "Age < 30"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
var predicate = request.BuildFilterExpression<TestEntity>();
|
||||||
var filtered = request.ApplyFilters(queryable);
|
var filtered = queryable.Where(predicate).ToList();
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.All(filtered, t => Assert.True(t.Age < 30));
|
Assert.All(filtered, t => Assert.True(t.Age < 30));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyFilters_ShouldHandleAndOperator() {
|
public void BuildFilterExpression_ShouldHandleAndOperator() {
|
||||||
// Arrange
|
|
||||||
var queryable = GetTestQueryable();
|
var queryable = GetTestQueryable();
|
||||||
var request = new PagedRequest {
|
var request = new PagedRequest {
|
||||||
Filters = "Name == \"John\" && Age > 30"
|
Filters = "Name == \"John\" && Age > 30"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
var predicate = request.BuildFilterExpression<TestEntity>();
|
||||||
var filtered = request.ApplyFilters(queryable);
|
var filtered = queryable.Where(predicate).ToList();
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Contains(filtered, t => t.Name == "John" && t.Age > 30);
|
Assert.Contains(filtered, t => t.Name == "John" && t.Age > 30);
|
||||||
Assert.Single(filtered);
|
Assert.Single(filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyFilters_ShouldHandleOrOperator() {
|
public void BuildFilterExpression_ShouldHandleOrOperator() {
|
||||||
// Arrange
|
|
||||||
var queryable = GetTestQueryable();
|
var queryable = GetTestQueryable();
|
||||||
var request = new PagedRequest {
|
var request = new PagedRequest {
|
||||||
Filters = "Name == \"John\" || Age > 30"
|
Filters = "Name == \"John\" || Age > 30"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
var predicate = request.BuildFilterExpression<TestEntity>();
|
||||||
var filtered = request.ApplyFilters(queryable);
|
var filtered = queryable.Where(predicate).ToList();
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Contains(filtered, t => t.Name == "John" || t.Age > 30);
|
Assert.Contains(filtered, t => t.Name == "John" || t.Age > 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyFilters_ShouldHandleNegation() {
|
public void BuildFilterExpression_ShouldHandleNegation() {
|
||||||
// Arrange
|
|
||||||
var queryable = GetTestQueryable();
|
var queryable = GetTestQueryable();
|
||||||
var request = new PagedRequest {
|
var request = new PagedRequest {
|
||||||
Filters = "!(Name == \"John\")"
|
Filters = "!(Name == \"John\")"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
var predicate = request.BuildFilterExpression<TestEntity>();
|
||||||
var filtered = request.ApplyFilters(queryable);
|
var filtered = queryable.Where(predicate).ToList();
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.DoesNotContain(filtered, t => t.Name == "John");
|
Assert.DoesNotContain(filtered, t => t.Name == "John");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyFilters_ShouldHandleContainsOperator() {
|
public void BuildFilterExpression_ShouldHandleContainsOperator() {
|
||||||
// Arrange
|
|
||||||
var queryable = GetTestQueryable();
|
var queryable = GetTestQueryable();
|
||||||
var request = new PagedRequest {
|
var request = new PagedRequest {
|
||||||
Filters = "Name.Contains(\"oh\")"
|
Filters = "Name.Contains(\"oh\")"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
var predicate = request.BuildFilterExpression<TestEntity>();
|
||||||
var filtered = request.ApplyFilters(queryable);
|
var filtered = queryable.Where(predicate).ToList();
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Contains(filtered, t => t.Name.Contains("oh"));
|
Assert.Contains(filtered, t => t.Name.Contains("oh"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyFilters_ShouldHandleStartsWithOperator() {
|
public void BuildFilterExpression_ShouldHandleStartsWithOperator() {
|
||||||
// Arrange
|
|
||||||
var queryable = GetTestQueryable();
|
var queryable = GetTestQueryable();
|
||||||
var request = new PagedRequest {
|
var request = new PagedRequest {
|
||||||
Filters = "Name.StartsWith(\"Jo\")"
|
Filters = "Name.StartsWith(\"Jo\")"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
var predicate = request.BuildFilterExpression<TestEntity>();
|
||||||
var filtered = request.ApplyFilters(queryable);
|
var filtered = queryable.Where(predicate).ToList();
|
||||||
|
|
||||||
// Assert
|
Assert.Contains(filtered, t => t.Name.StartsWith("Jo"));
|
||||||
Assert.Contains(filtered, t => t.Name.StartsWith("John"));
|
Assert.Single(filtered); // Assuming only "John" starts with "Jo"
|
||||||
Assert.Single(filtered); // Assuming only "Johnny" starts with "John"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplyFilters_ShouldHandleEndsWithOperator() {
|
public void BuildFilterExpression_ShouldHandleEndsWithOperator() {
|
||||||
// Arrange
|
|
||||||
var queryable = GetTestQueryable();
|
var queryable = GetTestQueryable();
|
||||||
var request = new PagedRequest {
|
var request = new PagedRequest {
|
||||||
Filters = "Name.EndsWith(\"hn\")"
|
Filters = "Name.EndsWith(\"hn\")"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
var predicate = request.BuildFilterExpression<TestEntity>();
|
||||||
var filtered = request.ApplyFilters(queryable);
|
var filtered = queryable.Where(predicate).ToList();
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Contains(filtered, t => t.Name.EndsWith("hn"));
|
Assert.Contains(filtered, t => t.Name.EndsWith("hn"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<!-- NuGet package metadata -->
|
<!-- NuGet package metadata -->
|
||||||
<PackageId>MaksIT.Core</PackageId>
|
<PackageId>MaksIT.Core</PackageId>
|
||||||
<Version>1.2.9</Version>
|
<Version>1.3.0</Version>
|
||||||
<Authors>Maksym Sadovnychyy</Authors>
|
<Authors>Maksym Sadovnychyy</Authors>
|
||||||
<Company>MAKS-IT</Company>
|
<Company>MAKS-IT</Company>
|
||||||
<Product>MaksIT.Core</Product>
|
<Product>MaksIT.Core</Product>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
using System.Linq.Dynamic.Core;
|
using System.Linq.Dynamic.Core;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using MaksIT.Core.Abstractions.Webapi;
|
using MaksIT.Core.Abstractions.Webapi;
|
||||||
|
|
||||||
public class PagedRequest : RequestModelBase {
|
public class PagedRequest : RequestModelBase {
|
||||||
@ -10,16 +10,22 @@ public class PagedRequest : RequestModelBase {
|
|||||||
public string? SortBy { get; set; }
|
public string? SortBy { get; set; }
|
||||||
public bool IsAscending { get; set; } = true;
|
public bool IsAscending { get; set; } = true;
|
||||||
|
|
||||||
public IQueryable<T> ApplyFilters<T>(IQueryable<T> query) {
|
public Expression<Func<T, bool>> BuildFilterExpression<T>() {
|
||||||
if (!string.IsNullOrWhiteSpace(Filters)) {
|
if (string.IsNullOrWhiteSpace(Filters))
|
||||||
query = query.Where(Filters); // Filters interpreted directly
|
return x => true; // Returns an expression that doesn't filter anything.
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(SortBy)) {
|
// Parse the filter string into a dynamic lambda expression.
|
||||||
var direction = IsAscending ? "ascending" : "descending";
|
var predicate = DynamicExpressionParser.ParseLambda<T, bool>(
|
||||||
query = query.OrderBy($"{SortBy} {direction}");
|
new ParsingConfig(), false, Filters);
|
||||||
}
|
return predicate;
|
||||||
|
}
|
||||||
|
|
||||||
return query.Skip((PageNumber - 1) * PageSize).Take(PageSize);
|
public Func<IQueryable<T>, IOrderedQueryable<T>> BuildSortExpression<T>() {
|
||||||
|
if (string.IsNullOrWhiteSpace(SortBy))
|
||||||
|
return q => (IOrderedQueryable<T>)q; // Cast to IOrderedQueryable
|
||||||
|
|
||||||
|
var direction = IsAscending ? "ascending" : "descending";
|
||||||
|
// Return a Func that takes an IQueryable and applies the sorting to it.
|
||||||
|
return q => (IOrderedQueryable<T>)q.OrderBy($"{SortBy} {direction}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user