From 5ec4465a5a0194a2e83a8b0e8617c5183d1e55cc Mon Sep 17 00:00:00 2001 From: Maksym Sadovnychyy Date: Sun, 13 Oct 2024 17:03:58 +0200 Subject: [PATCH] (feature): webapi base models --- .../Abstractions/Webapi/RequestModelBase.cs | 9 ++ .../Abstractions/Webapi/ResponseModelBase.cs | 9 ++ src/MaksIT.Core/MaksIT.Core.csproj | 2 +- src/MaksIT.Core/Webapi/Models/PagedRequest.cs | 118 ++++++++++++++++++ .../Webapi/Models/PagedResponse.cs | 20 +++ 5 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 src/MaksIT.Core/Abstractions/Webapi/RequestModelBase.cs create mode 100644 src/MaksIT.Core/Abstractions/Webapi/ResponseModelBase.cs create mode 100644 src/MaksIT.Core/Webapi/Models/PagedRequest.cs create mode 100644 src/MaksIT.Core/Webapi/Models/PagedResponse.cs diff --git a/src/MaksIT.Core/Abstractions/Webapi/RequestModelBase.cs b/src/MaksIT.Core/Abstractions/Webapi/RequestModelBase.cs new file mode 100644 index 0000000..c195bd5 --- /dev/null +++ b/src/MaksIT.Core/Abstractions/Webapi/RequestModelBase.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MaksIT.Core.Abstractions.Webapi; +public abstract class RequestModelBase { +} diff --git a/src/MaksIT.Core/Abstractions/Webapi/ResponseModelBase.cs b/src/MaksIT.Core/Abstractions/Webapi/ResponseModelBase.cs new file mode 100644 index 0000000..0be10f8 --- /dev/null +++ b/src/MaksIT.Core/Abstractions/Webapi/ResponseModelBase.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MaksIT.Core.Abstractions.Webapi; +public abstract class ResponseModelBase { +} diff --git a/src/MaksIT.Core/MaksIT.Core.csproj b/src/MaksIT.Core/MaksIT.Core.csproj index 043bb78..d6232ba 100644 --- a/src/MaksIT.Core/MaksIT.Core.csproj +++ b/src/MaksIT.Core/MaksIT.Core.csproj @@ -8,7 +8,7 @@ MaksIT.Core - 1.0.8 + 1.0.9 Maksym Sadovnychyy MAKS-IT MaksIT.Core diff --git a/src/MaksIT.Core/Webapi/Models/PagedRequest.cs b/src/MaksIT.Core/Webapi/Models/PagedRequest.cs new file mode 100644 index 0000000..2fa78ac --- /dev/null +++ b/src/MaksIT.Core/Webapi/Models/PagedRequest.cs @@ -0,0 +1,118 @@ +using System.Linq.Expressions; + +using MaksIT.Core.Abstractions.Webapi; + +namespace MaksIT.Core.Webapi.Models; +public abstract class PagedRequest : RequestModelBase { + public int PageSize { get; set; } = 100; + public int PageNumber { get; set; } = 1; + + // Global filter applicable to any collection + public string? Filters { get; set; } + + // Specific filters for different collections + public Dictionary? CollectionFilters { get; set; } + + // Optional sorting + public string? SortBy { get; set; } + public bool IsAscending { get; set; } = true; + + // Method to build an expression for a specific collection, combining global and collection-specific filters + public Expression> BuildCollectionFilterExpression(string collectionName) { + var expressions = new List(); + + var parameter = Expression.Parameter(typeof(T), "x"); + + // Add global filters if available + if (!string.IsNullOrEmpty(Filters)) { + var globalFilterExpression = BuildFilterExpression(Filters, parameter); + expressions.Add(globalFilterExpression); + } + + // Add collection-specific filters if available + if (CollectionFilters != null && CollectionFilters.ContainsKey(collectionName) && !string.IsNullOrEmpty(CollectionFilters[collectionName])) { + var collectionFilterExpression = BuildFilterExpression(CollectionFilters[collectionName], parameter); + expressions.Add(collectionFilterExpression); + } + + // Combine the expressions using AND (you can extend to OR logic if needed) + Expression combinedExpression; + if (expressions.Any()) { + combinedExpression = expressions.Aggregate(Expression.AndAlso); + } + else { + // Default to 'true' if no filters are provided + combinedExpression = Expression.Constant(true); + } + + return Expression.Lambda>(combinedExpression, parameter); + } + + // Method to build a LINQ expression from a single filter string (global or collection-specific) + public Expression> BuildFilterExpression(string filter, ParameterExpression? parameter = null) { + if (string.IsNullOrEmpty(filter)) + return x => true; // Default to 'true' if no filters are provided + + parameter ??= Expression.Parameter(typeof(T), "x"); + var expressions = new List(); + + // Parse the filters string (this logic can be extended to support more complex filtering) + var filters = filter.Split(new[] { "AND", "OR" }, StringSplitOptions.None); + + foreach (var subFilter in filters) { + if (subFilter.Contains('=')) { + var parts = subFilter.Split('='); + var propertyName = parts[0].Trim(); + var value = parts[1].Trim().Replace("'", ""); + + var property = Expression.Property(parameter, propertyName); + var constant = Expression.Constant(ConvertValue(property.Type, value)); + + expressions.Add(Expression.Equal(property, constant)); + } + else if (subFilter.Contains('>') || subFilter.Contains('<')) { + var comparisonType = subFilter.Contains(">=") ? ">=" : + subFilter.Contains("<=") ? "<=" : + subFilter.Contains(">") ? ">" : "<"; + var parts = subFilter.Split(new[] { '>', '<', '=', ' ' }, StringSplitOptions.RemoveEmptyEntries); + var propertyName = parts[0].Trim(); + var value = parts[1].Trim().Replace("'", ""); + + var property = Expression.Property(parameter, propertyName); + var constant = Expression.Constant(ConvertValue(property.Type, value)); + + switch (comparisonType) { + case ">": + expressions.Add(Expression.GreaterThan(property, constant)); + break; + case "<": + expressions.Add(Expression.LessThan(property, constant)); + break; + case ">=": + expressions.Add(Expression.GreaterThanOrEqual(property, constant)); + break; + case "<=": + expressions.Add(Expression.LessThanOrEqual(property, constant)); + break; + } + } + } + + // Combine the expressions using AND (you can extend to support OR) + var combinedExpression = expressions.Aggregate(Expression.AndAlso); + + return Expression.Lambda>(combinedExpression, parameter); + } + + // Helper method to convert the value to the correct type + private static object ConvertValue(Type type, string value) { + if (type == typeof(int)) + return int.Parse(value); + if (type == typeof(bool)) + return bool.Parse(value); + if (type == typeof(DateTime)) + return DateTime.Parse(value); + + return value; // Default to string + } +} diff --git a/src/MaksIT.Core/Webapi/Models/PagedResponse.cs b/src/MaksIT.Core/Webapi/Models/PagedResponse.cs new file mode 100644 index 0000000..8f1e49f --- /dev/null +++ b/src/MaksIT.Core/Webapi/Models/PagedResponse.cs @@ -0,0 +1,20 @@ +using MaksIT.Core.Abstractions.Webapi; + +namespace MaksIT.Core.Webapi.Models; + +public class PagedResponse : ResponseModelBase { + public IEnumerable Items { get; set; } + public int PageNumber { get; set; } + public int PageSize { get; set; } + public int TotalCount { get; set; } + public int TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize); + public bool HasPreviousPage => PageNumber > 1; + public bool HasNextPage => PageNumber < TotalPages; + + public PagedResponse(IEnumerable items, int totalCount, int pageNumber, int pageSize) { + Items = items; + TotalCount = totalCount; + PageNumber = pageNumber; + PageSize = pageSize; + } +} \ No newline at end of file