diff --git a/backend/CookifyAPI/CookifyAPI/Controllers/SearchController.cs b/backend/CookifyAPI/CookifyAPI/Controllers/SearchController.cs index eb0382b..c53c443 100644 --- a/backend/CookifyAPI/CookifyAPI/Controllers/SearchController.cs +++ b/backend/CookifyAPI/CookifyAPI/Controllers/SearchController.cs @@ -30,10 +30,17 @@ public async Task SearchIngredients([FromQuery] string? name, [Fr return Ok(results); } + // [HttpGet("recipes-Detailed")] + // public async Task SearchDetailedRecipes([FromQuery] RecipeSearchRequest request) + // { + // var results = await recipeService.SearchRecipesDetailedAsync(request); + // return Ok(results); + // } + [HttpGet("recipes")] public async Task SearchRecipes([FromQuery] RecipeSearchRequest request) { - var results = await recipeService.SearchRecipesDetailedAsync(request); + var results = await recipeService.SearchRecipesAsync(request); return Ok(results); } } \ No newline at end of file diff --git a/backend/CookifyAPI/CookifyAPI/Models/DTOs/Requests/RecipeSearchRequest.cs b/backend/CookifyAPI/CookifyAPI/Models/DTOs/Requests/RecipeSearchRequest.cs index afe567a..b525b50 100644 --- a/backend/CookifyAPI/CookifyAPI/Models/DTOs/Requests/RecipeSearchRequest.cs +++ b/backend/CookifyAPI/CookifyAPI/Models/DTOs/Requests/RecipeSearchRequest.cs @@ -9,7 +9,7 @@ public record RecipeSearchRequest( float? MinProtein, float? MaxProtein, float? MinFat, float? MaxFat, float? MinCalories, float? MaxCalories, - int? Difficulty, + [FromQuery] int[]? Difficulty, [FromQuery] int[]? TagIds, [FromQuery] int[]? IngredientIds ); \ No newline at end of file diff --git a/backend/CookifyAPI/CookifyAPI/Services/Implementations/RecipeService.cs b/backend/CookifyAPI/CookifyAPI/Services/Implementations/RecipeService.cs index eea8793..f344f36 100644 --- a/backend/CookifyAPI/CookifyAPI/Services/Implementations/RecipeService.cs +++ b/backend/CookifyAPI/CookifyAPI/Services/Implementations/RecipeService.cs @@ -196,7 +196,7 @@ public async Task> SearchRecipesDetailedAsync(RecipeSearch } if (request.MaxCookingTime.HasValue) query = query.Where(r => r.CookingTimeMin <= request.MaxCookingTime); - if (request.Difficulty.HasValue) query = query.Where(r => r.Difficulty == request.Difficulty); + //if (request.Difficulty.HasValue) query = query.Where(r => r.Difficulty == request.Difficulty); // Фильтры по БЖУ и Калориям if (request.MinCalories.HasValue) query = query.Where(r => r.Calories100g >= request.MinCalories); @@ -221,6 +221,11 @@ public async Task> SearchRecipesDetailedAsync(RecipeSearch query = query.Where(r => r.Ingredients.Any(i => request.IngredientIds.Contains(i.IngredientId))); } + if (request.Difficulty is { Length: > 0 }) + { + query = query.Where(r => request.Difficulty.Contains(r.Difficulty)); + } + var recipes = await query .AsSplitQuery() .Select(r => new RecipeDetailDto @@ -267,4 +272,78 @@ public async Task> SearchRecipesDetailedAsync(RecipeSearch return recipes; } + + public async Task> SearchRecipesAsync(RecipeSearchRequest request) + { + var query = context.Recipes.AsNoTracking(); + + if (!string.IsNullOrWhiteSpace(request.Title)) + { + var recipeIds = await searchService.SearchRecipeIdsAsync(request.Title); + + // Если Meili ничего не нашел, возвращаем пустой список, чтобы не делать запрос к БД + if (recipeIds.Length == 0) + { + Console.WriteLine($"No recipes found for {request.Title}"); + return new List(); + } + + query = query.Where(r => recipeIds.Contains(r.Id)); + } + + if (request.MaxCookingTime.HasValue) query = query.Where(r => r.CookingTimeMin <= request.MaxCookingTime); + //if (request.Difficulty.HasValue) query = query.Where(r => r.Difficulty == request.Difficulty); + + // Фильтры по БЖУ и Калориям + if (request.MinCalories.HasValue) query = query.Where(r => r.Calories100g >= request.MinCalories); + if (request.MaxCalories.HasValue) query = query.Where(r => r.Calories100g <= request.MaxCalories); + + if (request.MinProtein.HasValue) query = query.Where(r => r.Protein100g >= request.MinProtein); + if (request.MaxProtein.HasValue) query = query.Where(r => r.Protein100g <= request.MaxProtein); + + if (request.MinFat.HasValue) query = query.Where(r => r.Fat100g >= request.MinFat); + if (request.MaxFat.HasValue) query = query.Where(r => r.Fat100g <= request.MaxFat); + + if (request.MinCarb.HasValue) query = query.Where(r => r.Carb100g >= request.MinCarb); + if (request.MaxCarb.HasValue) query = query.Where(r => r.Carb100g <= request.MaxCarb); + + if (request.Difficulty is { Length: > 0 }) + { + query = query.Where(r => request.Difficulty.Contains(r.Difficulty)); + } + + if (request.TagIds is { Length: > 0 }) + { + var targetIds = request.TagIds.Distinct().ToList(); + int targetCount = targetIds.Count; + query = query.Where(r => r.Tags.Count(i => targetIds.Contains(i.TagId)) == targetCount); + } + + if (request.IngredientIds is { Length: > 0 }) + { + var targetIds = request.IngredientIds.Distinct().ToList(); + int targetCount = targetIds.Count; + + query = query.Where(r => r.Ingredients.Count(i => targetIds.Contains(i.IngredientId)) == targetCount); + } + + var recipes = await query + .AsSplitQuery() + .Select(r => new RecipeListDto() + { + Id = r.Id, + Title = r.Title, + CookingTimeMin = r.CookingTimeMin, + Servings = r.Servings, + Difficulty = r.Difficulty, + PreviewImageUrl = r.Images + .OrderBy(i => i.Order) + .Select(i => i.Url) + .FirstOrDefault(), + Tags = r.Tags.Select(m2m => m2m.Tag.Name).ToList(), + }) + .ToListAsync(); + + return recipes; + } } \ No newline at end of file diff --git a/backend/CookifyAPI/CookifyAPI/Services/Interfaces/IRecipeService.cs b/backend/CookifyAPI/CookifyAPI/Services/Interfaces/IRecipeService.cs index 43a0f8c..4dc9c00 100644 --- a/backend/CookifyAPI/CookifyAPI/Services/Interfaces/IRecipeService.cs +++ b/backend/CookifyAPI/CookifyAPI/Services/Interfaces/IRecipeService.cs @@ -6,9 +6,10 @@ namespace CookifyAPI.Services; public interface IRecipeService { - Task> GetRecipesListAsync(); + //Task> GetRecipesListAsync(); Task GetRecipeByIdAsync(int id); - Task> GetRecipesOffsetAsync(int page); + //Task> GetRecipesOffsetAsync(int page); Task> GetRecipesKeysetAsync(int? lastId); - Task> SearchRecipesDetailedAsync(RecipeSearchRequest request); + //Task> SearchRecipesDetailedAsync(RecipeSearchRequest request); + Task> SearchRecipesAsync(RecipeSearchRequest request); } \ No newline at end of file