tag recipe relationship made

This commit is contained in:
durn
2026-03-03 21:44:04 -07:00
parent fcb00b32a7
commit d03cbaf9a3
8 changed files with 147 additions and 9 deletions
@@ -10,8 +10,7 @@ public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.anyRequest().permitAll()
);
@@ -15,6 +15,7 @@ public class RecipeDto {
private List<RecipeIngredientDto> ingredients;
private List<StepDto> steps;
private List<ImageDto> images;
private List<TagDto> tags;
@@ -24,7 +25,7 @@ public class RecipeDto {
}
public RecipeDto(String title, String description, Integer prepTimeMinutes, Integer cookTimeMinutes,
Integer servings, UserDto userDto, String status, List<RecipeIngredientDto> ingredients, List<StepDto> steps, List<ImageDto> images) {
Integer servings, UserDto userDto, String status, List<RecipeIngredientDto> ingredients, List<StepDto> steps, List<ImageDto> images, List<TagDto> tags) {
super();
this.title = title;
this.description = description;
@@ -36,6 +37,7 @@ public class RecipeDto {
this.ingredients = ingredients;
this.steps = steps;
this.images = images;
this.tags = tags;
}
// getters and setters
@@ -100,6 +102,15 @@ public class RecipeDto {
this.images = images;
}
public List<TagDto> getTags() {
return tags;
}
public void setTags(List<TagDto> tags) {
this.tags = tags;
}
public UserDto getUserDto() {
return userDto;
}
@@ -0,0 +1,28 @@
package com.example.demo.dto;
public class TagDto {
private String name;
public TagDto() {
super();
}
public TagDto(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -48,6 +48,13 @@ public class Recipe {
@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<Image> images = new HashSet<>();
// Recipe Tag relationship and also junction table
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "recipe_tags",
joinColumns = {@JoinColumn(name = "recipe_id")},
inverseJoinColumns = {@JoinColumn(name = "tag_id")})
private Set<Tag> tags = new HashSet<>();
// Default constructor
public Recipe() {}
@@ -147,4 +154,14 @@ public class Recipe {
this.images = images;
}
public Set<Tag> getTags() {
return tags;
}
public void setTags(Set<Tag> tags) {
this.tags = tags;
}
}
@@ -1,5 +1,8 @@
package com.example.demo.entity;
import java.util.HashSet;
import java.util.Set;
import jakarta.persistence.*;
@Entity
@@ -13,6 +16,10 @@ public class Tag {
@Column(nullable = false, unique = true)
private String name;
// Recipe is the manager for this relationship
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "tags")
private Set<Recipe> recipes = new HashSet<>();
// Required by JPA
public Tag() {}
@@ -36,4 +43,14 @@ public class Tag {
public void setName(String name) {
this.name = name;
}
public Set<Recipe> getRecipes() {
return recipes;
}
public void setRecipes(Set<Recipe> recipes) {
this.recipes = recipes;
}
}
@@ -2,12 +2,11 @@ package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.entity.Ingredient;
import com.example.demo.entity.Tag;
import java.util.Optional;
public interface TagRepo extends JpaRepository<Tag, Integer> {
Optional<Tag> findByName(String name);
}
@@ -8,6 +8,7 @@ import org.springframework.stereotype.Service;
import com.example.demo.dto.RecipeDto;
import com.example.demo.dto.UserDto;
import com.example.demo.dto.StepDto;
import com.example.demo.dto.TagDto;
import com.example.demo.dto.ImageDto;
import com.example.demo.dto.RecipeIngredientDto;
import com.example.demo.entity.Image;
@@ -15,6 +16,7 @@ import com.example.demo.entity.Ingredient;
import com.example.demo.entity.Recipe;
import com.example.demo.entity.RecipeIngredient;
import com.example.demo.entity.Step;
import com.example.demo.entity.Tag;
import com.example.demo.entity.User;
import com.example.demo.exception.NotFoundException;
import com.example.demo.repository.ImageRepo;
@@ -22,6 +24,7 @@ import com.example.demo.repository.IngredientRepo;
import com.example.demo.repository.RecipeIngredientRepo;
import com.example.demo.repository.RecipeRepo;
import com.example.demo.repository.StepRepo;
import com.example.demo.repository.TagRepo;
import com.example.demo.repository.UserRepo;
import com.example.demo.service.RecipeService;
@@ -37,8 +40,9 @@ private RecipeIngredientRepo recipeIngredientRepository;
private UserRepo userRepository;
private StepRepo stepRepository;
private ImageRepo imageRepository;
private TagRepo tagRepository;
public RecipeServiceImpl(RecipeRepo recipeRepository, IngredientRepo ingredientRepository, RecipeIngredientRepo recipeIngredientRepository, UserRepo userRepository, StepRepo stepRepository, ImageRepo imageRepository) {
public RecipeServiceImpl(RecipeRepo recipeRepository, IngredientRepo ingredientRepository, RecipeIngredientRepo recipeIngredientRepository, UserRepo userRepository, StepRepo stepRepository, ImageRepo imageRepository, TagRepo tagRepository) {
super();
this.recipeRepository = recipeRepository;
this.ingredientRepository = ingredientRepository;
@@ -46,6 +50,7 @@ private ImageRepo imageRepository;
this.userRepository = userRepository;
this.stepRepository = stepRepository;
this.imageRepository = imageRepository;
this.tagRepository = tagRepository;
}
public RecipeDto convertToDto(Recipe recipe) {
@@ -71,6 +76,12 @@ private ImageRepo imageRepository;
))
.toList();
List<TagDto> tagDtos = recipe.getTags().stream()
.map(ri -> new TagDto(
ri.getName()
))
.toList();
UserDto userDto = new UserDto(recipe.getUser().getId());
return new RecipeDto(
@@ -83,7 +94,8 @@ private ImageRepo imageRepository;
recipe.getStatus(),
ingredientDtos,
stepDtos,
imageDtos
imageDtos,
tagDtos
);
}
@@ -140,6 +152,27 @@ private ImageRepo imageRepository;
}
}
// if (dto.getTags() != null) {
// for (TagDto tagDto : dto.getTags()) {
// Tag tag = new Tag(tagDto.getName());
// tagRepository.save(tag);
// recipe.getTags().add(tag);
// }
// }
for (TagDto tDto : dto.getTags()) {
Tag tag = tagRepository.findByName(tDto.getName())
.orElseGet(() -> new Tag(tDto.getName()));
if (tag.getId() == null) {
tagRepository.save(tag);
}
recipe.getTags().add(tag);
}
Recipe saved = recipeRepository.save(recipe);
return convertToDto(saved);
@@ -188,6 +221,9 @@ private ImageRepo imageRepository;
List<ImageDto> updatedImages = recipeDto.getImages();
List<Image> imagesToRemove = new ArrayList<>();
List<TagDto> updatedTags = recipeDto.getTags();
List<Tag> tagsToRemove = new ArrayList<>();
for (RecipeIngredient ri : existingRecipe.getRecipeIngredients()) {
boolean existsInUpdatedList = false;
@@ -305,6 +341,37 @@ private ImageRepo imageRepository;
}
}
}
//same process as above just with tags instead, except for saving the tag
// since the relationship for this one was slightly different
if (updatedTags != null) {
for (Tag tag : existingRecipe.getTags()) {
boolean existsInUpdatedList = updatedTags.stream()
.anyMatch(dto -> dto.getName().equals(tag.getName()));
if (!existsInUpdatedList) tagsToRemove.add(tag);
}
existingRecipe.getTags().removeAll(tagsToRemove);
for (TagDto tagDto : updatedTags) {
Tag existingTag = existingRecipe.getTags().stream()
.filter(tag -> tag.getName().equals(tagDto.getName()))
.findFirst()
.orElse(null);
if (existingTag != null) {
existingTag.setName(tagDto.getName());
}
else {
Tag newTag = tagRepository.findByName(tagDto.getName())
.orElseGet(() -> tagRepository.save(new Tag(tagDto.getName())));
existingRecipe.getTags().add(newTag);
}
}
}
recipeRepository.save(existingRecipe);
return convertToDto(existingRecipe);
}