From 734030fa2c7e6d0b8cf0c92dd223c185d1ab748f Mon Sep 17 00:00:00 2001 From: Stian Lyng <stianlyng@protonmail.com> Date: Thu, 4 May 2023 15:41:06 +0200 Subject: [PATCH] enhanced weekly menu --- .../SmartMat/controller/RecipeController.java | 12 --- .../controller/WeeklyMenuController.java | 17 +++++ ...ipeFridgeMatch.java => RecipeDetails.java} | 12 +-- .../dto/response/RecipeWithMatchCount.java | 21 +++++ .../SmartMat/repository/RecipeRepository.java | 26 +++---- .../v233/SmartMat/service/RecipeService.java | 76 ++++++++++++++----- .../controller/WeeklyMenuControllerTest.java | 23 ++++-- 7 files changed, 125 insertions(+), 62 deletions(-) rename src/main/java/ntnu/idatt2016/v233/SmartMat/dto/response/{RecipeFridgeMatch.java => RecipeDetails.java} (70%) create mode 100644 src/main/java/ntnu/idatt2016/v233/SmartMat/dto/response/RecipeWithMatchCount.java diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/RecipeController.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/RecipeController.java index 3c4dcce1..aaa3bb28 100644 --- a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/RecipeController.java +++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/RecipeController.java @@ -4,7 +4,6 @@ import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.RestController; import lombok.AllArgsConstructor; -import ntnu.idatt2016.v233.SmartMat.dto.response.RecipeFridgeMatch; import ntnu.idatt2016.v233.SmartMat.entity.Recipe; import ntnu.idatt2016.v233.SmartMat.service.RecipeService; @@ -56,17 +55,6 @@ public class RecipeController { return ResponseEntity.ok(recipes); } - @GetMapping("/match/{fridgeId}/{recipeId}") - public ResponseEntity<List<RecipeFridgeMatch>> getRecipeWithByProductsInFridge( - @PathVariable("fridgeId") Long fridgeId, @PathVariable("recipeId") Long recipeId) { - - List<RecipeFridgeMatch> recipe = recipeService.getRecipeWithFridgeProductMatch(fridgeId, recipeId); - if (recipe.isEmpty()) { - return ResponseEntity.notFound().build(); - } else { - return ResponseEntity.ok(recipe); - } - } /** * add recipe to favorites in user diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/WeeklyMenuController.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/WeeklyMenuController.java index f7e4e753..74c65bb7 100644 --- a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/WeeklyMenuController.java +++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/WeeklyMenuController.java @@ -9,7 +9,9 @@ import java.util.List; import org.springframework.http.ResponseEntity; import lombok.AllArgsConstructor; +import ntnu.idatt2016.v233.SmartMat.dto.response.RecipeWithMatchCount; import ntnu.idatt2016.v233.SmartMat.dto.response.WeeklyMenuResponse; +import ntnu.idatt2016.v233.SmartMat.service.RecipeService; import ntnu.idatt2016.v233.SmartMat.service.WeeklyMenuService; @AllArgsConstructor @@ -17,6 +19,7 @@ import ntnu.idatt2016.v233.SmartMat.service.WeeklyMenuService; @RequestMapping("/api/weeklymenu") public class WeeklyMenuController { + /* private WeeklyMenuService weeklyMenuService; @GetMapping("/{fridgeId}") @@ -29,5 +32,19 @@ public class WeeklyMenuController { return ResponseEntity.ok(weeklyMenu); } } + */ + + final private RecipeService recipeService; + + @GetMapping("/{fridgeId}") + public ResponseEntity<Object> compareWeeklyMenuAndRecipeProducts(@PathVariable("fridgeId") Integer fridgeId) { + List<RecipeWithMatchCount> weeklyMenuDetails = recipeService.getWeeklyMenu(fridgeId); + + if (weeklyMenuDetails.isEmpty()) { + return ResponseEntity.notFound().build(); + } else { + return ResponseEntity.ok(weeklyMenuDetails); + } + } } diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/dto/response/RecipeFridgeMatch.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/dto/response/RecipeDetails.java similarity index 70% rename from src/main/java/ntnu/idatt2016/v233/SmartMat/dto/response/RecipeFridgeMatch.java rename to src/main/java/ntnu/idatt2016/v233/SmartMat/dto/response/RecipeDetails.java index 586ce3c8..2fd6f3f2 100644 --- a/src/main/java/ntnu/idatt2016/v233/SmartMat/dto/response/RecipeFridgeMatch.java +++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/dto/response/RecipeDetails.java @@ -12,15 +12,11 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor +public class RecipeDetails { -public class RecipeFridgeMatch { - private Integer recipeId; private String recipeName; private String recipeDescription; - private long ean; - private String productName; - private String productDescription; - private boolean inFridge; - -} + private String recipeImage; + +} \ No newline at end of file diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/dto/response/RecipeWithMatchCount.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/dto/response/RecipeWithMatchCount.java new file mode 100644 index 00000000..0dbdf685 --- /dev/null +++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/dto/response/RecipeWithMatchCount.java @@ -0,0 +1,21 @@ +package ntnu.idatt2016.v233.SmartMat.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * This class represents a response for a weekly menu. + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor + +public class RecipeWithMatchCount { + + private RecipeDetails recipeDetails; + private int matchCount; + +} \ No newline at end of file diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/RecipeRepository.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/RecipeRepository.java index efea184a..d85894c2 100644 --- a/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/RecipeRepository.java +++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/RecipeRepository.java @@ -23,25 +23,19 @@ public interface RecipeRepository extends JpaRepository<Recipe, Long> { List<Recipe> findAllByName(String name); @Query( value = """ - SELECT r.recipe_id, r.recipe_name,r.recipe_description,r.image_url, COUNT(fp.ean) as product_count - FROM recipe r - LEFT JOIN recipe_product rp ON r.recipe_id = rp.recipe_id - LEFT JOIN fridge_product fp ON rp.ean = fp.ean AND fp.fridge_id = :fridgeId - GROUP BY r.recipe_id, r.recipe_name - ORDER BY product_count DESC - LIMIT 5; + select p2.item_name, f.fridge_id + from fridge f + inner join fridge_product fp on f.fridge_id = fp.fridge_id and f.fridge_id = :fridgeId + inner join product p2 on p2.ean = fp.ean """, nativeQuery = true) - List<Object[]> findWeeklyMenu(@Param("fridgeId") long fridgeId); + List<Object[]> findWeeklyMenu(long fridgeId); @Query( value = """ - SELECT r.recipe_id, r.recipe_name, r.recipe_description, p.ean, p.item_name, p.description as product_description, - CASE WHEN fp.fridge_id IS NOT NULL THEN TRUE ELSE FALSE END as in_fridge - FROM recipe AS r - JOIN recipe_product AS rp ON r.recipe_id = rp.recipe_id - JOIN product AS p ON rp.ean = p.ean - LEFT JOIN fridge_product AS fp ON p.ean = fp.ean AND fp.fridge_id = :fridgeId - WHERE r.recipe_id = :recipeId ; + SELECT r.recipe_id, r.recipe_name, r.recipe_description, r.image_url, p.item_name + FROM recipe r + inner JOIN recipe_product rp ON r.recipe_id = rp.recipe_id + inner join product p on rp.ean = p.ean """ , nativeQuery = true) - List<Object[]> findRecipeWithMatchingProductsInFridge(long fridgeId, long recipeId); + List<Object[]> findRecipeProductsWithName(); } diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/RecipeService.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/RecipeService.java index bdcb8888..783bcb4b 100644 --- a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/RecipeService.java +++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/RecipeService.java @@ -1,11 +1,15 @@ package ntnu.idatt2016.v233.SmartMat.service; -import ntnu.idatt2016.v233.SmartMat.dto.response.RecipeFridgeMatch; +import ntnu.idatt2016.v233.SmartMat.dto.response.RecipeDetails; +import ntnu.idatt2016.v233.SmartMat.dto.response.RecipeWithMatchCount; import ntnu.idatt2016.v233.SmartMat.entity.Recipe; import ntnu.idatt2016.v233.SmartMat.entity.user.User; import ntnu.idatt2016.v233.SmartMat.repository.RecipeRepository; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; @@ -110,25 +114,6 @@ public class RecipeService { recipeRepository.save(recipe); } - public List<RecipeFridgeMatch> getRecipeWithFridgeProductMatch(long fridgeId, long recipeId) { - - List<Object[]> rawData = recipeRepository.findRecipeWithMatchingProductsInFridge(fridgeId, recipeId); - - List<RecipeFridgeMatch> result = rawData.stream() - .map(row -> new RecipeFridgeMatch( - (Integer) row[0], - (String) row[1], - (String) row[2], - (Long) row[3], - (String) row[4], - (String) row[5], - (Boolean) row[6] - )) - .collect(Collectors.toList()); - - return result; - } - /** * Adds a recipe to a users favorites * @param recipeId id of the recipe @@ -180,4 +165,55 @@ public class RecipeService { return ResponseEntity.ok("Recipe deleted from favorites"); } } + public List<RecipeWithMatchCount> getWeeklyMenu(Integer fridgeId) { + // Get the results from both repository methods + List<Object[]> weeklyMenu = recipeRepository.findWeeklyMenu(fridgeId); + + List<Object[]> recipeProducts = recipeRepository.findRecipeProductsWithName(); + + // Prepare a map to store RecipeDetails with their match count + Map<RecipeDetails, Integer> recipeMatchCountMap = new HashMap<>(); + + // Compare the item_name on both lists + for (Object[] menuRow : weeklyMenu) { + String menuRowItemName = (String) menuRow[0]; + for (Object[] recipeProductRow : recipeProducts) { + String recipeProductRowItemName = (String) recipeProductRow[4]; + List<String> recipeProductWords = Arrays.asList(recipeProductRowItemName.split("\\s+")); + + boolean allWordsContained = recipeProductWords.stream() + .allMatch(word -> menuRowItemName.contains(word)); + + if (allWordsContained) { + Integer recipeId = ((Integer) recipeProductRow[0]).intValue(); + String recipeName = (String) recipeProductRow[1]; + String recipeDescription = (String) recipeProductRow[2]; + String recipeImage = (String) recipeProductRow[3]; + RecipeDetails recipeDetails = new RecipeDetails(recipeId, recipeName, recipeDescription, recipeImage); + + recipeMatchCountMap.put(recipeDetails, recipeMatchCountMap.getOrDefault(recipeDetails, 0) + 1); + } + } + } + + // Get a list of unique RecipeDetails from recipeProducts + List<RecipeDetails> uniqueRecipeDetails = recipeProducts.stream() + .map(row -> new RecipeDetails(((Integer) row[0]).intValue(), (String) row[1], (String) row[2], (String) row[3])) + .distinct() + .collect(Collectors.toList()); + + // Convert the map to a list of RecipeWithMatchCount + List<RecipeWithMatchCount> commonRecipes = recipeMatchCountMap.entrySet().stream() + .map(entry -> new RecipeWithMatchCount(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); + + // Add additional recipes from uniqueRecipeDetails with a count of 0 if the list has less than 5 recipes + for (RecipeDetails recipeDetails : uniqueRecipeDetails) { + if (commonRecipes.size() < 5 && !recipeMatchCountMap.containsKey(recipeDetails)) { + commonRecipes.add(new RecipeWithMatchCount(recipeDetails, 0)); + } + } + + return commonRecipes; + } } \ No newline at end of file diff --git a/src/test/java/ntnu/idatt2016/v233/SmartMat/controller/WeeklyMenuControllerTest.java b/src/test/java/ntnu/idatt2016/v233/SmartMat/controller/WeeklyMenuControllerTest.java index 17a69d72..0d58818c 100644 --- a/src/test/java/ntnu/idatt2016/v233/SmartMat/controller/WeeklyMenuControllerTest.java +++ b/src/test/java/ntnu/idatt2016/v233/SmartMat/controller/WeeklyMenuControllerTest.java @@ -1,6 +1,9 @@ package ntnu.idatt2016.v233.SmartMat.controller; +import ntnu.idatt2016.v233.SmartMat.dto.response.RecipeDetails; +import ntnu.idatt2016.v233.SmartMat.dto.response.RecipeWithMatchCount; import ntnu.idatt2016.v233.SmartMat.dto.response.WeeklyMenuResponse; +import ntnu.idatt2016.v233.SmartMat.service.RecipeService; import ntnu.idatt2016.v233.SmartMat.service.WeeklyMenuService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -23,6 +26,9 @@ public class WeeklyMenuControllerTest { @InjectMocks private WeeklyMenuController weeklyMenuController; + @Mock + private RecipeService recipeService; + @Mock private WeeklyMenuService weeklyMenuService; @@ -48,10 +54,15 @@ public class WeeklyMenuControllerTest { @Test public void getWeeklyMenu_found() { - long fridgeId = 1L; - when(weeklyMenuService.getWeeklyMenu(fridgeId)).thenReturn(weeklyMenu); + Integer fridgeId = 1; + List<RecipeWithMatchCount> weeklyMenu = List.of( + new RecipeWithMatchCount(new RecipeDetails(1, "Recipe 1", "Description 1", "ImageURL 1"), 3), + new RecipeWithMatchCount(new RecipeDetails(2, "Recipe 2", "Description 2", "ImageURL 2"), 1) + ); + + when(recipeService.getWeeklyMenu(fridgeId)).thenReturn(weeklyMenu); - ResponseEntity<List<WeeklyMenuResponse>> response = weeklyMenuController.getWeeklyMenu(fridgeId); + ResponseEntity<Object> response = weeklyMenuController.compareWeeklyMenuAndRecipeProducts(fridgeId); assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(weeklyMenu, response.getBody()); @@ -59,10 +70,10 @@ public class WeeklyMenuControllerTest { @Test public void getWeeklyMenu_notFound() { - long fridgeId = 1L; - when(weeklyMenuService.getWeeklyMenu(fridgeId)).thenReturn(new ArrayList<>()); + Integer fridgeId = 1; + when(recipeService.getWeeklyMenu(fridgeId)).thenReturn(new ArrayList<>()); - ResponseEntity<List<WeeklyMenuResponse>> response = weeklyMenuController.getWeeklyMenu(fridgeId); + ResponseEntity<Object> response = weeklyMenuController.compareWeeklyMenuAndRecipeProducts(fridgeId); assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); } -- GitLab