fixed todo delete progatation in recipe

added count to IngredientController about what recipes we have or dont and 2 small typo mistakes

also added counting ingredients to IngredientService
This commit is contained in:
Aysegul 2026-01-08 22:06:45 +01:00
commit 16c8d4c6dc
3 changed files with 43 additions and 14 deletions

View file

@ -15,6 +15,7 @@
*/ */
package commons; package commons;
import jakarta.persistence.CascadeType;
import jakarta.persistence.CollectionTable; import jakarta.persistence.CollectionTable;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection; import jakarta.persistence.ElementCollection;
@ -60,7 +61,7 @@ public class Recipe {
// | 1 (Steak) | 40g pepper | // | 1 (Steak) | 40g pepper |
// | 1 (Steak) | Meat | // | 1 (Steak) | Meat |
// |----------------------------------| // |----------------------------------|
@OneToMany @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@CollectionTable(name = "recipe_ingredients", joinColumns = @JoinColumn(name = "recipe_id")) @CollectionTable(name = "recipe_ingredients", joinColumns = @JoinColumn(name = "recipe_id"))
@Column(name = "ingredient") @Column(name = "ingredient")
// TODO: Replace String with Embeddable Ingredient Class // TODO: Replace String with Embeddable Ingredient Class

View file

@ -1,5 +1,6 @@
package server.api; package server.api;
import commons.Ingredient; import commons.Ingredient;
import commons.ws.Topics; import commons.ws.Topics;
import commons.ws.messages.CreateIngredientMessage; import commons.ws.messages.CreateIngredientMessage;
@ -93,13 +94,22 @@ public class IngredientController {
* *
* @see Ingredient * @see Ingredient
*/ */
@GetMapping("/ingredients/{id}") @GetMapping("/ingredients/{id}/usage")
public ResponseEntity<Ingredient> getIngredientById(@PathVariable Long id) { public ResponseEntity<IngredientUsageResponse> getIngredientUsage(@PathVariable Long id) {
return ingredientService.findById(id) if (ingredientService.findById(id).isEmpty()) {
.map(ResponseEntity::ok) return ResponseEntity.notFound().build();
.orElseGet(() -> ResponseEntity.notFound().build()); }
// Server-side computation of how many recipes reference this ingredient
long usedInRecipes = ingredientService.countUsage(id);
return ResponseEntity.ok(new IngredientUsageResponse(id, usedInRecipes));
} }
/** /**
* Update an existing ingredient by its ID. * Update an existing ingredient by its ID.
* Maps to <code>PATCH /api/ingredients/{id}</code> * Maps to <code>PATCH /api/ingredients/{id}</code>
@ -126,7 +136,7 @@ public class IngredientController {
updated.setId(id); updated.setId(id);
return ingredientService.update(id, updated) return ingredientService.update(id, updated)
.map(saved -> { .map(saved -> {
messagingTemplate.convertAndSend(Topics.INGREDIENTS, new CreateIngredientMessage(saved)); messagingTemplate.convertAndSend(Topics.INGREDIENTS, new UpdateIngredientMessage(saved));
return ResponseEntity.ok(saved); return ResponseEntity.ok(saved);
}) })
.orElseGet(() -> ResponseEntity.notFound().build()); .orElseGet(() -> ResponseEntity.notFound().build());
@ -139,7 +149,7 @@ public class IngredientController {
* <p> * <p>
* If an ingredient with the same name already exists, * If an ingredient with the same name already exists,
* returns 400 Bad Request. * returns 400 Bad Request.
* * <p>
* If the ingredient is created successfully, * If the ingredient is created successfully,
* returns the created ingredient with 200 OK. * returns the created ingredient with 200 OK.
* </p> * </p>
@ -157,7 +167,7 @@ public class IngredientController {
return ingredientService.create(ingredient) return ingredientService.create(ingredient)
.map(saved -> { .map(saved -> {
messagingTemplate.convertAndSend(Topics.INGREDIENTS, new UpdateIngredientMessage(saved)); messagingTemplate.convertAndSend(Topics.INGREDIENTS, new CreateIngredientMessage(saved));
return ResponseEntity.ok(saved); return ResponseEntity.ok(saved);
}) })
.orElseGet(() -> ResponseEntity.badRequest().build()); .orElseGet(() -> ResponseEntity.badRequest().build());
@ -186,4 +196,6 @@ public class IngredientController {
messagingTemplate.convertAndSend(Topics.INGREDIENTS, new DeleteIngredientMessage(id)); messagingTemplate.convertAndSend(Topics.INGREDIENTS, new DeleteIngredientMessage(id));
return ResponseEntity.ok(true); return ResponseEntity.ok(true);
} }
public record IngredientUsageResponse(Long ingredientId, long usedInRecipes){}
} }

View file

@ -4,16 +4,21 @@ import commons.Ingredient;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import server.database.IngredientRepository; import server.database.IngredientRepository;
import server.database.RecipeIngredientRepository;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@Service @Service
public class IngredientService { public class IngredientService {
IngredientRepository ingredientRepository;
public IngredientService(IngredientRepository ingredientRepository) { private final IngredientRepository ingredientRepository;
private final RecipeIngredientRepository recipeIngredientRepository;
public IngredientService(IngredientRepository ingredientRepository,
RecipeIngredientRepository recipeIngredientRepository) {
this.ingredientRepository = ingredientRepository; this.ingredientRepository = ingredientRepository;
this.recipeIngredientRepository = recipeIngredientRepository;
} }
public Optional<Ingredient> findById(Long id) { public Optional<Ingredient> findById(Long id) {
@ -30,12 +35,16 @@ public class IngredientService {
/** /**
* Creates a new ingredient. Returns empty if the recipe with the same name or id already exists. * Creates a new ingredient. Returns empty if the recipe with the same name or id already exists.
*
* @param ingredient Ingredient to be saved in the db. * @param ingredient Ingredient to be saved in the db.
* @return The created ingredient (the ingredient arg with a new assigned id) or empty if it already exists in db. * @return The created ingredient (the ingredient arg with a new assigned id) or empty if it already exists in db.
*/ */
public Optional<Ingredient> create(Ingredient ingredient) { public Optional<Ingredient> create(Ingredient ingredient) {
if (ingredientRepository.existsByName(ingredient.getName()) || if (ingredient == null || ingredient.getName() == null) {
ingredientRepository.existsById(ingredient.getId())) { return Optional.empty();
}
if (ingredientRepository.existsByName(ingredient.getName())) {
return Optional.empty(); return Optional.empty();
} }
@ -44,7 +53,8 @@ public class IngredientService {
/** /**
* Updates an ingredient. The ingredient with the provided id will be replaced (in db) with the provided ingredient. * Updates an ingredient. The ingredient with the provided id will be replaced (in db) with the provided ingredient.
* @param id id of the ingredient to update. *
* @param id id of the ingredient to update.
* @param ingredient Ingredient to be saved in the db. * @param ingredient Ingredient to be saved in the db.
* @return The created ingredient (the ingredient arg with a new assigned id.) * @return The created ingredient (the ingredient arg with a new assigned id.)
*/ */
@ -64,4 +74,10 @@ public class IngredientService {
return true; return true;
} }
//actually counting the amount used in recipes
public long countUsage(long ingredientId) {
return recipeIngredientRepository.countByIngredientId(ingredientId);
}
} }