From 70d006f430d19cc715217f2473b9a75420f6a04e Mon Sep 17 00:00:00 2001 From: BilaalDev <80774166+BilaalDev@users.noreply.github.com> Date: Mon, 20 May 2024 12:41:44 +0200 Subject: [PATCH 1/4] Add filter. --- Photo.db | Bin 65536 -> 0 bytes Photo.db-shm | Bin 32768 -> 0 bytes Photo.db-wal | 0 .../Services/PhotoService.cs | 2 +- .../Filters/NameContainsParameter.cs | 27 ++++++++++ .../Filters/NameEndsWithParameter.cs | 28 +++++++++++ .../Filters/NameEqualsParameter.cs | 28 +++++++++++ .../Filters/NameRegexParameter.cs | 28 +++++++++++ .../Filters/NameStartsWithParameter.cs | 27 ++++++++++ .../Query/GetPhotosQueryHandler.cs | 21 ++++---- .../Query/LastNameBeginsWithParameter.cs | 42 ++++++++-------- .../Query/LastNameContainsParameter.cs | 42 ++++++++-------- .../Query/LastNameEndsWithParameter.cs | 42 ++++++++-------- .../Filters/ContainsFilter.cs | 25 ++++++++++ .../Filters/EndsWithFilter.cs | 25 ++++++++++ .../Filters/EqualsFilter.cs | 23 +++++++++ .../Filters/RegexFilter.cs | 29 +++++++++++ .../Filters/StartsWithFilter.cs | 25 ++++++++++ .../Interfaces/IFilter.cs | 8 +++ .../Repositories/IPhotoFilterBuilder.cs | 9 +--- .../Builder/PhotoFilterBuilder.cs | 46 ++++++------------ 21 files changed, 365 insertions(+), 112 deletions(-) delete mode 100644 Photo.db delete mode 100644 Photo.db-shm delete mode 100644 Photo.db-wal create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameContainsParameter.cs create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameEndsWithParameter.cs create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameEqualsParameter.cs create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameRegexParameter.cs create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameStartsWithParameter.cs create mode 100644 src/Spg.AloMalo.DomainModel/Filters/ContainsFilter.cs create mode 100644 src/Spg.AloMalo.DomainModel/Filters/EndsWithFilter.cs create mode 100644 src/Spg.AloMalo.DomainModel/Filters/EqualsFilter.cs create mode 100644 src/Spg.AloMalo.DomainModel/Filters/RegexFilter.cs create mode 100644 src/Spg.AloMalo.DomainModel/Filters/StartsWithFilter.cs create mode 100644 src/Spg.AloMalo.DomainModel/Interfaces/IFilter.cs diff --git a/Photo.db b/Photo.db deleted file mode 100644 index 499428c0ef9cde5f566e270b1d13f1650bc8fcf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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 W{2IF86ct$X>z~Q?R@1TP|NjMB%!s)F diff --git a/Photo.db-shm b/Photo.db-shm deleted file mode 100644 index fe9ac2845eca6fe6da8a63cd096d9cf9e24ece10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeIuAr62r3 GetPhotos() { IQueryable result = _readOnlyPhotoRepository .FilterBuilder - .ApplyNameContainsFilter("My") + //.ApplyNameContainsFilter("My") .Build() .Select(p => new PhotoDto( diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameContainsParameter.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameContainsParameter.cs new file mode 100644 index 0000000..b4151d0 --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameContainsParameter.cs @@ -0,0 +1,27 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Filters; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Filters +{ + public class NameContainsParameter : IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public NameContainsParameter(IPhotoFilterBuilder photoFilterBuilder) + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string queryParameter) + { + string[] parts = queryParameter.Split(' '); + if (parts.Length == 3 && parts[0]?.Trim().ToLower() == "name" && parts[1]?.Trim().ToLower() == "contains") + { + return _photoFilterBuilder.ApplyFilter(new ContainsFilter(p => p.Name, parts[2])); + } + return _photoFilterBuilder; + } + } +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameEndsWithParameter.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameEndsWithParameter.cs new file mode 100644 index 0000000..6e05d15 --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameEndsWithParameter.cs @@ -0,0 +1,28 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Filters; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Filters +{ + public class NameEndsWithParameter : IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public NameEndsWithParameter(IPhotoFilterBuilder photoFilterBuilder) + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string queryParameter) + { + string[] parts = queryParameter.Split(' '); + if (parts.Length == 3 && parts[0]?.Trim().ToLower() == "name" && parts[1]?.Trim().ToLower() == "endswith") + { + return _photoFilterBuilder.ApplyFilter(new EndsWithFilter(p => p.Name, parts[2])); + } + return _photoFilterBuilder; + } + } + +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameEqualsParameter.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameEqualsParameter.cs new file mode 100644 index 0000000..6c081e4 --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameEqualsParameter.cs @@ -0,0 +1,28 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Filters; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Filters +{ + public class NameEqualsParameter : IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public NameEqualsParameter(IPhotoFilterBuilder photoFilterBuilder) + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string queryParameter) + { + string[] parts = queryParameter.Split(' '); + if (parts.Length == 3 && parts[0]?.Trim().ToLower() == "name" && parts[1]?.Trim().ToLower() == "equals") + { + return _photoFilterBuilder.ApplyFilter(new EqualsFilter(p => p.Name, parts[2])); + } + return _photoFilterBuilder; + } + } + +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameRegexParameter.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameRegexParameter.cs new file mode 100644 index 0000000..880b6de --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameRegexParameter.cs @@ -0,0 +1,28 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Filters; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Filters +{ + public class NameRegexParameter : IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public NameRegexParameter(IPhotoFilterBuilder photoFilterBuilder) + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string queryParameter) + { + string[] parts = queryParameter.Split(' '); + if (parts.Length == 3 && parts[0]?.Trim().ToLower() == "name" && parts[1]?.Trim().ToLower() == "regex") + { + return _photoFilterBuilder.ApplyFilter(new RegexFilter(p => p.Name, parts[2])); + } + return _photoFilterBuilder; + } + } + +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameStartsWithParameter.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameStartsWithParameter.cs new file mode 100644 index 0000000..b190268 --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/NameStartsWithParameter.cs @@ -0,0 +1,27 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Filters; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Filters +{ + public class NameStartsWithParameter : IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public NameStartsWithParameter(IPhotoFilterBuilder photoFilterBuilder) + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string queryParameter) + { + string[] parts = queryParameter.Split(' '); + if (parts.Length == 3 && parts[0]?.Trim().ToLower() == "name" && parts[1]?.Trim().ToLower() == "startswith") + { + return _photoFilterBuilder.ApplyFilter(new StartsWithFilter(p => p.Name, parts[2])); + } + return _photoFilterBuilder; + } + } +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs index 84fed9d..1f0d795 100644 --- a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs @@ -1,4 +1,5 @@ using MediatR; +using Spg.AloMalo.Application.Services.PhotoUseCases.Filters; using Spg.AloMalo.DomainModel.Dtos; using Spg.AloMalo.DomainModel.Interfaces.Repositories; @@ -15,17 +16,17 @@ public GetPhotosQueryHandler(IReadOnlyPhotoRepository photoRepository) public Task> Handle(GetPhotosQueryModel request, CancellationToken cancellationToken) { - IPhotoFilterBuilder builder = - _photoRepository - .FilterBuilder; + IPhotoFilterBuilder builder = _photoRepository.FilterBuilder; - builder = new LastNameContainsParameter(builder) - .Compile(request.Query.Filter); - builder = new LastNameBeginsWithParameter(builder) - .Compile(request.Query.Filter); - builder = new LastNameEndsWithParameter(builder) - .Compile(request.Query.Filter); - // builder = new ... + var filters = request.Query.Filter.Split(';'); + foreach (var filter in filters) + { + builder = new NameContainsParameter(builder).Compile(filter); + builder = new NameEqualsParameter(builder).Compile(filter); + builder = new NameStartsWithParameter(builder).Compile(filter); + builder = new NameEndsWithParameter(builder).Compile(filter); + builder = new NameRegexParameter(builder).Compile(filter); + } return Task.FromResult( builder diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameBeginsWithParameter.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameBeginsWithParameter.cs index 9c256f4..d538abf 100644 --- a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameBeginsWithParameter.cs +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameBeginsWithParameter.cs @@ -2,27 +2,27 @@ namespace Spg.AloMalo.Application.Services.PhotoUseCases.Query { - public class LastNameBeginsWithParameter : IQueryParameter - { - private readonly IPhotoFilterBuilder _photoFilterBuilder; + //public class LastNameBeginsWithParameter : IQueryParameter + //{ + // private readonly IPhotoFilterBuilder _photoFilterBuilder; - public LastNameBeginsWithParameter(IPhotoFilterBuilder photoFilterBuilder) - { - _photoFilterBuilder = photoFilterBuilder; - } + // public LastNameBeginsWithParameter(IPhotoFilterBuilder photoFilterBuilder) + // { + // _photoFilterBuilder = photoFilterBuilder; + // } - public IPhotoFilterBuilder Compile(string queryParameter) - { - string[] parts = queryParameter.Split(' '); - //TODO: Checks... - if (parts[0]?.Trim().ToLower() == "name") - { - if (parts[1]?.Trim().ToLower() == "bw") - { - return _photoFilterBuilder.ApplyNameBeginsWithFilter(parts[2]); - } - } - return _photoFilterBuilder; - } - } + // public IPhotoFilterBuilder Compile(string queryParameter) + // { + // string[] parts = queryParameter.Split(' '); + // //TODO: Checks... + // if (parts[0]?.Trim().ToLower() == "name") + // { + // if (parts[1]?.Trim().ToLower() == "bw") + // { + // return _photoFilterBuilder.ApplyNameBeginsWithFilter(parts[2]); + // } + // } + // return _photoFilterBuilder; + // } + //} } diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameContainsParameter.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameContainsParameter.cs index f4dad0c..0a6d971 100644 --- a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameContainsParameter.cs +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameContainsParameter.cs @@ -2,27 +2,27 @@ namespace Spg.AloMalo.Application.Services.PhotoUseCases.Query { - public class LastNameContainsParameter : IQueryParameter - { - private readonly IPhotoFilterBuilder _photoFilterBuilder; + //public class LastNameContainsParameter : IQueryParameter + //{ + // private readonly IPhotoFilterBuilder _photoFilterBuilder; - public LastNameContainsParameter(IPhotoFilterBuilder photoFilterBuilder) - { - _photoFilterBuilder = photoFilterBuilder; - } + // public LastNameContainsParameter(IPhotoFilterBuilder photoFilterBuilder) + // { + // _photoFilterBuilder = photoFilterBuilder; + // } - public IPhotoFilterBuilder Compile(string queryParameter) - { - string[] parts = queryParameter.Split(' '); - //TODO: Checks... - if (parts[0]?.Trim().ToLower() == "name") - { - if (parts[1]?.Trim().ToLower() == "ct") - { - return _photoFilterBuilder.ApplyNameContainsFilter(parts[2]); - } - } - return _photoFilterBuilder; - } - } + // public IPhotoFilterBuilder Compile(string queryParameter) + // { + // string[] parts = queryParameter.Split(' '); + // //TODO: Checks... + // if (parts[0]?.Trim().ToLower() == "name") + // { + // if (parts[1]?.Trim().ToLower() == "ct") + // { + // return _photoFilterBuilder.ApplyNameContainsFilter(parts[2]); + // } + // } + // return _photoFilterBuilder; + // } + //} } diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameEndsWithParameter.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameEndsWithParameter.cs index 896a0fa..9af5522 100644 --- a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameEndsWithParameter.cs +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/LastNameEndsWithParameter.cs @@ -2,27 +2,27 @@ namespace Spg.AloMalo.Application.Services.PhotoUseCases.Query { - public class LastNameEndsWithParameter : IQueryParameter - { - private readonly IPhotoFilterBuilder _photoFilterBuilder; + //public class LastNameEndsWithParameter : IQueryParameter + //{ + // private readonly IPhotoFilterBuilder _photoFilterBuilder; - public LastNameEndsWithParameter(IPhotoFilterBuilder photoFilterBuilder) - { - _photoFilterBuilder = photoFilterBuilder; - } + // public LastNameEndsWithParameter(IPhotoFilterBuilder photoFilterBuilder) + // { + // _photoFilterBuilder = photoFilterBuilder; + // } - public IPhotoFilterBuilder Compile(string queryParameter) - { - string[] parts = queryParameter.Split(' '); - //TODO: Checks... - if (parts[0]?.Trim().ToLower() == "name") - { - if (parts[1]?.Trim().ToLower() == "ew") - { - return _photoFilterBuilder.ApplyNameEndsWithFilter(parts[2]); - } - } - return _photoFilterBuilder; - } - } + // public IPhotoFilterBuilder Compile(string queryParameter) + // { + // string[] parts = queryParameter.Split(' '); + // //TODO: Checks... + // if (parts[0]?.Trim().ToLower() == "name") + // { + // if (parts[1]?.Trim().ToLower() == "ew") + // { + // return _photoFilterBuilder.ApplyNameEndsWithFilter(parts[2]); + // } + // } + // return _photoFilterBuilder; + // } + //} } diff --git a/src/Spg.AloMalo.DomainModel/Filters/ContainsFilter.cs b/src/Spg.AloMalo.DomainModel/Filters/ContainsFilter.cs new file mode 100644 index 0000000..9140d5a --- /dev/null +++ b/src/Spg.AloMalo.DomainModel/Filters/ContainsFilter.cs @@ -0,0 +1,25 @@ +using Spg.AloMalo.DomainModel.Interfaces; +using System.Linq.Expressions; + +namespace Spg.AloMalo.DomainModel.Filters +{ + public class ContainsFilter : IFilter + { + private readonly Expression> _propertyExpression; + private readonly string _value; + + public ContainsFilter(Expression> propertyExpression, string value) + { + _propertyExpression = propertyExpression; + _value = value; + } + + public IQueryable Apply(IQueryable query) + { + return query.Where(Expression.Lambda>( + Expression.Call(_propertyExpression.Body, nameof(string.Contains), Type.EmptyTypes, Expression.Constant(_value)), + _propertyExpression.Parameters)); + } + } + +} diff --git a/src/Spg.AloMalo.DomainModel/Filters/EndsWithFilter.cs b/src/Spg.AloMalo.DomainModel/Filters/EndsWithFilter.cs new file mode 100644 index 0000000..4d1f066 --- /dev/null +++ b/src/Spg.AloMalo.DomainModel/Filters/EndsWithFilter.cs @@ -0,0 +1,25 @@ +using Spg.AloMalo.DomainModel.Interfaces; +using System.Linq.Expressions; + +namespace Spg.AloMalo.DomainModel.Filters +{ + public class EndsWithFilter : IFilter + { + private readonly Expression> _propertyExpression; + private readonly string _value; + + public EndsWithFilter(Expression> propertyExpression, string value) + { + _propertyExpression = propertyExpression; + _value = value; + } + + public IQueryable Apply(IQueryable query) + { + return query.Where(Expression.Lambda>( + Expression.Call(_propertyExpression.Body, nameof(string.EndsWith), Type.EmptyTypes, Expression.Constant(_value)), + _propertyExpression.Parameters)); + } + } + +} diff --git a/src/Spg.AloMalo.DomainModel/Filters/EqualsFilter.cs b/src/Spg.AloMalo.DomainModel/Filters/EqualsFilter.cs new file mode 100644 index 0000000..ce702ab --- /dev/null +++ b/src/Spg.AloMalo.DomainModel/Filters/EqualsFilter.cs @@ -0,0 +1,23 @@ +using Spg.AloMalo.DomainModel.Interfaces; +using System.Linq.Expressions; + +namespace Spg.AloMalo.DomainModel.Filters +{ + public class EqualsFilter : IFilter + { + private readonly Expression> _propertyExpression; + private readonly TProperty _value; + + public EqualsFilter(Expression> propertyExpression, TProperty value) + { + _propertyExpression = propertyExpression; + _value = value; + } + + public IQueryable Apply(IQueryable query) + { + return query.Where(Expression.Lambda>( + Expression.Equal(_propertyExpression.Body, Expression.Constant(_value)), _propertyExpression.Parameters)); + } + } +} diff --git a/src/Spg.AloMalo.DomainModel/Filters/RegexFilter.cs b/src/Spg.AloMalo.DomainModel/Filters/RegexFilter.cs new file mode 100644 index 0000000..fcbb72a --- /dev/null +++ b/src/Spg.AloMalo.DomainModel/Filters/RegexFilter.cs @@ -0,0 +1,29 @@ +using Spg.AloMalo.DomainModel.Interfaces; +using System.Linq.Expressions; +using System.Text.RegularExpressions; + +namespace Spg.AloMalo.DomainModel.Filters +{ + public class RegexFilter : IFilter + { + private readonly Expression> _propertyExpression; + private readonly string _pattern; + + public RegexFilter(Expression> propertyExpression, string pattern) + { + _propertyExpression = propertyExpression; + _pattern = pattern; + } + + public IQueryable Apply(IQueryable query) + { + var parameter = _propertyExpression.Parameters.Single(); + var body = Expression.Call( + typeof(Regex).GetMethod(nameof(Regex.IsMatch), new[] { typeof(string), typeof(string) }), + _propertyExpression.Body, + Expression.Constant(_pattern)); + var predicate = Expression.Lambda>(body, parameter); + return query.Where(predicate); + } + } +} diff --git a/src/Spg.AloMalo.DomainModel/Filters/StartsWithFilter.cs b/src/Spg.AloMalo.DomainModel/Filters/StartsWithFilter.cs new file mode 100644 index 0000000..89857b0 --- /dev/null +++ b/src/Spg.AloMalo.DomainModel/Filters/StartsWithFilter.cs @@ -0,0 +1,25 @@ +using Spg.AloMalo.DomainModel.Interfaces; +using System.Linq.Expressions; + +namespace Spg.AloMalo.DomainModel.Filters +{ + public class StartsWithFilter : IFilter + { + private readonly Expression> _propertyExpression; + private readonly string _value; + + public StartsWithFilter(Expression> propertyExpression, string value) + { + _propertyExpression = propertyExpression; + _value = value; + } + + public IQueryable Apply(IQueryable query) + { + return query.Where(Expression.Lambda>( + Expression.Call(_propertyExpression.Body, nameof(string.StartsWith), Type.EmptyTypes, Expression.Constant(_value)), + _propertyExpression.Parameters)); + } + } + +} diff --git a/src/Spg.AloMalo.DomainModel/Interfaces/IFilter.cs b/src/Spg.AloMalo.DomainModel/Interfaces/IFilter.cs new file mode 100644 index 0000000..59c4ae5 --- /dev/null +++ b/src/Spg.AloMalo.DomainModel/Interfaces/IFilter.cs @@ -0,0 +1,8 @@ +namespace Spg.AloMalo.DomainModel.Interfaces +{ + public interface IFilter + { + IQueryable Apply(IQueryable query); + } + +} diff --git a/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs b/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs index 34e6727..43c0478 100644 --- a/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs +++ b/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs @@ -4,12 +4,7 @@ namespace Spg.AloMalo.DomainModel.Interfaces.Repositories { public interface IPhotoFilterBuilder : IEntityFilterBuilder { - IPhotoFilterBuilder ApplyIdFilter(PhotoId id); - IPhotoFilterBuilder ApplyNameContainsFilter(string filter); - IPhotoFilterBuilder ApplyNameBeginsWithFilter(string filter); - IPhotoFilterBuilder ApplyNameEndsWithFilter(string filter); - IPhotoFilterBuilder ApplyOrientationFilter(Orientations orientation); - IPhotoFilterBuilder ApplyAiFilter(bool @is); - //IPhotoFilterBuilder ApplyPaging(int page, int size); + IPhotoFilterBuilder ApplyFilter(IFilter filter); + IQueryable Build(); } } diff --git a/src/Spg.AloMalo.Repository/Builder/PhotoFilterBuilder.cs b/src/Spg.AloMalo.Repository/Builder/PhotoFilterBuilder.cs index 617dc37..7400455 100644 --- a/src/Spg.AloMalo.Repository/Builder/PhotoFilterBuilder.cs +++ b/src/Spg.AloMalo.Repository/Builder/PhotoFilterBuilder.cs @@ -1,10 +1,13 @@ -using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Interfaces; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; using Spg.AloMalo.DomainModel.Model; namespace Spg.AloMalo.Repository.Builder { public class PhotoFilterBuilder : IPhotoFilterBuilder { + private readonly List> _filters = new(); + public IQueryable EntityList { get; set; } public PhotoFilterBuilder(IQueryable photos) @@ -12,40 +15,21 @@ public PhotoFilterBuilder(IQueryable photos) EntityList = photos; } - public IQueryable Build() - { - return EntityList; - } - - public IPhotoFilterBuilder ApplyIdFilter(PhotoId id) - { - EntityList = EntityList.Where(x => x.Id == id); - return this; - } - public IPhotoFilterBuilder ApplyNameContainsFilter(string name) - { - EntityList = EntityList.Where(x => x.Name.Contains(name)); - return this; - } - public IPhotoFilterBuilder ApplyNameBeginsWithFilter(string name) + public IPhotoFilterBuilder ApplyFilter(IFilter filter) { - EntityList = EntityList.Where(x => x.Name.StartsWith(name)); + _filters.Add(filter); return this; } - public IPhotoFilterBuilder ApplyNameEndsWithFilter(string name) - { - EntityList = EntityList.Where(x => x.Name.EndsWith(name)); - return this; - } - public IPhotoFilterBuilder ApplyOrientationFilter(Orientations orientation) - { - EntityList = EntityList.Where(x => x.Orientation == orientation); - return this; - } - public IPhotoFilterBuilder ApplyAiFilter(bool @is) + + public IQueryable Build() { - EntityList = EntityList.Where(x => x.AiGenerated == @is); - return this; + var query = EntityList; + foreach (var filter in _filters) + { + query = filter.Apply(query); + } + return query; } } + } From ead7e21a30c3118e4f86164cb4558050c402e01c Mon Sep 17 00:00:00 2001 From: BilaalDev <80774166+BilaalDev@users.noreply.github.com> Date: Mon, 20 May 2024 13:13:57 +0200 Subject: [PATCH 2/4] Add Filter with multiple properties. --- .../Filters/PropertyFilterParameter.cs | 103 ++++++++++++++++++ .../Query/GetPhotosQueryHandler.cs | 41 ++++++- .../Repositories/IPhotoFilterBuilder.cs | 1 + 3 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/PropertyFilterParameter.cs diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/PropertyFilterParameter.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/PropertyFilterParameter.cs new file mode 100644 index 0000000..3baefcd --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Filters/PropertyFilterParameter.cs @@ -0,0 +1,103 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Filters; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; +using System.Linq.Expressions; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Filters +{ + public class PropertyFilterParameter : IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + private readonly Expression> _propertyExpression; + private readonly string _operation; + private readonly string _value; + + public PropertyFilterParameter(IPhotoFilterBuilder photoFilterBuilder, Expression> propertyExpression, string operation, string value) + { + _photoFilterBuilder = photoFilterBuilder; + _propertyExpression = propertyExpression; + _operation = operation; + _value = value; + } + + public IPhotoFilterBuilder Compile(string queryParameter) + { + var parts = queryParameter.Split(' '); + if (parts.Length != 3) + throw new ArgumentException("Invalid query parameter format. Expected format: 'property operation value'"); + + var property = parts[0]; + var operation = parts[1]; + var value = parts[2]; + + switch (operation.ToLower()) + { + case "equals": + ApplyEqualsFilter(value); + break; + case "contains": + ApplyContainsFilter(value); + break; + case "startswith": + ApplyStartsWithFilter(value); + break; + case "endswith": + ApplyEndsWithFilter(value); + break; + case "regex": + ApplyRegexFilter(value); + break; + default: + throw new InvalidOperationException("Unknown operation"); + } + return _photoFilterBuilder; + } + + private void ApplyEqualsFilter(string value) + { + var propertyType = _propertyExpression.Body.Type; + var convertedValue = Convert.ChangeType(value, propertyType); + var filterType = typeof(EqualsFilter<,>).MakeGenericType(typeof(Photo), propertyType); + var filter = (EqualsFilter)Activator.CreateInstance(filterType, _propertyExpression, convertedValue); + _photoFilterBuilder.ApplyFilter(filter); + } + + private void ApplyContainsFilter(string value) + { + if (_propertyExpression.Body.Type != typeof(string)) + throw new InvalidOperationException("Contains operation is only supported for string properties"); + + var filter = new ContainsFilter(_propertyExpression as Expression>, value); + _photoFilterBuilder.ApplyFilter(filter); + } + + private void ApplyStartsWithFilter(string value) + { + if (_propertyExpression.Body.Type != typeof(string)) + throw new InvalidOperationException("StartsWith operation is only supported for string properties"); + + var filter = new StartsWithFilter(_propertyExpression as Expression>, value); + _photoFilterBuilder.ApplyFilter(filter); + } + + private void ApplyEndsWithFilter(string value) + { + if (_propertyExpression.Body.Type != typeof(string)) + throw new InvalidOperationException("EndsWith operation is only supported for string properties"); + + var filter = new EndsWithFilter(_propertyExpression as Expression>, value); + _photoFilterBuilder.ApplyFilter(filter); + } + + private void ApplyRegexFilter(string value) + { + if (_propertyExpression.Body.Type != typeof(string)) + throw new InvalidOperationException("Regex operation is only supported for string properties"); + + var filter = new RegexFilter(_propertyExpression as Expression>, value); + _photoFilterBuilder.ApplyFilter(filter); + } + + } +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs index 1f0d795..0e3a818 100644 --- a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs @@ -2,6 +2,7 @@ using Spg.AloMalo.Application.Services.PhotoUseCases.Filters; using Spg.AloMalo.DomainModel.Dtos; using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; namespace Spg.AloMalo.Application.Services.PhotoUseCases.Query { @@ -21,11 +22,40 @@ public Task> Handle(GetPhotosQueryModel request, CancellationToke var filters = request.Query.Filter.Split(';'); foreach (var filter in filters) { - builder = new NameContainsParameter(builder).Compile(filter); - builder = new NameEqualsParameter(builder).Compile(filter); - builder = new NameStartsWithParameter(builder).Compile(filter); - builder = new NameEndsWithParameter(builder).Compile(filter); - builder = new NameRegexParameter(builder).Compile(filter); + var parts = filter.Split(' '); + if (parts.Length == 3) + { + var property = parts[0]; + var operation = parts[1]; + var value = parts[2]; + + switch (property.ToLower()) + { + case "name": + builder = new PropertyFilterParameter(builder, p => p.Name, operation, value).Compile(filter); + break; + case "description": + builder = new PropertyFilterParameter(builder, p => p.Description, operation, value).Compile(filter); + break; + case "location": + builder = new PropertyFilterParameter(builder, p => p.Location, operation, value).Compile(filter); + break; + case "width": + builder = new PropertyFilterParameter(builder, p => p.Width, operation, value).Compile(filter); + break; + case "height": + builder = new PropertyFilterParameter(builder, p => p.Height, operation, value).Compile(filter); + break; + case "orientation": + builder = new PropertyFilterParameter(builder, p => p.Orientation, operation, value).Compile(filter); + break; + case "aigenerated": + builder = new PropertyFilterParameter(builder, p => p.AiGenerated, operation, value).Compile(filter); + break; + default: + throw new InvalidOperationException("Unknown property"); + } + } } return Task.FromResult( @@ -36,4 +66,5 @@ public Task> Handle(GetPhotosQueryModel request, CancellationToke ); } } + } diff --git a/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs b/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs index 43c0478..fb69be6 100644 --- a/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs +++ b/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs @@ -4,6 +4,7 @@ namespace Spg.AloMalo.DomainModel.Interfaces.Repositories { public interface IPhotoFilterBuilder : IEntityFilterBuilder { + IQueryable EntityList { get; set; } IPhotoFilterBuilder ApplyFilter(IFilter filter); IQueryable Build(); } From 4512113d9f45d7cfcdfcc43c9bd11085af9b9a38 Mon Sep 17 00:00:00 2001 From: BilaalDev <80774166+BilaalDev@users.noreply.github.com> Date: Wed, 29 May 2024 19:25:11 +0200 Subject: [PATCH 3/4] Update Filter. Add Tests. --- Photo.db | Bin 0 -> 65536 bytes .../Controllers/PhotosCqsController.cs | 11 +- src/Spg.AloMalo.Api/Program.cs | 2 +- .../ExpressionMapper.cs | 69 +++++++++ .../InterpretParameterBase.cs | 54 +++++++ .../Operations/FilterBetweenOperations.cs | 25 +++ .../Operations/FilterContainsOperations.cs | 28 ++++ .../FilterGreaterThanEqualOperations.cs | 25 +++ .../Operations/FilterGreaterThanOperations.cs | 25 +++ .../FilterLowerThanEqualOperations.cs | 25 +++ .../Operations/FilterLowerThanOperations.cs | 25 +++ .../Operations/FilterStartsWithOperations.cs | 28 ++++ .../Query/GetPhotosQueryHandler.cs | 67 +++----- .../Query/GetPhotosQueryModel.cs | 2 +- .../PhotoUseCases/Query/IQueryParameter.cs | 5 - .../PhotoUseCases/Query/IQueryParameter1.cs | 6 - src/Spg.AloMalo.Application/TConverter.cs | 23 +++ .../Repositories/IPhotoFilterBuilder.cs | 9 ++ .../Queries/GetPhotosQuery.cs | 11 +- .../Builder/PhotoFilterBuilder.cs | 58 +++++++ .../PhotoServiceTests.cs | 146 +++++++++++++++++- .../Spg.AloMalo.Application.Test.csproj | 3 + 22 files changed, 572 insertions(+), 75 deletions(-) create mode 100644 Photo.db create mode 100644 src/Spg.AloMalo.Application/ExpressionMapper.cs create mode 100644 src/Spg.AloMalo.Application/InterpretParameterBase.cs create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterBetweenOperations.cs create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterContainsOperations.cs create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterGreaterThanEqualOperations.cs create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterGreaterThanOperations.cs create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterLowerThanEqualOperations.cs create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterLowerThanOperations.cs create mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterStartsWithOperations.cs delete mode 100644 src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/IQueryParameter1.cs create mode 100644 src/Spg.AloMalo.Application/TConverter.cs diff --git a/Photo.db b/Photo.db new file mode 100644 index 0000000000000000000000000000000000000000..040ab1462b1eac5916e0656b75f79321a7933ce6 GIT binary patch literal 65536 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 result = _mediator + .Send(new GetPhotosQueryModel(query)) + .Result + .ToList(); return Ok(result); } diff --git a/src/Spg.AloMalo.Api/Program.cs b/src/Spg.AloMalo.Api/Program.cs index d016591..ae69ee7 100644 --- a/src/Spg.AloMalo.Api/Program.cs +++ b/src/Spg.AloMalo.Api/Program.cs @@ -117,7 +117,7 @@ options.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()); }); builder.Services.AddTransient, CreatePhotoCommandHandler>(); -builder.Services.AddTransient>, GetPhotosQueryHandler>(); +builder.Services.AddTransient>, GetPhotosQueryHandler>(); // // Build App var app = builder.Build(); diff --git a/src/Spg.AloMalo.Application/ExpressionMapper.cs b/src/Spg.AloMalo.Application/ExpressionMapper.cs new file mode 100644 index 0000000..fd3cbb3 --- /dev/null +++ b/src/Spg.AloMalo.Application/ExpressionMapper.cs @@ -0,0 +1,69 @@ +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using System.Reflection; + +namespace Spg.AloMalo.Application +{ + public class ExpressionMapper + where TEntity : class + { + private readonly PropertyInfo _propertyInfo; + private readonly string? _propertyName; + private readonly string? _value1; + private readonly string? _value2; + + public ExpressionMapper(PropertyInfo propertyInfo, string? propertyName = null + , string? value1 = null, string? value2 = null) + { + _propertyInfo = propertyInfo; + _propertyName = propertyName; + _value1 = value1; + _value2 = value2; + } + + + public void Use(Func>? action) + { + if (string.IsNullOrEmpty(_value1)) + { + return; + } + if (action is null) + { + return; + } + + T target1 = TConverter.ChangeType(_value1); + + if ((_propertyInfo?.Name?.Trim()?.ToLower() ?? string.Empty) + == (_propertyName?.Trim()?.ToLower() ?? string.Empty)) + { + action(target1); + } + } + + public void Use(Func>? action) + { + if (string.IsNullOrEmpty(_value1)) + { + return; + } + if (string.IsNullOrEmpty(_value2)) + { + return; + } + if (action is null) + { + return; + } + + T1 target1 = TConverter.ChangeType(_value1); + T2 target2 = TConverter.ChangeType(_value2); + + if ((_propertyInfo?.Name?.Trim()?.ToLower() ?? string.Empty) + == (_propertyName?.Trim()?.ToLower() ?? string.Empty)) + { + action(target1, target2); + } + } + } +} diff --git a/src/Spg.AloMalo.Application/InterpretParameterBase.cs b/src/Spg.AloMalo.Application/InterpretParameterBase.cs new file mode 100644 index 0000000..f8f9f71 --- /dev/null +++ b/src/Spg.AloMalo.Application/InterpretParameterBase.cs @@ -0,0 +1,54 @@ +using System.Linq.Expressions; +using System.Reflection; + +namespace Spg.AloMalo.Application +{ + public abstract class InterpretParameterBase + where TEntity : class + { + private readonly string _operator; + + public InterpretParameterBase(string @operator) + { + _operator = @operator; + } + + public ExpressionMapper ForProperty( + string? queryParameter, + Expression> propertyExpression) + { + MemberExpression? member = propertyExpression.Body as MemberExpression; + if (member == null) + { + throw new ArgumentException($"{propertyExpression} is a Method!"); + } + PropertyInfo? propInfo = member.Member as PropertyInfo; + if (propInfo == null) + { + throw new ArgumentException($"{propertyExpression} is a Field!"); + } + + if (string.IsNullOrEmpty(queryParameter)) + { + return new ExpressionMapper(propInfo); + } + string[] parts = queryParameter.Split(' '); + if (parts.Length < 3 || parts.Length > 4) + { + throw new ArgumentException($"Incorrect Expression ('xxxx ct xxxx' or 'xxxx bw xxxx xxxx')"); + } + if (parts[1].Trim().ToLower() == _operator.Trim().ToLower()) + { + if (parts.Length == 3) + { + return new ExpressionMapper(propInfo, parts[0], parts[2]); + } + if (parts.Length == 4) + { + return new ExpressionMapper(propInfo, parts[0], parts[2], parts[3]); + } + } + return new ExpressionMapper(propInfo); + } + } +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterBetweenOperations.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterBetweenOperations.cs new file mode 100644 index 0000000..9647a56 --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterBetweenOperations.cs @@ -0,0 +1,25 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Filters +{ + public class FilterBetweenOperations : InterpretParameterBase, IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public FilterBetweenOperations(IPhotoFilterBuilder photoFilterBuilder) + : base("bw") + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string? queryParameter) + { + ForProperty(queryParameter, p => p.CreationTimeStamp) + .Use(_photoFilterBuilder.ApplyCreationTimeStampBetweenFilter); + + return _photoFilterBuilder; + } + } +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterContainsOperations.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterContainsOperations.cs new file mode 100644 index 0000000..104bdf8 --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterContainsOperations.cs @@ -0,0 +1,28 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Operations +{ + public class FilterContainsOperations : InterpretParameterBase, IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public FilterContainsOperations(IPhotoFilterBuilder photoFilterBuilder) + : base("ct") + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string? queryParameter) + { + ForProperty(queryParameter, p => p.Name) + .Use(_photoFilterBuilder.ApplyNameContainsFilter); + + ForProperty(queryParameter, p => p.Description) + .Use(_photoFilterBuilder.ApplyDescriptionContainsFilter); + + return _photoFilterBuilder; + } + } +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterGreaterThanEqualOperations.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterGreaterThanEqualOperations.cs new file mode 100644 index 0000000..9cc6773 --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterGreaterThanEqualOperations.cs @@ -0,0 +1,25 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Operations +{ + public class FilterGreaterThanEqualOperations : InterpretParameterBase, IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public FilterGreaterThanEqualOperations(IPhotoFilterBuilder photoFilterBuilder) + : base("gte") + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string? queryParameter) + { + ForProperty(queryParameter, p => p.Width) + .Use(_photoFilterBuilder.ApplyWidthGreaterThanEqualFilter); + + return _photoFilterBuilder; + } + } +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterGreaterThanOperations.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterGreaterThanOperations.cs new file mode 100644 index 0000000..97f6159 --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterGreaterThanOperations.cs @@ -0,0 +1,25 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Operations +{ + public class FilterGreaterThanOperations : InterpretParameterBase, IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public FilterGreaterThanOperations(IPhotoFilterBuilder photoFilterBuilder) + : base("gt") + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string? queryParameter) + { + ForProperty(queryParameter, p => p.Width) + .Use(_photoFilterBuilder.ApplyWidthGreaterThanFilter); + + return _photoFilterBuilder; + } + } +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterLowerThanEqualOperations.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterLowerThanEqualOperations.cs new file mode 100644 index 0000000..b9f18d6 --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterLowerThanEqualOperations.cs @@ -0,0 +1,25 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Operations +{ + public class FilterLowerThanEqualOperations : InterpretParameterBase, IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public FilterLowerThanEqualOperations(IPhotoFilterBuilder photoFilterBuilder) + : base("lte") + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string? queryParameter) + { + ForProperty(queryParameter, p => p.Width) + .Use(_photoFilterBuilder.ApplyWidthLowerThanEqualFilter); + + return _photoFilterBuilder; + } + } +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterLowerThanOperations.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterLowerThanOperations.cs new file mode 100644 index 0000000..6e672d4 --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterLowerThanOperations.cs @@ -0,0 +1,25 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Operations +{ + public class FilterLowerThanOperations : InterpretParameterBase, IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public FilterLowerThanOperations(IPhotoFilterBuilder photoFilterBuilder) + : base("lt") + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string? queryParameter) + { + ForProperty(queryParameter, p => p.Width) + .Use(_photoFilterBuilder.ApplyWidthLowerThanFilter); + + return _photoFilterBuilder; + } + } +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterStartsWithOperations.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterStartsWithOperations.cs new file mode 100644 index 0000000..ad2012a --- /dev/null +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Operations/FilterStartsWithOperations.cs @@ -0,0 +1,28 @@ +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Interfaces.Repositories; +using Spg.AloMalo.DomainModel.Model; + +namespace Spg.AloMalo.Application.Services.PhotoUseCases.Operations +{ + public class FilterStartsWithOperations : InterpretParameterBase, IQueryParameter + { + private readonly IPhotoFilterBuilder _photoFilterBuilder; + + public FilterStartsWithOperations(IPhotoFilterBuilder photoFilterBuilder) + : base("sw") + { + _photoFilterBuilder = photoFilterBuilder; + } + + public IPhotoFilterBuilder Compile(string? queryParameter) + { + ForProperty(queryParameter, p => p.Name) + .Use(_photoFilterBuilder.ApplyNameStartsWithFilter); + + ForProperty(queryParameter, p => p.Description) + .Use(_photoFilterBuilder.ApplyDescriptionStartsWithFilter); + + return _photoFilterBuilder; + } + } +} diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs index 0e3a818..d331a67 100644 --- a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryHandler.cs @@ -1,12 +1,12 @@ using MediatR; using Spg.AloMalo.Application.Services.PhotoUseCases.Filters; +using Spg.AloMalo.Application.Services.PhotoUseCases.Operations; using Spg.AloMalo.DomainModel.Dtos; using Spg.AloMalo.DomainModel.Interfaces.Repositories; -using Spg.AloMalo.DomainModel.Model; namespace Spg.AloMalo.Application.Services.PhotoUseCases.Query { - public class GetPhotosQueryHandler : IRequestHandler> + public class GetPhotosQueryHandler : IRequestHandler> { private readonly IReadOnlyPhotoRepository _photoRepository; @@ -15,55 +15,32 @@ public GetPhotosQueryHandler(IReadOnlyPhotoRepository photoRepository) _photoRepository = photoRepository; } - public Task> Handle(GetPhotosQueryModel request, CancellationToken cancellationToken) + public Task> Handle(GetPhotosQueryModel request, CancellationToken cancellationToken) { - IPhotoFilterBuilder builder = _photoRepository.FilterBuilder; + IPhotoFilterBuilder builder = + _photoRepository + .FilterBuilder; - var filters = request.Query.Filter.Split(';'); - foreach (var filter in filters) + List operations = + [ + new FilterContainsOperations(builder), + new FilterStartsWithOperations(builder), + new FilterGreaterThanOperations(builder), + new FilterGreaterThanEqualOperations(builder), + new FilterLowerThanOperations(builder), + new FilterLowerThanEqualOperations(builder), + new FilterBetweenOperations(builder), + ]; + foreach (IQueryParameter operation in operations) { - var parts = filter.Split(' '); - if (parts.Length == 3) - { - var property = parts[0]; - var operation = parts[1]; - var value = parts[2]; - - switch (property.ToLower()) - { - case "name": - builder = new PropertyFilterParameter(builder, p => p.Name, operation, value).Compile(filter); - break; - case "description": - builder = new PropertyFilterParameter(builder, p => p.Description, operation, value).Compile(filter); - break; - case "location": - builder = new PropertyFilterParameter(builder, p => p.Location, operation, value).Compile(filter); - break; - case "width": - builder = new PropertyFilterParameter(builder, p => p.Width, operation, value).Compile(filter); - break; - case "height": - builder = new PropertyFilterParameter(builder, p => p.Height, operation, value).Compile(filter); - break; - case "orientation": - builder = new PropertyFilterParameter(builder, p => p.Orientation, operation, value).Compile(filter); - break; - case "aigenerated": - builder = new PropertyFilterParameter(builder, p => p.AiGenerated, operation, value).Compile(filter); - break; - default: - throw new InvalidOperationException("Unknown property"); - } - } + builder = operation.Compile(request?.Query?.Filter ?? string.Empty); } - return Task.FromResult( - builder + IQueryable result = builder .Build() - .Select(p => p.ToDto()) - .ToList() - ); + .Select(r => r.ToDto()); + + return Task.FromResult(result); } } diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryModel.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryModel.cs index 66712c9..8ba638f 100644 --- a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryModel.cs +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/GetPhotosQueryModel.cs @@ -4,7 +4,7 @@ namespace Spg.AloMalo.Application.Services.PhotoUseCases.Query { - public class GetPhotosQueryModel : IRequest> + public class GetPhotosQueryModel : IRequest> { public GetPhotosQuery Query { get; } diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/IQueryParameter.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/IQueryParameter.cs index ef1efd1..c69d7a6 100644 --- a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/IQueryParameter.cs +++ b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/IQueryParameter.cs @@ -1,9 +1,4 @@ using Spg.AloMalo.DomainModel.Interfaces.Repositories; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Spg.AloMalo.Application.Services.PhotoUseCases.Query { diff --git a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/IQueryParameter1.cs b/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/IQueryParameter1.cs deleted file mode 100644 index 1dee1a0..0000000 --- a/src/Spg.AloMalo.Application/Services/PhotoUseCases/Query/IQueryParameter1.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Spg.AloMalo.Application.Services.PhotoUseCases.Query -{ - public interface IQueryParameter - { - } -} \ No newline at end of file diff --git a/src/Spg.AloMalo.Application/TConverter.cs b/src/Spg.AloMalo.Application/TConverter.cs new file mode 100644 index 0000000..edd144d --- /dev/null +++ b/src/Spg.AloMalo.Application/TConverter.cs @@ -0,0 +1,23 @@ +using System.ComponentModel; + +namespace Spg.AloMalo.Application +{ + public static class TConverter + { + public static T ChangeType(object value) + { + return (T)ChangeType(typeof(T), value); + } + + public static object ChangeType(Type t, object value) + { + TypeConverter tc = TypeDescriptor.GetConverter(t); + return tc.ConvertFrom(value)!; + } + + public static void RegisterTypeConverter() where TC : TypeConverter + { + TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC))); + } + } +} diff --git a/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs b/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs index fb69be6..dc2803f 100644 --- a/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs +++ b/src/Spg.AloMalo.DomainModel/Interfaces/Repositories/IPhotoFilterBuilder.cs @@ -7,5 +7,14 @@ public interface IPhotoFilterBuilder : IEntityFilterBuilder IQueryable EntityList { get; set; } IPhotoFilterBuilder ApplyFilter(IFilter filter); IQueryable Build(); + IPhotoFilterBuilder ApplyWidthGreaterThanFilter(int start); + IPhotoFilterBuilder ApplyWidthGreaterThanEqualFilter(int start); + IPhotoFilterBuilder ApplyWidthLowerThanFilter(int start); + IPhotoFilterBuilder ApplyWidthLowerThanEqualFilter(int start); + IPhotoFilterBuilder ApplyNameContainsFilter(string namePart); + IPhotoFilterBuilder ApplyDescriptionContainsFilter(string namePart); + IPhotoFilterBuilder ApplyNameStartsWithFilter(string namePart); + IPhotoFilterBuilder ApplyDescriptionStartsWithFilter(string namePart); + IPhotoFilterBuilder ApplyCreationTimeStampBetweenFilter(DateTime start, DateTime end); } } diff --git a/src/Spg.AloMalo.DomainModel/Queries/GetPhotosQuery.cs b/src/Spg.AloMalo.DomainModel/Queries/GetPhotosQuery.cs index db63077..8475e1a 100644 --- a/src/Spg.AloMalo.DomainModel/Queries/GetPhotosQuery.cs +++ b/src/Spg.AloMalo.DomainModel/Queries/GetPhotosQuery.cs @@ -1,12 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Spg.AloMalo.DomainModel.Queries +namespace Spg.AloMalo.DomainModel.Queries { public record GetPhotosQuery( - string Filter, - string Order); + string? Filter = null); } diff --git a/src/Spg.AloMalo.Repository/Builder/PhotoFilterBuilder.cs b/src/Spg.AloMalo.Repository/Builder/PhotoFilterBuilder.cs index 7400455..c08cc73 100644 --- a/src/Spg.AloMalo.Repository/Builder/PhotoFilterBuilder.cs +++ b/src/Spg.AloMalo.Repository/Builder/PhotoFilterBuilder.cs @@ -30,6 +30,64 @@ public IQueryable Build() } return query; } + + public IPhotoFilterBuilder ApplyWidthGreaterThanFilter(int start) + { + EntityList = EntityList.Where(x => x.Width > start); + return this; + } + + public IPhotoFilterBuilder ApplyWidthGreaterThanEqualFilter(int start) + { + EntityList = EntityList.Where(x => x.Width >= start); + return this; + } + + public IPhotoFilterBuilder ApplyWidthLowerThanFilter(int start) + { + EntityList = EntityList.Where(x => x.Width < start); + return this; + } + + public IPhotoFilterBuilder ApplyWidthLowerThanEqualFilter(int start) + { + EntityList = EntityList.Where(x => x.Width <= start); + return this; + } + + public IPhotoFilterBuilder ApplyNameContainsFilter(string namePart) + { + EntityList = EntityList.Where(x => x.Name.Trim().ToLower() + .Contains(namePart.Trim().ToLower())); + return this; + } + + public IPhotoFilterBuilder ApplyDescriptionContainsFilter(string namePart) + { + EntityList = EntityList.Where(x => x.Description.Trim().ToLower() + .Contains(namePart.Trim().ToLower())); + return this; + } + + public IPhotoFilterBuilder ApplyNameStartsWithFilter(string namePart) + { + EntityList = EntityList.Where(x => x.Name.Trim().ToLower() + .StartsWith(namePart.Trim().ToLower())); + return this; + } + + public IPhotoFilterBuilder ApplyDescriptionStartsWithFilter(string namePart) + { + EntityList = EntityList.Where(x => x.Description.Trim().ToLower() + .StartsWith(namePart.Trim().ToLower())); + return this; + } + + public IPhotoFilterBuilder ApplyCreationTimeStampBetweenFilter(DateTime start, DateTime end) + { + EntityList = EntityList.Where(x => x.CreationTimeStamp > start && x.CreationTimeStamp < end); + return this; + } } } diff --git a/test/Spg.AloMalo.Application.Test/PhotoServiceTests.cs b/test/Spg.AloMalo.Application.Test/PhotoServiceTests.cs index d88adfb..1682c62 100644 --- a/test/Spg.AloMalo.Application.Test/PhotoServiceTests.cs +++ b/test/Spg.AloMalo.Application.Test/PhotoServiceTests.cs @@ -1,4 +1,11 @@ -namespace Spg.AloMalo.Application.Test +using Spg.AloMalo.Application.Services.PhotoUseCases.Query; +using Spg.AloMalo.DomainModel.Dtos; +using Spg.AloMalo.DomainModel.Test.Helpers; +using Spg.AloMalo.Infrastructure; +using Spg.AloMalo.Repository.Builder; +using Spg.AloMalo.Repository.Repositories; + +namespace Spg.AloMalo.Application.Test { public class PhotoServiceTests { @@ -7,5 +14,142 @@ public void OK_Test() { Assert.True(true); } + + [Fact] + public void TestIfInsertWorks() + { + using (PhotoContext db = DatabaseUtilities.CreateDb()) + { + db.Photos.AddRange(DatabaseUtilities.GetSeedingPhotos(DatabaseUtilities.GetSeedingPhotographers())); + db.SaveChanges(); + Assert.Equal(8, db.Photos.Count()); + } + } + + [Fact] + public void Should_Get4Photos_When_NameStartsWithB() + { + using (PhotoContext db = DatabaseUtilities.CreateDb()) + { + db.Photos.AddRange(DatabaseUtilities.GetSeedingPhotos(DatabaseUtilities.GetSeedingPhotographers())); + db.SaveChanges(); + GetPhotosQueryModel model = new GetPhotosQueryModel( + new DomainModel.Queries.GetPhotosQuery("name sw b")); + + GetPhotosQueryHandler handler = new GetPhotosQueryHandler( + new PhotoRepository(db, new PhotoFilterBuilder(db.Photos), new PhotoUpdateBuilder(db))); + IQueryable result = handler.Handle(model, CancellationToken.None).Result; + + Assert.Equal(4, result.Count()); + } + } + + [Fact] + public void Should_Get0Photos_When_DateBetween2020And2022() + { + using (PhotoContext db = DatabaseUtilities.CreateDb()) + { + db.Photos.AddRange(DatabaseUtilities.GetSeedingPhotos(DatabaseUtilities.GetSeedingPhotographers())); + db.SaveChanges(); + GetPhotosQueryModel model = new GetPhotosQueryModel( + new DomainModel.Queries.GetPhotosQuery("creationtimestamp bw 2020.01.01 2022.12.31")); + + GetPhotosQueryHandler handler = new GetPhotosQueryHandler( + new PhotoRepository(db, new PhotoFilterBuilder(db.Photos), new PhotoUpdateBuilder(db))); + IQueryable result = handler.Handle(model, CancellationToken.None).Result; + + Assert.Equal(0, result.Count()); + } + } + + [Fact] + public void Should_Get2Photos_When_NameContainsE() + { + using (PhotoContext db = DatabaseUtilities.CreateDb()) + { + db.Photos.AddRange(DatabaseUtilities.GetSeedingPhotos(DatabaseUtilities.GetSeedingPhotographers())); + db.SaveChanges(); + GetPhotosQueryModel model = new GetPhotosQueryModel( + new DomainModel.Queries.GetPhotosQuery("name ct e")); + + GetPhotosQueryHandler handler = new GetPhotosQueryHandler( + new PhotoRepository(db, new PhotoFilterBuilder(db.Photos), new PhotoUpdateBuilder(db))); + IQueryable result = handler.Handle(model, CancellationToken.None).Result; + + Assert.Equal(2, result.Count()); + } + } + + [Fact] + public void Should_Get5Photos_When_WidthGreaterThan200() + { + using (PhotoContext db = DatabaseUtilities.CreateDb()) + { + db.Photos.AddRange(DatabaseUtilities.GetSeedingPhotos(DatabaseUtilities.GetSeedingPhotographers())); + db.SaveChanges(); + GetPhotosQueryModel model = new GetPhotosQueryModel( + new DomainModel.Queries.GetPhotosQuery("width gt 200")); + + GetPhotosQueryHandler handler = new GetPhotosQueryHandler( + new PhotoRepository(db, new PhotoFilterBuilder(db.Photos), new PhotoUpdateBuilder(db))); + IQueryable result = handler.Handle(model, CancellationToken.None).Result; + + Assert.Equal(5, result.Count()); + } + } + + [Fact] + public void Should_Get8Photos_When_WidthGreaterThanEqual200() + { + using (PhotoContext db = DatabaseUtilities.CreateDb()) + { + db.Photos.AddRange(DatabaseUtilities.GetSeedingPhotos(DatabaseUtilities.GetSeedingPhotographers())); + db.SaveChanges(); + GetPhotosQueryModel model = new GetPhotosQueryModel( + new DomainModel.Queries.GetPhotosQuery("width gte 200")); + + GetPhotosQueryHandler handler = new GetPhotosQueryHandler( + new PhotoRepository(db, new PhotoFilterBuilder(db.Photos), new PhotoUpdateBuilder(db))); + IQueryable result = handler.Handle(model, CancellationToken.None).Result; + + Assert.Equal(8, result.Count()); + } + } + + [Fact] + public void Should_Get5Photos_When_WidthLowerThan500() + { + using (PhotoContext db = DatabaseUtilities.CreateDb()) + { + db.Photos.AddRange(DatabaseUtilities.GetSeedingPhotos(DatabaseUtilities.GetSeedingPhotographers())); + db.SaveChanges(); + GetPhotosQueryModel model = new GetPhotosQueryModel( + new DomainModel.Queries.GetPhotosQuery("width lt 500")); + + GetPhotosQueryHandler handler = new GetPhotosQueryHandler( + new PhotoRepository(db, new PhotoFilterBuilder(db.Photos), new PhotoUpdateBuilder(db))); + IQueryable result = handler.Handle(model, CancellationToken.None).Result; + + Assert.Equal(5, result.Count()); + } + } + + [Fact] + public void Should_Get7Photos_When_WidthLowerThanEqual800() + { + using (PhotoContext db = DatabaseUtilities.CreateDb()) + { + db.Photos.AddRange(DatabaseUtilities.GetSeedingPhotos(DatabaseUtilities.GetSeedingPhotographers())); + db.SaveChanges(); + GetPhotosQueryModel model = new GetPhotosQueryModel( + new DomainModel.Queries.GetPhotosQuery("width lte 800")); + + GetPhotosQueryHandler handler = new GetPhotosQueryHandler( + new PhotoRepository(db, new PhotoFilterBuilder(db.Photos), new PhotoUpdateBuilder(db))); + IQueryable result = handler.Handle(model, CancellationToken.None).Result; + + Assert.Equal(7, result.Count()); + } + } } } diff --git a/test/Spg.AloMalo.Application.Test/Spg.AloMalo.Application.Test.csproj b/test/Spg.AloMalo.Application.Test/Spg.AloMalo.Application.Test.csproj index 3018ca0..8343e88 100644 --- a/test/Spg.AloMalo.Application.Test/Spg.AloMalo.Application.Test.csproj +++ b/test/Spg.AloMalo.Application.Test/Spg.AloMalo.Application.Test.csproj @@ -26,6 +26,9 @@ + + + From d6dfdb1052e0bc3d11df7daee03251b3ef2cc409 Mon Sep 17 00:00:00 2001 From: BilaalDev <80774166+BilaalDev@users.noreply.github.com> Date: Wed, 29 May 2024 19:26:53 +0200 Subject: [PATCH 4/4] Delete Database. --- Photo.db | Bin 65536 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Photo.db diff --git a/Photo.db b/Photo.db deleted file mode 100644 index 040ab1462b1eac5916e0656b75f79321a7933ce6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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