diff --git a/API/Dispo.API/Controllers/DatatableController.cs b/API/Dispo.API/Controllers/DatatableController.cs
new file mode 100644
index 0000000..b8108f4
--- /dev/null
+++ b/API/Dispo.API/Controllers/DatatableController.cs
@@ -0,0 +1,105 @@
+using Dispo.API.ResponseBuilder;
+using Dispo.Shared.Core.Domain.Interfaces;
+using Dispo.Shared.Filter.Model;
+using Dispo.Shared.Filter.Services;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Dispo.API.Controllers
+{
+ [Route("api/v1/datatable")]
+ [ApiController]
+ [Authorize]
+ public class DatatableController : ControllerBase
+ {
+ private readonly IDatatableRepository _datatableRepository;
+ private readonly IFilterService _filterService;
+
+ public DatatableController(IDatatableRepository datatableRepository, IFilterService filterService)
+ {
+ _datatableRepository = datatableRepository;
+ _filterService = filterService;
+ }
+
+ [HttpGet("get-count")]
+ public IActionResult GetCount([FromQuery] string entity)
+ {
+ var type = Type.GetType($"Dispo.Shared.Core.Domain.Entities.{entity}, Dispo.Shared.Core.Domain");
+ if (type is null)
+ {
+ return BadRequest("Entidade inválida.");
+ }
+
+ var method = _datatableRepository.GetType().GetMethod("GetTotalRecords");
+ if (method is null)
+ {
+ return BadRequest($"Método 'GetTotalRecords' não implementado para a entidade '{entity}'");
+ }
+
+ var genericMethod = method.MakeGenericMethod(type);
+ var result = genericMethod.Invoke(_datatableRepository, new object[] {});
+
+ return Ok(new ResponseModelBuilder().WithData(result)
+ .WithSuccess(true)
+ .WithAlert(AlertType.Success)
+ .Build());
+ }
+
+ [HttpGet("get-all")]
+ public IActionResult Get([FromQuery] PaginationModel paginationModel)
+ {
+ dynamic datatableData = null;
+
+ if (paginationModel.Entity == "Manufacturer")
+ {
+ datatableData = _datatableRepository.GetToDatatableManufacturer(paginationModel.PageNumber, paginationModel.PageSize).ToList();
+ }
+ else if (paginationModel.Entity == "Product")
+ {
+ datatableData = _datatableRepository.GetToDatatableProduct(paginationModel.PageNumber, paginationModel.PageSize).ToList();
+ }
+ else if (paginationModel.Entity == "Supplier")
+ {
+ datatableData = _datatableRepository.GetToDatatableSupplier(paginationModel.PageNumber, paginationModel.PageSize).ToList();
+ }
+
+
+ return Ok(new ResponseModelBuilder().WithData(datatableData)
+ .WithSuccess(true)
+ .WithAlert(AlertType.Success)
+ .Build());
+ }
+
+ [HttpPost("get-by-filter")]
+ public IActionResult GetByFilter([FromBody] FilterModel filter)
+ {
+ try
+ {
+ var type = Type.GetType($"Dispo.Shared.Core.Domain.Entities.{filter.Entity}, Dispo.Shared.Core.Domain");
+ if (type is null)
+ {
+ return BadRequest("Entidade inválida.");
+ }
+
+ var method = _filterService.GetType().GetMethod("Get");
+ if (method is null)
+ {
+ return BadRequest($"Método 'Get' não implementado para a entidade '{filter.Entity}'");
+ }
+
+ var genericMethod = method.MakeGenericMethod(type);
+ var result = genericMethod.Invoke(_filterService, new object[] { filter });
+
+ return Ok(new ResponseModelBuilder().WithData(result)
+ .WithSuccess(true)
+ .Build());
+ }
+ catch (Exception ex)
+ {
+ return BadRequest(new ResponseModelBuilder().WithMessage(ex.Message)
+ .WithSuccess(false)
+ .Build()); ;
+ }
+ }
+ }
+}
diff --git a/API/Dispo.API/Dispo.API.csproj b/API/Dispo.API/Dispo.API.csproj
index 9ffae8d..6800f96 100644
--- a/API/Dispo.API/Dispo.API.csproj
+++ b/API/Dispo.API/Dispo.API.csproj
@@ -31,6 +31,7 @@
+
diff --git a/API/Dispo.API/Dispo.API.sln b/API/Dispo.API/Dispo.API.sln
index f540800..32fba8e 100644
--- a/API/Dispo.API/Dispo.API.sln
+++ b/API/Dispo.API/Dispo.API.sln
@@ -65,7 +65,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dispo.Infra.Infrastructure.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dispo.Infra.Plugin", "..\..\src\Modules\Infra\Dispo.Infra.Plugin\Dispo.Infra.Plugin.csproj", "{FC7852D4-961C-4A2E-A77D-F32F72D12608}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dispo.Shared.Log", "..\..\src\Modules\Shared\Dispo.Shared.Log\Dispo.Shared.Log.csproj", "{9DF2CC91-7E5B-450D-B281-EA8D0C66A474}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dispo.Shared.Log", "..\..\src\Modules\Shared\Dispo.Shared.Log\Dispo.Shared.Log.csproj", "{9DF2CC91-7E5B-450D-B281-EA8D0C66A474}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dispo.Shared.Filter", "..\..\src\Modules\Shared\Dispo.Shared.Filter\Dispo.Shared.Filter.csproj", "{98098519-4E21-4796-A422-0451709588EA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -161,6 +163,10 @@ Global
{9DF2CC91-7E5B-450D-B281-EA8D0C66A474}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9DF2CC91-7E5B-450D-B281-EA8D0C66A474}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9DF2CC91-7E5B-450D-B281-EA8D0C66A474}.Release|Any CPU.Build.0 = Release|Any CPU
+ {98098519-4E21-4796-A422-0451709588EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {98098519-4E21-4796-A422-0451709588EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {98098519-4E21-4796-A422-0451709588EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {98098519-4E21-4796-A422-0451709588EA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -195,6 +201,7 @@ Global
{16FD027B-42F0-4176-AD7D-FC83ED649ED5} = {B6DEED8C-370C-4FC7-858B-73A9CCB41F86}
{FC7852D4-961C-4A2E-A77D-F32F72D12608} = {B6DEED8C-370C-4FC7-858B-73A9CCB41F86}
{9DF2CC91-7E5B-450D-B281-EA8D0C66A474} = {A26E43DA-73D5-449E-BE45-9E7A88E5E4A2}
+ {98098519-4E21-4796-A422-0451709588EA} = {A26E43DA-73D5-449E-BE45-9E7A88E5E4A2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3375A49-13C9-4341-A913-D223CE4E41FC}
diff --git a/src/Modules/Infra/Dispo.Infra.Core.Application/Dispo.Infra.Core.Application.csproj b/src/Modules/Infra/Dispo.Infra.Core.Application/Dispo.Infra.Core.Application.csproj
index 9b2c1f3..50e206a 100644
--- a/src/Modules/Infra/Dispo.Infra.Core.Application/Dispo.Infra.Core.Application.csproj
+++ b/src/Modules/Infra/Dispo.Infra.Core.Application/Dispo.Infra.Core.Application.csproj
@@ -12,8 +12,8 @@
-
-
+
+
diff --git a/src/Modules/Infra/Dispo.Infra.Infrastructure.Ioc/Dispo.Infra.Infrastructure.Ioc.csproj b/src/Modules/Infra/Dispo.Infra.Infrastructure.Ioc/Dispo.Infra.Infrastructure.Ioc.csproj
index 1d01ddc..ba5f395 100644
--- a/src/Modules/Infra/Dispo.Infra.Infrastructure.Ioc/Dispo.Infra.Infrastructure.Ioc.csproj
+++ b/src/Modules/Infra/Dispo.Infra.Infrastructure.Ioc/Dispo.Infra.Infrastructure.Ioc.csproj
@@ -12,6 +12,7 @@
+
diff --git a/src/Modules/Infra/Dispo.Infra.Infrastructure.Ioc/Injector.cs b/src/Modules/Infra/Dispo.Infra.Infrastructure.Ioc/Injector.cs
index d495690..7616429 100644
--- a/src/Modules/Infra/Dispo.Infra.Infrastructure.Ioc/Injector.cs
+++ b/src/Modules/Infra/Dispo.Infra.Infrastructure.Ioc/Injector.cs
@@ -2,6 +2,7 @@
using Dispo.Infra.Core.Application.Services;
using Dispo.Infra.Infrastructure.Persistence.Repositories;
using Dispo.Shared.Core.Domain.Interfaces;
+using Dispo.Shared.Filter.Services;
using Microsoft.Extensions.DependencyInjection;
namespace Dispo.Infra.Infrastructure.Ioc
@@ -20,6 +21,8 @@ private static void InjectRepositories(IServiceCollection serviceColletion)
serviceColletion.AddScoped();
serviceColletion.AddScoped();
serviceColletion.AddScoped();
+
+ serviceColletion.AddScoped();
}
private static void InjectServices(IServiceCollection serviceColletion)
@@ -29,6 +32,7 @@ private static void InjectServices(IServiceCollection serviceColletion)
serviceColletion.AddScoped();
serviceColletion.AddScoped();
serviceColletion.AddScoped();
+ serviceColletion.AddScoped();
}
}
}
\ No newline at end of file
diff --git a/src/Modules/Infra/Dispo.Infra.Infrastructure.Persistence/Repositories/DatatableRepository.cs b/src/Modules/Infra/Dispo.Infra.Infrastructure.Persistence/Repositories/DatatableRepository.cs
new file mode 100644
index 0000000..0a0024b
--- /dev/null
+++ b/src/Modules/Infra/Dispo.Infra.Infrastructure.Persistence/Repositories/DatatableRepository.cs
@@ -0,0 +1,122 @@
+using Dispo.Shared.Core.Domain.DTOs;
+using Dispo.Shared.Core.Domain.Entities;
+using Dispo.Shared.Core.Domain.Interfaces;
+using Dispo.Shared.Infrastructure.Persistence;
+using Dispo.Shared.Infrastructure.Persistence.Context;
+using Dispo.Shared.Utils.Extensions;
+using Microsoft.EntityFrameworkCore;
+
+namespace Dispo.Infra.Infrastructure.Persistence.Repositories
+{
+ public class DatatableRepository : BaseRepository, IDatatableRepository
+ {
+ private readonly DispoContext _dispoContext;
+
+ public DatatableRepository(DispoContext dispoContext) : base(dispoContext)
+ {
+ _dispoContext = dispoContext;
+ }
+
+ public int GetTotalRecords() where T : EntityBase
+ => _dispoContext.Set()
+ .AsNoTracking()
+ .Count();
+
+ //public IEnumerable GetToDatatable(int pageNumber, int pageSize)
+ // => _dispoContext.Manufacturers.Skip((pageNumber - 1) * pageSize)
+ // .Take(pageSize)
+ // .Select(s => new ManufacturerInfoDto()
+ // {
+ // Id = s.Id,
+ // Name = s.Name,
+ // })
+ // .ToList();
+
+ public IEnumerable GetToDatatableProduct(int pageNumber, int pageSize)
+ => _dispoContext.Set().Skip((pageNumber - 1) * pageSize)
+ .Take(pageSize)
+ .Select(product => new ProductDatatableDto
+ {
+ Id = product.Id,
+ Name = product.Name,
+ PurchasePrice = product.PurchasePrice.ConvertToCurrency(),
+ SalePrice = product.SalePrice.ConvertToCurrency(),
+ Category = EnumExtension.ConvertToString(product.Category),
+ UnitOfMeasurement = EnumExtension.ConvertToString(product.UnitOfMeasurement),
+ })
+ .ToList();
+
+ public IEnumerable GetToDatatableManufacturer(int pageNumber, int pageSize)
+ => _dispoContext.Set().Skip((pageNumber - 1) * pageSize)
+ .Take(pageSize)
+ .Select(manufacturer => new ManufacturerDatatableDto
+ {
+ Id = manufacturer.Id,
+ Name = manufacturer.Name,
+ })
+ .ToList();
+
+ public IEnumerable GetToDatatableSupplier(int pageNumber, int pageSize)
+ => _dispoContext.Set().Skip((pageNumber - 1) * pageSize)
+ .Take(pageSize)
+ .Select(supplier => new SupplierDatatableDto
+ {
+ Id = supplier.Id,
+ Name = supplier.Name,
+ ContactName = supplier.ContactName,
+ Cnpj = supplier.Cnpj,
+ Email = supplier.Email,
+ Phone = supplier.Phone,
+ })
+ .ToList();
+
+
+
+ public IEnumerable GetToDatatable(int pageNumber, int pageSize) where TEntity : EntityBase
+ => _dispoContext.Set().Skip((pageNumber - 1) * pageSize)
+ .Take(pageSize)
+ .Select(ConvertToDatabaseDto)
+ .ToList();
+
+ private EntityDatatableDto ConvertToDatabaseDto(TEntity entity) where TEntity : EntityBase
+ {
+ if (typeof(TEntity) == typeof(Product))
+ {
+ var product = entity as Product;
+ return new ProductDatatableDto
+ {
+ Id = product.Id,
+ Name = product.Name,
+ PurchasePrice = product.PurchasePrice.ConvertToCurrency(),
+ SalePrice = product.SalePrice.ConvertToCurrency(),
+ Category = EnumExtension.ConvertToString(product.Category),
+ UnitOfMeasurement = EnumExtension.ConvertToString(product.UnitOfMeasurement),
+ };
+ }
+ else if (typeof(TEntity) == typeof(Manufacturer))
+ {
+ var manufacturer = entity as Manufacturer;
+ return new ManufacturerDatatableDto
+ {
+ Id = manufacturer.Id,
+ Name = manufacturer.Name,
+ };
+ }
+ else if (typeof(TEntity) == typeof(Supplier))
+ {
+ var supplier = entity as Supplier;
+ return new SupplierDatatableDto
+ {
+ Id = supplier.Id,
+ Name = supplier.Name,
+ ContactName = supplier.ContactName,
+ Cnpj = supplier.Cnpj,
+ Email = supplier.Email,
+ Phone = supplier.Phone,
+ };
+ }
+
+ throw new NotImplementedException($"Entidade não encontrada {typeof(TEntity)}");
+ }
+ }
+}
diff --git a/src/Modules/Shared/Dispo.Shared.Core.Domain/DTOs/EntityDatatableDto.cs b/src/Modules/Shared/Dispo.Shared.Core.Domain/DTOs/EntityDatatableDto.cs
new file mode 100644
index 0000000..9c79706
--- /dev/null
+++ b/src/Modules/Shared/Dispo.Shared.Core.Domain/DTOs/EntityDatatableDto.cs
@@ -0,0 +1,30 @@
+namespace Dispo.Shared.Core.Domain.DTOs
+{
+ public class EntityDatatableDto
+ {
+ public long Id { get; set; }
+ }
+
+ public class ProductDatatableDto : EntityDatatableDto
+ {
+ public string Name { get; set; }
+ public string PurchasePrice { get; set; }
+ public string SalePrice { get; set; }
+ public string UnitOfMeasurement { get; set; }
+ public string Category { get; set; }
+ }
+
+ public class ManufacturerDatatableDto : EntityDatatableDto
+ {
+ public string Name { get; set; }
+ }
+
+ public class SupplierDatatableDto : EntityDatatableDto
+ {
+ public string Name { get; set; }
+ public string ContactName { get; set; }
+ public string Cnpj { get; set; }
+ public string Email { get; set; }
+ public string Phone { get; set; }
+ }
+}
diff --git a/src/Modules/Shared/Dispo.Shared.Core.Domain/Interfaces/IDatatableRepository.cs b/src/Modules/Shared/Dispo.Shared.Core.Domain/Interfaces/IDatatableRepository.cs
new file mode 100644
index 0000000..0f18ddf
--- /dev/null
+++ b/src/Modules/Shared/Dispo.Shared.Core.Domain/Interfaces/IDatatableRepository.cs
@@ -0,0 +1,14 @@
+using Dispo.Shared.Core.Domain.DTOs;
+using Dispo.Shared.Core.Domain.Entities;
+
+namespace Dispo.Shared.Core.Domain.Interfaces
+{
+ public interface IDatatableRepository
+ {
+ int GetTotalRecords() where T : EntityBase;
+ IEnumerable GetToDatatable(int pageNumber, int pageSize) where TEntity : EntityBase;
+ IEnumerable GetToDatatableProduct(int pageNumber, int pageSize);
+ IEnumerable GetToDatatableManufacturer(int pageNumber, int pageSize);
+ IEnumerable GetToDatatableSupplier(int pageNumber, int pageSize);
+ }
+}
diff --git a/src/Modules/Shared/Dispo.Shared.Filter/Dispo.Shared.Filter.csproj b/src/Modules/Shared/Dispo.Shared.Filter/Dispo.Shared.Filter.csproj
new file mode 100644
index 0000000..f7657de
--- /dev/null
+++ b/src/Modules/Shared/Dispo.Shared.Filter/Dispo.Shared.Filter.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/src/Modules/Shared/Dispo.Shared.Filter/Model/FilterModel.cs b/src/Modules/Shared/Dispo.Shared.Filter/Model/FilterModel.cs
new file mode 100644
index 0000000..994c5c3
--- /dev/null
+++ b/src/Modules/Shared/Dispo.Shared.Filter/Model/FilterModel.cs
@@ -0,0 +1,15 @@
+namespace Dispo.Shared.Filter.Model
+{
+ public class FilterModel
+ {
+ public required string Entity { get; set; }
+ public required List Properties { get; set; }
+ public required PaginationFilter PaginationConfig { get; set; }
+ }
+
+ public class PaginationFilter
+ {
+ public int PageNumber { get; set; }
+ public int PageSize { get; set; }
+ }
+}
diff --git a/src/Modules/Shared/Dispo.Shared.Filter/Model/PaginationFilter.cs b/src/Modules/Shared/Dispo.Shared.Filter/Model/PaginationFilter.cs
new file mode 100644
index 0000000..54ef0f4
--- /dev/null
+++ b/src/Modules/Shared/Dispo.Shared.Filter/Model/PaginationFilter.cs
@@ -0,0 +1,9 @@
+namespace Dispo.Shared.Filter.Model
+{
+ public class PaginationModel
+ {
+ public string Entity { get; set; }
+ public int PageNumber { get; set; }
+ public int PageSize { get; set; }
+ }
+}
diff --git a/src/Modules/Shared/Dispo.Shared.Filter/Model/PropertyModel.cs b/src/Modules/Shared/Dispo.Shared.Filter/Model/PropertyModel.cs
new file mode 100644
index 0000000..d85bcae
--- /dev/null
+++ b/src/Modules/Shared/Dispo.Shared.Filter/Model/PropertyModel.cs
@@ -0,0 +1,21 @@
+namespace Dispo.Shared.Filter.Model
+{
+ public class PropertyModel
+ {
+ public string Name { get; set; }
+ public dynamic Value { get; set; }
+ public SearchType SearchType { get; set; }
+ }
+
+ public enum SearchType
+ {
+ Equals,
+ Contains,
+ StartsWith,
+ EndsWith,
+ GreaterThan,
+ GreaterThanOrEqual,
+ LessThan,
+ LessThanOrEqual
+ }
+}
diff --git a/src/Modules/Shared/Dispo.Shared.Filter/Services/FilterService.cs b/src/Modules/Shared/Dispo.Shared.Filter/Services/FilterService.cs
new file mode 100644
index 0000000..a66b273
--- /dev/null
+++ b/src/Modules/Shared/Dispo.Shared.Filter/Services/FilterService.cs
@@ -0,0 +1,159 @@
+using Dispo.Shared.Core.Domain.Entities;
+using Dispo.Shared.Core.Domain.Enums;
+using Dispo.Shared.Filter.Model;
+using Dispo.Shared.Infrastructure.Persistence.Context;
+using Microsoft.EntityFrameworkCore;
+using System.Linq.Expressions;
+using System.Reflection.Metadata;
+using System.Text.Json;
+
+namespace Dispo.Shared.Filter.Services
+{
+ public class FilterService : IFilterService
+ {
+ private const string UnsupportedSearchTypeMessage = "Unsupported search type for property of type:";
+ private readonly DispoContext _dispoContext;
+
+ public FilterService(DispoContext dispoContext)
+ {
+ _dispoContext = dispoContext;
+ }
+
+ public object Get(FilterModel filterModel) where T : EntityBase
+ {
+ if (filterModel is null)
+ {
+ throw new ArgumentNullException(nameof(filterModel));
+ }
+
+ var buildExpression = BuildExpression(filterModel);
+
+ var recordCount = _dispoContext.Set()
+ .AsNoTracking()
+ .Where(buildExpression)
+ .Count();
+
+ var records = _dispoContext.Set()
+ .AsNoTracking()
+ .Where(buildExpression)
+ .Skip((filterModel.PaginationConfig.PageNumber - 1) * filterModel.PaginationConfig.PageSize)
+ .Take(filterModel.PaginationConfig.PageSize)
+ .ToList();
+
+ var obj = new
+ {
+ RecordCount = recordCount,
+ Records = records
+ };
+
+ return obj;
+ }
+
+ private Func BuildExpression(FilterModel filterModel)
+ {
+ var parameter = Expression.Parameter(typeof(T), filterModel.Entity);
+ Expression filterExpression = null;
+ foreach (var property in filterModel.Properties)
+ {
+ JsonElement jsonElementValue = property.Value;
+
+ var valueType = jsonElementValue.ValueKind;
+ Expression comparison;
+ var memberExpression = Expression.Property(parameter, property.Name);
+
+ if (valueType == JsonValueKind.String) // String
+ {
+ var valor = jsonElementValue.GetString();
+ var constant = Expression.Constant(valor);
+
+ comparison = Expression.Call(memberExpression, property.SearchType.ToString(), Type.EmptyTypes, constant);
+ }
+ else if (IsNumericType(memberExpression.Type, property.Value, out ConstantExpression convertedConstant) && valueType == JsonValueKind.Number) // Numerico
+ {
+ comparison = GetGenericComparisonExpression(memberExpression, property, convertedConstant);
+ }
+ else if (valueType == JsonValueKind.Object) // Enum
+ {
+ var valor = jsonElementValue.GetProperty("value").GetInt64();
+ var convertedValue = Enum.Parse(memberExpression.Type, valor.ToString());
+ var constant = Expression.Constant(convertedValue);
+ comparison = Expression.Equal(memberExpression, constant);
+
+ }
+ else if (IsDateTimeType(memberExpression.Type, property.Value, out DateTime convertedDateTime))
+ {
+ comparison = GetGenericComparisonExpression(memberExpression, property, Expression.Constant(convertedDateTime));
+ }
+ else
+ {
+ throw new NotSupportedException($"{UnsupportedSearchTypeMessage} {property.SearchType}");
+ }
+
+ filterExpression = filterExpression == null ? comparison : Expression.And(filterExpression, comparison);
+ }
+
+ return Expression.Lambda>(filterExpression ?? Expression.Constant(true), parameter).Compile();
+ }
+
+ private Expression GetStringComparisonExpression(MemberExpression memberExpression, PropertyModel property)
+ {
+ string convertedValue = Convert.ToString(property.Value);
+ var constant = Expression.Constant(convertedValue);
+
+ // Ao enviar o SearchType.Equals está disparando uma exceção.
+ return Expression.Call(memberExpression, property.SearchType.ToString(), Type.EmptyTypes, constant);
+ }
+
+ private Expression GetGenericComparisonExpression(MemberExpression memberExpression, PropertyModel property, ConstantExpression convertedConstant)
+ {
+ switch (property.SearchType)
+ {
+ case SearchType.Equals:
+ return Expression.Equal(memberExpression, convertedConstant);
+ case SearchType.GreaterThan:
+ return Expression.GreaterThan(memberExpression, convertedConstant);
+ case SearchType.GreaterThanOrEqual:
+ return Expression.GreaterThanOrEqual(memberExpression, convertedConstant);
+ case SearchType.LessThan:
+ return Expression.LessThan(memberExpression, convertedConstant);
+ case SearchType.LessThanOrEqual:
+ return Expression.LessThanOrEqual(memberExpression, convertedConstant);
+ default:
+ throw new NotSupportedException($"{UnsupportedSearchTypeMessage} {property.SearchType}");
+ }
+ }
+
+ private bool IsNumericType(Type type, object value, out ConstantExpression convertedConstant)
+ {
+ convertedConstant = null;
+ if (NumericTypes.Contains(type))
+ {
+ try
+ {
+ var convertedValue = Convert.ChangeType(Convert.ToString(value), type);
+ convertedConstant = Expression.Constant(convertedValue);
+ return true;
+ }
+ catch (InvalidCastException)
+ {
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ private bool IsDateTimeType(Type type, object value, out DateTime convertedDateTime)
+ {
+ convertedDateTime = DateTime.MinValue;
+ return type == typeof(DateTime) && DateTime.TryParse(Convert.ToString(value), out convertedDateTime);
+ }
+
+ private static readonly HashSet NumericTypes = new HashSet
+ {
+ typeof(int), typeof(double), typeof(float), typeof(decimal),
+ typeof(long), typeof(short), typeof(byte), typeof(uint),
+ typeof(ulong), typeof(ushort), typeof(sbyte)
+ };
+ }
+}
diff --git a/src/Modules/Shared/Dispo.Shared.Filter/Services/IFilterService.cs b/src/Modules/Shared/Dispo.Shared.Filter/Services/IFilterService.cs
new file mode 100644
index 0000000..16ff635
--- /dev/null
+++ b/src/Modules/Shared/Dispo.Shared.Filter/Services/IFilterService.cs
@@ -0,0 +1,10 @@
+using Dispo.Shared.Core.Domain.Entities;
+using Dispo.Shared.Filter.Model;
+
+namespace Dispo.Shared.Filter.Services
+{
+ public interface IFilterService
+ {
+ object Get(FilterModel filterModel) where T : EntityBase;
+ }
+}