diff --git a/back/src/Kyoo.Abstractions/Controllers/ISearchManager.cs b/back/src/Kyoo.Abstractions/Controllers/ISearchManager.cs index e6175018..ed210a52 100644 --- a/back/src/Kyoo.Abstractions/Controllers/ISearchManager.cs +++ b/back/src/Kyoo.Abstractions/Controllers/ISearchManager.cs @@ -38,6 +38,7 @@ public interface ISearchManager public Task.SearchResult> SearchItems( string? query, Sort sortBy, + Filter? filter, SearchPagination pagination, Include? include = default ); @@ -98,6 +99,7 @@ public interface ISearchManager public Task.SearchResult> SearchEpisodes( string? query, Sort sortBy, + Filter? filter, SearchPagination pagination, Include? include = default ); @@ -113,6 +115,7 @@ public interface ISearchManager public Task.SearchResult> SearchStudios( string? query, Sort sortBy, + Filter? filter, SearchPagination pagination, Include? include = default ); diff --git a/back/src/Kyoo.Core/Views/Resources/SearchApi.cs b/back/src/Kyoo.Core/Views/Resources/SearchApi.cs index b3754d3c..323efd07 100644 --- a/back/src/Kyoo.Core/Views/Resources/SearchApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/SearchApi.cs @@ -44,7 +44,7 @@ public class SearchApi : BaseApi _searchManager = searchManager; } - // TODO: add filters and facets + // TODO: add facets /// /// Search collections @@ -143,11 +143,12 @@ public class SearchApi : BaseApi public async Task> SearchItems( [FromQuery] string? q, [FromQuery] Sort sortBy, + [FromQuery] Filter? filter, [FromQuery] SearchPagination pagination, [FromQuery] Include fields ) { - return SearchPage(await _searchManager.SearchItems(q, sortBy, pagination, fields)); + return SearchPage(await _searchManager.SearchItems(q, sortBy, filter, pagination, fields)); } /// @@ -169,11 +170,12 @@ public class SearchApi : BaseApi public async Task> SearchEpisodes( [FromQuery] string? q, [FromQuery] Sort sortBy, + [FromQuery] Filter? filter, [FromQuery] SearchPagination pagination, [FromQuery] Include fields ) { - return SearchPage(await _searchManager.SearchEpisodes(q, sortBy, pagination, fields)); + return SearchPage(await _searchManager.SearchEpisodes(q, sortBy, filter, pagination, fields)); } /// @@ -195,10 +197,11 @@ public class SearchApi : BaseApi public async Task> SearchStudios( [FromQuery] string? q, [FromQuery] Sort sortBy, + [FromQuery] Filter? filter, [FromQuery] SearchPagination pagination, [FromQuery] Include fields ) { - return SearchPage(await _searchManager.SearchStudios(q, sortBy, pagination, fields)); + return SearchPage(await _searchManager.SearchStudios(q, sortBy, filter, pagination, fields)); } } diff --git a/back/src/Kyoo.Meilisearch/FilterExtensionMethods.cs b/back/src/Kyoo.Meilisearch/FilterExtensionMethods.cs new file mode 100644 index 00000000..caa36f6a --- /dev/null +++ b/back/src/Kyoo.Meilisearch/FilterExtensionMethods.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; +using Kyoo.Abstractions.Models.Utils; + +namespace Kyoo.Meiliseach; + +public static class FilterExtensionMethods +{ + public static string? CreateMeilisearchFilter(this Filter? filter) + { + return filter switch + { + Filter.And and => $"({and.First.CreateMeilisearchFilter()}) AND ({and.Second.CreateMeilisearchFilter()})", + Filter.Or or => $"({or.First.CreateMeilisearchFilter()}) OR ({or.Second.CreateMeilisearchFilter()})", + Filter.Gt gt => $"{gt.Property} > {gt.Value}", + Filter.Lt lt => $"{lt.Property} < {lt.Value}", + Filter.Ge ge => $"{ge.Property} >= {ge.Value}", + Filter.Le le => $"{le.Property} <= {le.Value}", + Filter.Eq eq => $"{eq.Property} = {eq.Value}", + Filter.Has has => $"{has.Property} = {has.Value}", + Filter.Ne ne => $"{ne.Property} != {ne.Value}", + Filter.Not not => $"NOT ({not.Filter.CreateMeilisearchFilter()})", + Filter.CmpRandom => throw new ValidationException("Random comparison is not supported."), + _ => null + }; + } +} diff --git a/back/src/Kyoo.Meilisearch/SearchManager.cs b/back/src/Kyoo.Meilisearch/SearchManager.cs index 07b5ed11..cb7c8235 100644 --- a/back/src/Kyoo.Meilisearch/SearchManager.cs +++ b/back/src/Kyoo.Meilisearch/SearchManager.cs @@ -99,11 +99,12 @@ public class SearchManager : ISearchManager public Task.SearchResult> SearchItems( string? query, Sort sortBy, + Filter? filter, SearchPagination pagination, Include? include = default ) { - return _Search("items", query, null, sortBy, pagination, include); + return _Search("items", query, filter.CreateMeilisearchFilter(), sortBy, pagination, include); } /// @@ -143,22 +144,24 @@ public class SearchManager : ISearchManager public Task.SearchResult> SearchEpisodes( string? query, Sort sortBy, + Filter? filter, SearchPagination pagination, Include? include = default ) { - return _Search(nameof(Episode), query, null, sortBy, pagination, include); + return _Search(nameof(Episode), query, filter.CreateMeilisearchFilter(), sortBy, pagination, include); } /// public Task.SearchResult> SearchStudios( string? query, Sort sortBy, + Filter? filter, SearchPagination pagination, Include? include = default ) { - return _Search(nameof(Studio), query, null, sortBy, pagination, include); + return _Search(nameof(Studio), query, filter.CreateMeilisearchFilter(), sortBy, pagination, include); } private class IdResource