Merge branch 'CountringRecipeIngredients' into 'main'
added counting ingredients to serverside requirment of 4.3 Closes #51 See merge request cse1105/2025-2026/teams/csep-team-76!43
This commit is contained in:
commit
809457254d
3 changed files with 43 additions and 9 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,6 +94,7 @@ public class IngredientController {
|
||||||
*
|
*
|
||||||
* @see Ingredient
|
* @see Ingredient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@GetMapping("/ingredients/{id}")
|
@GetMapping("/ingredients/{id}")
|
||||||
public ResponseEntity<Ingredient> getIngredientById(@PathVariable Long id) {
|
public ResponseEntity<Ingredient> getIngredientById(@PathVariable Long id) {
|
||||||
return ingredientService.findById(id)
|
return ingredientService.findById(id)
|
||||||
|
|
@ -100,6 +102,19 @@ public class IngredientController {
|
||||||
.orElseGet(() -> ResponseEntity.notFound().build());
|
.orElseGet(() -> ResponseEntity.notFound().build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/ingredients/{id}/usage")
|
||||||
|
public ResponseEntity<IngredientUsageResponse> getIngredientUsage(@PathVariable Long id) {
|
||||||
|
if (ingredientService.findById(id).isEmpty()) {
|
||||||
|
return 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 +141,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 +154,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 +172,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 +201,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){}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,6 +53,7 @@ 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);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue