diff --git a/OutOfSchool/OutOfSchool.ElasticsearchData/ESWorkshopProvider.cs b/OutOfSchool/OutOfSchool.ElasticsearchData/ESWorkshopProvider.cs index 583f506005..94e5091962 100644 --- a/OutOfSchool/OutOfSchool.ElasticsearchData/ESWorkshopProvider.cs +++ b/OutOfSchool/OutOfSchool.ElasticsearchData/ESWorkshopProvider.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Nest; using OutOfSchool.Common; -using OutOfSchool.Common.Enums; using OutOfSchool.ElasticsearchData.Enums; using OutOfSchool.ElasticsearchData.Models; @@ -134,14 +133,14 @@ private QueryContainer CreateQueryFromFilter(WorkshopFilterES filter) ageQuery = new NumericRangeQuery() { - Field = Infer.Field(w => w.MinAge), - LessThanOrEqualTo = filter.MaxAge, + Field = filter.IsAppropriateAge ? Infer.Field(w => w.MinAge) : Infer.Field(w => w.MaxAge), + GreaterThanOrEqualTo = filter.MinAge, }; ageQuery &= new NumericRangeQuery() { - Field = Infer.Field(w => w.MaxAge), - GreaterThanOrEqualTo = filter.MinAge, + Field = filter.IsAppropriateAge ? Infer.Field(w => w.MaxAge) : Infer.Field(w => w.MinAge), + LessThanOrEqualTo = filter.MaxAge, }; queryContainer &= ageQuery; @@ -173,7 +172,9 @@ private QueryContainer CreateQueryFromFilter(WorkshopFilterES filter) Path = Infer.Field(p => p.DateTimeRanges), Query = new MatchQuery() { - Field = Infer.Field(w => w.DateTimeRanges.First().Workdays), + Field = filter.IsStrictWorkdays + ? Infer.Field(w => w.DateTimeRanges.First().Workdays.Suffix("keyword")) + : Infer.Field(w => w.DateTimeRanges.First().Workdays), Query = filter.Workdays, }, }; diff --git a/OutOfSchool/OutOfSchool.ElasticsearchData/Models/WorkshopFilterES.cs b/OutOfSchool/OutOfSchool.ElasticsearchData/Models/WorkshopFilterES.cs index f5a32c2dfe..301096e13f 100644 --- a/OutOfSchool/OutOfSchool.ElasticsearchData/Models/WorkshopFilterES.cs +++ b/OutOfSchool/OutOfSchool.ElasticsearchData/Models/WorkshopFilterES.cs @@ -44,4 +44,8 @@ public class WorkshopFilterES public decimal Longitude { get; set; } = 0; public IReadOnlyCollection Statuses { get; set; } = new List(); + + public bool IsAppropriateAge { get; set; } = false; + + public bool IsStrictWorkdays { get; set; } = false; } \ No newline at end of file diff --git a/OutOfSchool/OutOfSchool.WebApi/Models/Workshop/WorkshopFilter.cs b/OutOfSchool/OutOfSchool.WebApi/Models/Workshop/WorkshopFilter.cs index ae7214cd99..16bd196c7f 100644 --- a/OutOfSchool/OutOfSchool.WebApi/Models/Workshop/WorkshopFilter.cs +++ b/OutOfSchool/OutOfSchool.WebApi/Models/Workshop/WorkshopFilter.cs @@ -53,4 +53,8 @@ public class WorkshopFilter : OffsetFilter public decimal Longitude { get; set; } = 0; public IReadOnlyCollection Statuses { get; set; } = new List(); + + public bool IsAppropriateAge { get; set; } = false; + + public bool IsStrictWorkdays { get; set; } = false; } \ No newline at end of file diff --git a/OutOfSchool/OutOfSchool.WebApi/Services/Database/WorkshopService.cs b/OutOfSchool/OutOfSchool.WebApi/Services/Database/WorkshopService.cs index 799815362a..001f192376 100644 --- a/OutOfSchool/OutOfSchool.WebApi/Services/Database/WorkshopService.cs +++ b/OutOfSchool/OutOfSchool.WebApi/Services/Database/WorkshopService.cs @@ -563,7 +563,9 @@ private Expression> PredicateBuild(WorkshopFilter filter) if (filter.MinAge != 0 || filter.MaxAge != 100) { - predicate = predicate.And(x => x.MinAge <= filter.MaxAge && x.MaxAge >= filter.MinAge); + predicate = filter.IsAppropriateAge + ? predicate.And(x => x.MinAge >= filter.MinAge && x.MaxAge <= filter.MaxAge) + : predicate.And(x => x.MinAge <= filter.MaxAge && x.MaxAge >= filter.MinAge); } if (filter.WithDisabilityOptions) @@ -577,7 +579,9 @@ private Expression> PredicateBuild(WorkshopFilter filter) if (workdaysBitMask > 0) { - predicate = predicate.And(x => x.DateTimeRanges.Any(tr => (tr.Workdays & workdaysBitMask) > 0)); + predicate = filter.IsStrictWorkdays + ? predicate.And(x => x.DateTimeRanges.Any(tr => (tr.Workdays == workdaysBitMask))) + : predicate.And(x => x.DateTimeRanges.Any(tr => (tr.Workdays & workdaysBitMask) > 0)); } } diff --git a/OutOfSchool/OutOfSchool.WebApi/Services/Strategies/Interfaces/IWorkshopStrategy.cs b/OutOfSchool/OutOfSchool.WebApi/Services/Strategies/Interfaces/IWorkshopStrategy.cs new file mode 100644 index 0000000000..bc4dcc6cbc --- /dev/null +++ b/OutOfSchool/OutOfSchool.WebApi/Services/Strategies/Interfaces/IWorkshopStrategy.cs @@ -0,0 +1,8 @@ +using OutOfSchool.WebApi.Models; + +namespace OutOfSchool.WebApi.Services.Strategies.Interfaces; + +public interface IWorkshopStrategy +{ + Task> SearchAsync(WorkshopFilter filter); +} diff --git a/OutOfSchool/OutOfSchool.WebApi/Services/Strategies/WorkshopStrategies/WorkshopESStrategy.cs b/OutOfSchool/OutOfSchool.WebApi/Services/Strategies/WorkshopStrategies/WorkshopESStrategy.cs new file mode 100644 index 0000000000..6dfe984c86 --- /dev/null +++ b/OutOfSchool/OutOfSchool.WebApi/Services/Strategies/WorkshopStrategies/WorkshopESStrategy.cs @@ -0,0 +1,28 @@ +using OutOfSchool.WebApi.Models; +using OutOfSchool.WebApi.Services.Strategies.Interfaces; + +namespace OutOfSchool.WebApi.Services.Strategies.WorkshopStrategies; + +public class WorkshopESStrategy : IWorkshopStrategy +{ + private readonly IElasticsearchService elasticsearchService; + private readonly ILogger logger; + + public WorkshopESStrategy(IElasticsearchService elasticsearchService, ILogger logger) + { + this.elasticsearchService = elasticsearchService ?? throw new ArgumentNullException(); + this.logger = logger; + } + + public async Task> SearchAsync(WorkshopFilter filter) + { + var result = await elasticsearchService.Search(filter.ToESModel()).ConfigureAwait(false); + + if (result.TotalAmount <= 0) + { + logger?.LogInformation($"Result was {result.TotalAmount}"); + } + + return result.ToSearchResult(); + } +} diff --git a/OutOfSchool/OutOfSchool.WebApi/Services/Strategies/WorkshopStrategies/WorkshopServiceStrategy.cs b/OutOfSchool/OutOfSchool.WebApi/Services/Strategies/WorkshopStrategies/WorkshopServiceStrategy.cs new file mode 100644 index 0000000000..272aa04aa5 --- /dev/null +++ b/OutOfSchool/OutOfSchool.WebApi/Services/Strategies/WorkshopStrategies/WorkshopServiceStrategy.cs @@ -0,0 +1,28 @@ +using OutOfSchool.WebApi.Models; +using OutOfSchool.WebApi.Services.Strategies.Interfaces; + +namespace OutOfSchool.WebApi.Services.Strategies.WorkshopStrategies; + +public class WorkshopServiceStrategy : IWorkshopStrategy +{ + private readonly IWorkshopService workshopService; + private readonly ILogger logger; + + public WorkshopServiceStrategy(IWorkshopService workshopService, ILogger logger) + { + this.workshopService = workshopService ?? throw new ArgumentNullException(); + this.logger = logger; + } + + public async Task> SearchAsync(WorkshopFilter filter) + { + var databaseResult = await workshopService.GetByFilter(filter).ConfigureAwait(false); + + if (databaseResult.TotalAmount <= 0) + { + logger?.LogInformation($"Result was {databaseResult.TotalAmount}"); + } + + return new SearchResult() { TotalAmount = databaseResult.TotalAmount, Entities = databaseResult.Entities }; + } +} \ No newline at end of file diff --git a/OutOfSchool/OutOfSchool.WebApi/Services/WorkshopServicesCombiner.cs b/OutOfSchool/OutOfSchool.WebApi/Services/WorkshopServicesCombiner.cs index d9dcc42161..7fbf94f753 100644 --- a/OutOfSchool/OutOfSchool.WebApi/Services/WorkshopServicesCombiner.cs +++ b/OutOfSchool/OutOfSchool.WebApi/Services/WorkshopServicesCombiner.cs @@ -3,35 +3,33 @@ using OutOfSchool.WebApi.Enums; using OutOfSchool.WebApi.Models; using OutOfSchool.WebApi.Models.Workshop; +using OutOfSchool.WebApi.Services.Strategies.Interfaces; namespace OutOfSchool.WebApi.Services; public class WorkshopServicesCombiner : IWorkshopServicesCombiner, INotificationReciever { private protected readonly IWorkshopService workshopService; // make it private after removing v2 version - private readonly IElasticsearchService elasticsearchService; - private readonly ILogger logger; private protected readonly IElasticsearchSynchronizationService elasticsearchSynchronizationService; // make it private after removing v2 version private readonly INotificationService notificationService; private readonly IEntityRepository favoriteRepository; private readonly IApplicationRepository applicationRepository; + private readonly IWorkshopStrategy workshopStrategy; public WorkshopServicesCombiner( IWorkshopService workshopService, - IElasticsearchService elasticsearchService, - ILogger logger, IElasticsearchSynchronizationService elasticsearchSynchronizationService, INotificationService notificationService, IEntityRepository favoriteRepository, - IApplicationRepository applicationRepository) + IApplicationRepository applicationRepository, + IWorkshopStrategy workshopStrategy) { this.workshopService = workshopService; - this.elasticsearchService = elasticsearchService; - this.logger = logger; this.elasticsearchSynchronizationService = elasticsearchSynchronizationService; this.notificationService = notificationService; this.favoriteRepository = favoriteRepository; this.applicationRepository = applicationRepository; + this.workshopStrategy = workshopStrategy; } /// @@ -136,22 +134,7 @@ public async Task> GetAll(OffsetFilter offsetFilter) OrderByField = OrderBy.Id.ToString(), }; - if (elasticsearchService.IsElasticAlive) - { - var result = await elasticsearchService.Search(filter.ToESModel()).ConfigureAwait(false); - if (result.TotalAmount <= 0) - { - logger.LogInformation($"Result was {result.TotalAmount}"); - } - - return result.ToSearchResult(); - } - else - { - var databaseResult = await workshopService.GetByFilter(filter).ConfigureAwait(false); - - return new SearchResult() { TotalAmount = databaseResult.TotalAmount, Entities = databaseResult.Entities }; - } + return await workshopStrategy.SearchAsync(filter); } /// @@ -162,22 +145,7 @@ public async Task> GetByFilter(WorkshopFilter filter) return new SearchResult { TotalAmount = 0, Entities = new List() }; } - if (elasticsearchService.IsElasticAlive) - { - var result = await elasticsearchService.Search(filter.ToESModel()).ConfigureAwait(false); - if (result.TotalAmount <= 0) - { - logger.LogInformation($"Result was {result.TotalAmount}"); - } - - return result.ToSearchResult(); - } - else - { - var databaseResult = await workshopService.GetByFilter(filter).ConfigureAwait(false); - - return new SearchResult() { TotalAmount = databaseResult.TotalAmount, Entities = databaseResult.Entities }; - } + return await workshopStrategy.SearchAsync(filter); } /// diff --git a/OutOfSchool/OutOfSchool.WebApi/Services/WorkshopServicesCombinerV2.cs b/OutOfSchool/OutOfSchool.WebApi/Services/WorkshopServicesCombinerV2.cs index e2e95ad914..4855a5264d 100644 --- a/OutOfSchool/OutOfSchool.WebApi/Services/WorkshopServicesCombinerV2.cs +++ b/OutOfSchool/OutOfSchool.WebApi/Services/WorkshopServicesCombinerV2.cs @@ -1,6 +1,7 @@ using OutOfSchool.Services.Enums; using OutOfSchool.WebApi.Models; using OutOfSchool.WebApi.Models.Workshop; +using OutOfSchool.WebApi.Services.Strategies.Interfaces; namespace OutOfSchool.WebApi.Services; @@ -8,13 +9,12 @@ public class WorkshopServicesCombinerV2 : WorkshopServicesCombiner, IWorkshopSer { public WorkshopServicesCombinerV2( IWorkshopService workshopService, - IElasticsearchService elasticsearchService, - ILogger logger, IElasticsearchSynchronizationService elasticsearchSynchronizationService, INotificationService notificationService, IEntityRepository favoriteRepository, - IApplicationRepository applicationRepository) - : base(workshopService, elasticsearchService, logger, elasticsearchSynchronizationService, notificationService, favoriteRepository, applicationRepository) + IApplicationRepository applicationRepository, + IWorkshopStrategy workshopStrategy) + : base(workshopService, elasticsearchSynchronizationService, notificationService, favoriteRepository, applicationRepository, workshopStrategy) { } diff --git a/OutOfSchool/OutOfSchool.WebApi/Startup.cs b/OutOfSchool/OutOfSchool.WebApi/Startup.cs index e003b0a25b..caa8932c96 100644 --- a/OutOfSchool/OutOfSchool.WebApi/Startup.cs +++ b/OutOfSchool/OutOfSchool.WebApi/Startup.cs @@ -1,4 +1,6 @@ using System.Text.Json.Serialization; +using OutOfSchool.WebApi.Services.Strategies.Interfaces; +using OutOfSchool.WebApi.Services.Strategies.WorkshopStrategies; namespace OutOfSchool.WebApi; @@ -195,6 +197,13 @@ public static void AddApplicationServices(this WebApplicationBuilder builder) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(sp => + { + var elasticSearchService = sp.GetRequiredService>(); + return elasticSearchService.IsElasticAlive + ? new WorkshopESStrategy(elasticSearchService, sp.GetRequiredService>()) + : new WorkshopServiceStrategy(sp.GetRequiredService(), sp.GetRequiredService>()); + }); // entities repositories services.AddTransient, EntityRepository>();