Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added strict match checkboxes for workshop filter #772

Merged
merged 6 commits into from
Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions OutOfSchool/OutOfSchool.ElasticsearchData/ESWorkshopProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -134,14 +133,14 @@ private QueryContainer CreateQueryFromFilter(WorkshopFilterES filter)

ageQuery = new NumericRangeQuery()
{
Field = Infer.Field<WorkshopES>(w => w.MinAge),
LessThanOrEqualTo = filter.MaxAge,
Field = filter.IsAppropriateAge ? Infer.Field<WorkshopES>(w => w.MinAge) : Infer.Field<WorkshopES>(w => w.MaxAge),
GreaterThanOrEqualTo = filter.MinAge,
};

ageQuery &= new NumericRangeQuery()
{
Field = Infer.Field<WorkshopES>(w => w.MaxAge),
GreaterThanOrEqualTo = filter.MinAge,
Field = filter.IsAppropriateAge ? Infer.Field<WorkshopES>(w => w.MaxAge) : Infer.Field<WorkshopES>(w => w.MinAge),
LessThanOrEqualTo = filter.MaxAge,
};

queryContainer &= ageQuery;
Expand Down Expand Up @@ -173,7 +172,9 @@ private QueryContainer CreateQueryFromFilter(WorkshopFilterES filter)
Path = Infer.Field<WorkshopES>(p => p.DateTimeRanges),
Query = new MatchQuery()
{
Field = Infer.Field<WorkshopES>(w => w.DateTimeRanges.First().Workdays),
Field = filter.IsStrictWorkdays
? Infer.Field<WorkshopES>(w => w.DateTimeRanges.First().Workdays.Suffix("keyword"))
: Infer.Field<WorkshopES>(w => w.DateTimeRanges.First().Workdays),
Query = filter.Workdays,
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,8 @@ public class WorkshopFilterES
public decimal Longitude { get; set; } = 0;

public IReadOnlyCollection<WorkshopStatus> Statuses { get; set; } = new List<WorkshopStatus>();

public bool IsAppropriateAge { get; set; } = false;

public bool IsStrictWorkdays { get; set; } = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,8 @@ public class WorkshopFilter : OffsetFilter
public decimal Longitude { get; set; } = 0;

public IReadOnlyCollection<WorkshopStatus> Statuses { get; set; } = new List<WorkshopStatus>();

public bool IsAppropriateAge { get; set; } = false;

public bool IsStrictWorkdays { get; set; } = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,9 @@ private Expression<Func<Workshop, bool>> 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)
Expand All @@ -577,7 +579,9 @@ private Expression<Func<Workshop, bool>> 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));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using OutOfSchool.WebApi.Models;

namespace OutOfSchool.WebApi.Services.Strategies.Interfaces;

public interface IWorkshopStrategy
{
Task<SearchResult<WorkshopCard>> SearchAsync(WorkshopFilter filter);
}
Original file line number Diff line number Diff line change
@@ -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<WorkshopES, WorkshopFilterES> elasticsearchService;
private readonly ILogger<WorkshopESStrategy> logger;

public WorkshopESStrategy(IElasticsearchService<WorkshopES, WorkshopFilterES> elasticsearchService, ILogger<WorkshopESStrategy> logger)
{
this.elasticsearchService = elasticsearchService ?? throw new ArgumentNullException();
this.logger = logger;
}

public async Task<SearchResult<WorkshopCard>> 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();
}
}
Original file line number Diff line number Diff line change
@@ -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<WorkshopServiceStrategy> logger;

public WorkshopServiceStrategy(IWorkshopService workshopService, ILogger<WorkshopServiceStrategy> logger)
{
this.workshopService = workshopService ?? throw new ArgumentNullException();
this.logger = logger;
}

public async Task<SearchResult<WorkshopCard>> SearchAsync(WorkshopFilter filter)
{
var databaseResult = await workshopService.GetByFilter(filter).ConfigureAwait(false);

if (databaseResult.TotalAmount <= 0)
{
logger?.LogInformation($"Result was {databaseResult.TotalAmount}");
}

return new SearchResult<WorkshopCard>() { TotalAmount = databaseResult.TotalAmount, Entities = databaseResult.Entities };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<WorkshopES, WorkshopFilterES> elasticsearchService;
private readonly ILogger<WorkshopServicesCombiner> logger;
private protected readonly IElasticsearchSynchronizationService elasticsearchSynchronizationService; // make it private after removing v2 version
private readonly INotificationService notificationService;
private readonly IEntityRepository<long, Favorite> favoriteRepository;
private readonly IApplicationRepository applicationRepository;
private readonly IWorkshopStrategy workshopStrategy;

public WorkshopServicesCombiner(
IWorkshopService workshopService,
IElasticsearchService<WorkshopES, WorkshopFilterES> elasticsearchService,
ILogger<WorkshopServicesCombiner> logger,
IElasticsearchSynchronizationService elasticsearchSynchronizationService,
INotificationService notificationService,
IEntityRepository<long, Favorite> 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;
}

/// <inheritdoc/>
Expand Down Expand Up @@ -136,22 +134,7 @@ public async Task<SearchResult<WorkshopCard>> 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<WorkshopCard>() { TotalAmount = databaseResult.TotalAmount, Entities = databaseResult.Entities };
}
return await workshopStrategy.SearchAsync(filter);
}

/// <inheritdoc/>
Expand All @@ -162,22 +145,7 @@ public async Task<SearchResult<WorkshopCard>> GetByFilter(WorkshopFilter filter)
return new SearchResult<WorkshopCard> { TotalAmount = 0, Entities = new List<WorkshopCard>() };
}

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<WorkshopCard>() { TotalAmount = databaseResult.TotalAmount, Entities = databaseResult.Entities };
}
return await workshopStrategy.SearchAsync(filter);
}

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
using OutOfSchool.Services.Enums;
using OutOfSchool.WebApi.Models;
using OutOfSchool.WebApi.Models.Workshop;
using OutOfSchool.WebApi.Services.Strategies.Interfaces;

namespace OutOfSchool.WebApi.Services;

public class WorkshopServicesCombinerV2 : WorkshopServicesCombiner, IWorkshopServicesCombinerV2
{
public WorkshopServicesCombinerV2(
IWorkshopService workshopService,
IElasticsearchService<WorkshopES, WorkshopFilterES> elasticsearchService,
ILogger<WorkshopServicesCombiner> logger,
IElasticsearchSynchronizationService elasticsearchSynchronizationService,
INotificationService notificationService,
IEntityRepository<long, Favorite> favoriteRepository,
IApplicationRepository applicationRepository)
: base(workshopService, elasticsearchService, logger, elasticsearchSynchronizationService, notificationService, favoriteRepository, applicationRepository)
IApplicationRepository applicationRepository,
IWorkshopStrategy workshopStrategy)
: base(workshopService, elasticsearchSynchronizationService, notificationService, favoriteRepository, applicationRepository, workshopStrategy)
{
}

Expand Down
9 changes: 9 additions & 0 deletions OutOfSchool/OutOfSchool.WebApi/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Text.Json.Serialization;
using OutOfSchool.WebApi.Services.Strategies.Interfaces;
using OutOfSchool.WebApi.Services.Strategies.WorkshopStrategies;

namespace OutOfSchool.WebApi;

Expand Down Expand Up @@ -195,6 +197,13 @@ public static void AddApplicationServices(this WebApplicationBuilder builder)
services.AddTransient<IBlockedProviderParentService, BlockedProviderParentService>();
services.AddTransient<ICodeficatorService, CodeficatorService>();
services.AddTransient<IGRPCCommonService, GRPCCommonService>();
services.AddTransient<IWorkshopStrategy>(sp =>
{
var elasticSearchService = sp.GetRequiredService<IElasticsearchService<WorkshopES, WorkshopFilterES>>();
return elasticSearchService.IsElasticAlive
? new WorkshopESStrategy(elasticSearchService, sp.GetRequiredService<ILogger<WorkshopESStrategy>>())
: new WorkshopServiceStrategy(sp.GetRequiredService<IWorkshopService>(), sp.GetRequiredService<ILogger<WorkshopServiceStrategy>>());
});

// entities repositories
services.AddTransient<IEntityRepository<long, Address>, EntityRepository<long, Address>>();
Expand Down