diff --git a/src/main/java/dev/example/restaurantManager/controller/MenuController.java b/src/main/java/dev/example/restaurantManager/controller/MenuController.java new file mode 100644 index 0000000..eb5c26a --- /dev/null +++ b/src/main/java/dev/example/restaurantManager/controller/MenuController.java @@ -0,0 +1,87 @@ +package dev.example.restaurantManager.controller; + +import dev.example.restaurantManager.model.MenuRestaurant; +import dev.example.restaurantManager.service.MenuService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.List; + +@RequestMapping("/api/v1/menus") +@RestController +public class MenuController { + + @Autowired + MenuService menuService; + + // manage request by ResponseEntity with all menus + @GetMapping("/allMenus") + public ResponseEntity> getAllMenus( ) { + List menus = menuService.getAllMenus(); + HttpHeaders headers = getCommonHeaders("Get all menus"); + + return menus != null && !menus.isEmpty() + ? new ResponseEntity<>(menus, headers, HttpStatus.OK) + : new ResponseEntity<>(headers, HttpStatus.NOT_FOUND); + } + + @PostMapping + public ResponseEntity createMenu(@RequestBody MenuRestaurant menu) { + MenuRestaurant createdMenu = menuService.createMenu(menu); + HttpHeaders headers = getCommonHeaders("Create a new menu"); + + return createdMenu != null + ? new ResponseEntity<>(createdMenu, headers, HttpStatus.CREATED) + : new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST); + } + + @PutMapping("/{id}") + public ResponseEntity updateMenu(@PathVariable String id, @RequestBody MenuRestaurant menuDetails) { + MenuRestaurant updatedMenu = menuService.updateMenu(id, menuDetails); + HttpHeaders headers = getCommonHeaders("Update a menu"); + + return updatedMenu != null + ? new ResponseEntity<>(updatedMenu, headers, HttpStatus.OK) + : new ResponseEntity<>(headers, HttpStatus.NOT_FOUND); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteMenu(@PathVariable String id) { + menuService.deleteMenu(id); + HttpHeaders headers = getCommonHeaders("Delete a menu"); + boolean deleted = menuService.getMenuById(id) == null; + headers.add("deleted", String.valueOf(deleted)); + + return deleted + ? new ResponseEntity<>(headers, HttpStatus.NO_CONTENT) + : new ResponseEntity<>(headers, HttpStatus.NOT_FOUND); + } + + @GetMapping("/{id}") + public ResponseEntity getMenuById(@PathVariable String id) { + MenuRestaurant menu = menuService.getMenuById(id); + HttpHeaders headers = getCommonHeaders("Get a menu by Id"); + + return menu != null + ? new ResponseEntity<>(menu, headers, HttpStatus.OK) + : new ResponseEntity<>(headers, HttpStatus.NOT_FOUND); + } + + private HttpHeaders getCommonHeaders(String description) { + HttpHeaders headers = new HttpHeaders(); + headers.add("desc", description); + headers.add("content-type", "application/json"); + headers.add("date", new Date().toString()); + headers.add("server", "H2 Database"); + headers.add("version", "1.0.0"); + headers.add("menus-count", String.valueOf(menuService.countMenus())); + headers.add("object", "menus"); + return headers; + } + + +} diff --git a/src/main/java/dev/example/restaurantManager/controller/MenuItemController.java b/src/main/java/dev/example/restaurantManager/controller/MenuItemController.java new file mode 100644 index 0000000..2e57174 --- /dev/null +++ b/src/main/java/dev/example/restaurantManager/controller/MenuItemController.java @@ -0,0 +1,87 @@ +package dev.example.restaurantManager.controller; + +import dev.example.restaurantManager.model.MenuItem; +import dev.example.restaurantManager.service.MenuItemService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.List; + +@RequestMapping("/api/v1/items") +@RestController +public class MenuItemController { + + @Autowired + MenuItemService itemService; + + // manage request by ResponseEntity with all menus + @GetMapping("/allItems") + public ResponseEntity> getAllItems( ) { + List menus = itemService.getAllItems(); + HttpHeaders headers = getCommonHeaders("Get all items"); + + return menus != null && !menus.isEmpty() + ? new ResponseEntity<>(menus, headers, HttpStatus.OK) + : new ResponseEntity<>(headers, HttpStatus.NOT_FOUND); + } + + @PostMapping + public ResponseEntity createMenu(@RequestBody MenuItem item) { + MenuItem createdItem = itemService.createItem(item); + HttpHeaders headers = getCommonHeaders("Create a new item"); + + return createdItem != null + ? new ResponseEntity<>(createdItem, headers, HttpStatus.CREATED) + : new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST); + } + + @PutMapping("/{id}") + public ResponseEntity updateItem(@PathVariable String id, @RequestBody MenuItem itemDetails) { + MenuItem updatedItem = itemService.updateItem(id, itemDetails); + HttpHeaders headers = getCommonHeaders("Update an item"); + + return updatedItem != null + ? new ResponseEntity<>(updatedItem, headers, HttpStatus.OK) + : new ResponseEntity<>(headers, HttpStatus.NOT_FOUND); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteItem(@PathVariable String id) { + itemService.deleteItem(id); + HttpHeaders headers = getCommonHeaders("Delete an item"); + boolean deleted = itemService.getItemById(id) == null; + headers.add("deleted", String.valueOf(deleted)); + + return deleted + ? new ResponseEntity<>(headers, HttpStatus.NO_CONTENT) + : new ResponseEntity<>(headers, HttpStatus.NOT_FOUND); + } + + @GetMapping("/{id}") + public ResponseEntity getItemById(@PathVariable String id) { + MenuItem item = itemService.getItemById(id); + HttpHeaders headers = getCommonHeaders("Get an item by Id"); + + return item != null + ? new ResponseEntity<>(item, headers, HttpStatus.OK) + : new ResponseEntity<>(headers, HttpStatus.NOT_FOUND); + } + + private HttpHeaders getCommonHeaders(String description) { + HttpHeaders headers = new HttpHeaders(); + headers.add("desc", description); + headers.add("content-type", "application/json"); + headers.add("date", new Date().toString()); + headers.add("server", "H2 Database"); + headers.add("version", "1.0.0"); + headers.add("items-count", String.valueOf(itemService.countItems())); + headers.add("object", "items"); + return headers; + } + + +} diff --git a/src/main/java/dev/example/restaurantManager/model/CourseType.java b/src/main/java/dev/example/restaurantManager/model/CourseType.java new file mode 100644 index 0000000..4f21359 --- /dev/null +++ b/src/main/java/dev/example/restaurantManager/model/CourseType.java @@ -0,0 +1,7 @@ +package dev.example.restaurantManager.model; + +public enum CourseType { + STARTER, + MAIN, + DESSERT +} diff --git a/src/main/java/dev/example/restaurantManager/model/MenuItem.java b/src/main/java/dev/example/restaurantManager/model/MenuItem.java new file mode 100644 index 0000000..62a5c7a --- /dev/null +++ b/src/main/java/dev/example/restaurantManager/model/MenuItem.java @@ -0,0 +1,76 @@ +package dev.example.restaurantManager.model; + +import jakarta.persistence.*; +import lombok.Data; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +@Data +@Entity +public class MenuItem { + + @Id + private String id; + + private String name; + private String description; + private boolean isSpicy; + private boolean hasGluten; + private boolean isAvailable; + + @Enumerated(EnumType.STRING) + private CourseType courseType; + + @ManyToMany(mappedBy = "items") + private ArrayList menus; + + public void addMenus(List newMenus){ + if(newMenus== null){ + return; + } + if(this.menus == null){ + this.menus = new ArrayList<>(); + } + for(MenuRestaurant menu:newMenus){ + if(!this.menus.contains(menu)){ + menu.setItems(new ArrayList<>(Arrays.asList(this))); + this.menus.add(menu); + } + } + } + + + // Default constructor + public MenuItem() { + this.id = UUID.randomUUID().toString(); + } + + // Constructors, getters, and setters + + @Override + public boolean equals(Object other){ + if(this==other){ + return true; + } + + if(other == null || !(other instanceof MenuItem) ){ + return false; + } + + MenuItem that = (MenuItem)other; + + return this.id.equals(that.id) && + this.name.equals(that.name) && + this.description.equals(that.description) && + this.isSpicy == that.isSpicy && + this.hasGluten == that.hasGluten && + this.isAvailable == that.isAvailable && + this.courseType == that.courseType + ; + } + +} + diff --git a/src/main/java/dev/example/restaurantManager/model/MenuRestaurant.java b/src/main/java/dev/example/restaurantManager/model/MenuRestaurant.java index 1d2d819..adae21d 100644 --- a/src/main/java/dev/example/restaurantManager/model/MenuRestaurant.java +++ b/src/main/java/dev/example/restaurantManager/model/MenuRestaurant.java @@ -1,13 +1,11 @@ package dev.example.restaurantManager.model; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToMany; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; @Data @@ -27,13 +25,43 @@ public class MenuRestaurant { @ManyToMany(mappedBy = "menus", fetch = FetchType.LAZY) private List orders = new ArrayList<>(); + @ManyToMany + @JoinTable(name = "ITEMS_ON_MENUS", + joinColumns = @JoinColumn(name = "MENU_ID", referencedColumnName="id"), + inverseJoinColumns = @JoinColumn(name = "ITEM_ID", referencedColumnName="id")) + private List items; + + public void addMenuItems(List newItems){ + if(newItems== null){ + return; + } + if(this.items == null){ + this.items = new ArrayList<>(); + } + for(MenuItem menuItem:newItems){ + if(!this.items.contains(menuItem)){ + menuItem.setMenus(new ArrayList<>(Arrays.asList(this))); + this.items.add(menuItem); + } + } + } + + public void removeMenuItems(List newItems){ + if(this.items == null || newItems== null || newItems.size() == 0){ + return; + } + for(MenuItem menuItem:newItems){ + if(this.items.contains(menuItem)){ + this.items.remove(menuItem); + } + } + } + + public MenuRestaurant(String id, String name, Double price, String content, boolean active, boolean water,List orders) { + this(id,name,price,content,active,water,orders,null); + } public MenuRestaurant(String id, String name, Double price, String content, boolean active, boolean water) { - this.id = id; - this.name = name; - this.price = price; - this.content = content; - this.active = active; - this.water = water; + this(id,name,price,content,active,water,null,null); } //We might want to exclude 'orders' from toString() to avoid circular references diff --git a/src/main/java/dev/example/restaurantManager/repository/MenuItemRepository.java b/src/main/java/dev/example/restaurantManager/repository/MenuItemRepository.java new file mode 100644 index 0000000..34cab03 --- /dev/null +++ b/src/main/java/dev/example/restaurantManager/repository/MenuItemRepository.java @@ -0,0 +1,6 @@ +package dev.example.restaurantManager.repository; + +import dev.example.restaurantManager.model.MenuItem; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MenuItemRepository extends JpaRepository {} diff --git a/src/main/java/dev/example/restaurantManager/service/MenuItemService.java b/src/main/java/dev/example/restaurantManager/service/MenuItemService.java new file mode 100644 index 0000000..e456cbe --- /dev/null +++ b/src/main/java/dev/example/restaurantManager/service/MenuItemService.java @@ -0,0 +1,16 @@ +package dev.example.restaurantManager.service; + +import dev.example.restaurantManager.model.MenuItem; + +import java.util.List; + +public interface MenuItemService { + + List getAllItems(); + MenuItem createItem(MenuItem item); + MenuItem getItemById(String id); + MenuItem updateItem(String id,MenuItem itemDetails); + void deleteItem(String id); + long countItems(); + +} diff --git a/src/main/java/dev/example/restaurantManager/service/MenuItemServiceImpl.java b/src/main/java/dev/example/restaurantManager/service/MenuItemServiceImpl.java new file mode 100644 index 0000000..2227008 --- /dev/null +++ b/src/main/java/dev/example/restaurantManager/service/MenuItemServiceImpl.java @@ -0,0 +1,49 @@ +package dev.example.restaurantManager.service; + +import dev.example.restaurantManager.model.MenuItem; +import dev.example.restaurantManager.repository.MenuItemRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class MenuItemServiceImpl implements MenuItemService { + + @Autowired + MenuItemRepository itemRepository; + + @Override + public List getAllItems() { + return itemRepository.findAll(); + } + + @Override + public MenuItem createItem(MenuItem item) { + return itemRepository.save(item); + } + + @Override + public MenuItem getItemById(String id) { + return itemRepository.findById(id).orElse(null); + } + + @Override + public MenuItem updateItem(String id, MenuItem itemDetails) { + MenuItem item = getItemById(id); + if(item==null) { + return null; + } + return itemRepository.save(itemDetails); + } + + @Override + public void deleteItem(String id) { + itemRepository.deleteById(id); + } + + @Override + public long countItems() { + return itemRepository.count(); + } +} diff --git a/src/main/java/dev/example/restaurantManager/service/MenuService.java b/src/main/java/dev/example/restaurantManager/service/MenuService.java new file mode 100644 index 0000000..0cf9a56 --- /dev/null +++ b/src/main/java/dev/example/restaurantManager/service/MenuService.java @@ -0,0 +1,14 @@ +package dev.example.restaurantManager.service; + +import dev.example.restaurantManager.model.MenuRestaurant; + +import java.util.List; + +public interface MenuService { + List getAllMenus(); + MenuRestaurant createMenu(MenuRestaurant menu); + MenuRestaurant getMenuById(String id); + MenuRestaurant updateMenu(String id,MenuRestaurant menuDetails); + void deleteMenu(String id); + long countMenus(); +} diff --git a/src/main/java/dev/example/restaurantManager/service/MenuServiceImpl.java b/src/main/java/dev/example/restaurantManager/service/MenuServiceImpl.java new file mode 100644 index 0000000..19bc8de --- /dev/null +++ b/src/main/java/dev/example/restaurantManager/service/MenuServiceImpl.java @@ -0,0 +1,48 @@ +package dev.example.restaurantManager.service; + +import dev.example.restaurantManager.model.MenuRestaurant; +import dev.example.restaurantManager.repository.MenuRestaurantRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class MenuServiceImpl implements MenuService { + @Autowired + private MenuRestaurantRepository menuRepository; + + @Override + public List getAllMenus() { + return menuRepository.findAll(); + } + + @Override + public MenuRestaurant createMenu(MenuRestaurant menu) { + return menuRepository.save(menu); + } + + @Override + public MenuRestaurant getMenuById(String id) { + return menuRepository.findById(id).orElse(null); + } + + @Override + public MenuRestaurant updateMenu(String id, MenuRestaurant menuDetails) { + MenuRestaurant menu = getMenuById(id); + if(menu== null) { + return null; + } + return menuRepository.save(menuDetails); + } + + @Override + public void deleteMenu(String id) { + menuRepository.deleteById(id); + } + + @Override + public long countMenus() { + return menuRepository.count(); + } +} diff --git a/src/test/java/dev/example/restaurantManager/MenuItemTest.java b/src/test/java/dev/example/restaurantManager/MenuItemTest.java new file mode 100644 index 0000000..324b345 --- /dev/null +++ b/src/test/java/dev/example/restaurantManager/MenuItemTest.java @@ -0,0 +1,198 @@ +package dev.example.restaurantManager; + +import dev.example.restaurantManager.model.CourseType; +import dev.example.restaurantManager.model.MenuItem; +import dev.example.restaurantManager.model.MenuRestaurant; +import dev.example.restaurantManager.repository.MenuItemRepository; +import dev.example.restaurantManager.repository.MenuRestaurantRepository; +import jakarta.validation.constraints.AssertTrue; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +public class MenuItemTest { + + @Autowired + private MenuItemRepository menuItemRepository; + @Autowired + private MenuRestaurantRepository menuRepository; + + + private List createFakeMenuItems(){ + MenuItem i1 = new MenuItem(); + i1.setName("Macarrones carbonara"); + i1.setDescription("Macarrones carbonara desc."); + i1.setCourseType(CourseType.MAIN); + i1.setSpicy(false); + i1.setHasGluten(true); + i1.setAvailable(true); + + MenuItem i2 = new MenuItem(); + i2.setName("Ensalada de burrata"); + i2.setDescription("Ensalada de burrata desc."); + i2.setCourseType(CourseType.STARTER); + i2.setSpicy(false); + i2.setHasGluten(true); + i2.setAvailable(true); + + MenuItem i3 = new MenuItem(); + i3.setName("Tiramisú"); + i3.setDescription("Tiramisú desc."); + i3.setCourseType(CourseType.DESSERT); + i3.setSpicy(false); + i3.setHasGluten(true); + i3.setAvailable(true); + + return Arrays.asList(i1,i2,i3); + } + + + @Test + public void createMenuItemsInDBTest() { + + List menuItems = createFakeMenuItems(); + + for(MenuItem mi:menuItems){ + menuItemRepository.save(mi); + } + + // check if saved + List items = menuItemRepository.findAll(); + for(MenuItem mi:menuItems){ + assert(items.contains(mi)); + } + + MenuItem i4 = new MenuItem(); + i4.setName("Panceta"); + i4.setDescription("Panceta desc."); + i4.setCourseType(CourseType.STARTER); + i4.setSpicy(false); + i4.setHasGluten(true); + i4.setAvailable(true); + + assert(!items.contains(i4)); + + } + + + @Test + public void relationshipMenuItemsToMenuUnidirectionalTest() { + + List menuItems = createFakeMenuItems(); + + for(MenuItem mi:menuItems){ + menuItemRepository.save(mi); + } + + MenuRestaurant m1 = new MenuRestaurant(); + m1.setId("M1"); + m1.setName("Italliano"); + m1.setContent("Menú completo: ensalada, macarrones y tiramisú"); + m1.setPrice(25.50); + m1.setActive(true); + m1.setWater(true); + m1.setItems(menuItems); + + menuRepository.save(m1); + + Optional m1Found = menuRepository.findById("M1"); + + assertThat(m1Found).isPresent(); + MenuRestaurant m1DB = m1Found.get(); + assertThat(m1DB.getId().equals(m1.getId())).isEqualTo(true); + assertThat(m1DB.getItems().size() == menuItems.size()).isEqualTo(true); + assertThat(m1DB.getItems().get(0).equals(menuItems.get(0))).isEqualTo(true); + } + + @Test + public void relationshipMenuItemsToMenuBidirectionalTest() { + + List menuItems = createFakeMenuItems(); + + for(MenuItem mi:menuItems){ + menuItemRepository.save(mi); + } + + MenuRestaurant m1 = new MenuRestaurant(); + m1.setId("M1"); + m1.setName("Italliano"); + m1.setContent("Menú completo: ensalada, macarrones y tiramisú"); + m1.setPrice(25.50); + m1.setActive(true); + m1.setWater(true); + // setting relationship in MenuItems + m1.addMenuItems(menuItems); + + menuRepository.save(m1); + + // save relationship + for(MenuItem mi:menuItems){ + mi.addMenus(Arrays.asList(m1)); + menuItemRepository.save(mi); + } + + + Optional mi1Found = menuItemRepository.findById(menuItems.get(0).getId()); + + assertThat(mi1Found).isPresent(); + MenuItem mi1DB = mi1Found.get(); + MenuItem mi1Memory = menuItems.get(0); + assertThat(mi1DB.getId().equals(mi1Memory.getId())).isEqualTo(true); + + List menus = mi1DB.getMenus(); + MenuRestaurant m1DB = menus == null ? null: menus.getFirst(); + + assertThat(m1DB.getItems().size() == m1.getItems().size()).isEqualTo(true); + assertThat(m1DB.getItems().get(0).equals(m1.getItems().get(0))).isEqualTo(true); + + + } + + @Test + public void removeRelationshipMenuItemsToMenuTest() { + + List menuItems = createFakeMenuItems(); + + for(MenuItem mi:menuItems){ + menuItemRepository.save(mi); + } + + MenuRestaurant m1 = new MenuRestaurant(); + m1.setId("M1"); + m1.setName("Italliano"); + m1.setContent("Menú completo: ensalada, macarrones y tiramisú"); + m1.setPrice(25.50); + m1.setActive(true); + m1.setWater(true); + // setting relationship in MenuItems + m1.addMenuItems(menuItems); + + menuRepository.save(m1); + + Optional menuFound = menuRepository.findById("M1"); + assertThat(menuFound).isPresent(); + MenuRestaurant m1DB = menuFound.get(); + // check that all menuItems are in DB + assertThat(m1DB.getItems().size()==menuItems.size()).isEqualTo(true); + + // now we delete menuItems + m1DB.removeMenuItems(menuItems); + menuRepository.save(m1DB); + + Optional menuFound2 = menuRepository.findById("M1"); + assertThat(menuFound2).isPresent(); + MenuRestaurant m2DB = menuFound2.get(); + // check that no menuItem is in DB + assertThat(m1DB.getItems().size()==0).isEqualTo(true); + + } +} \ No newline at end of file diff --git a/src/test/java/dev/example/restaurantManager/RelationshipsOrderRestaurantTest.java b/src/test/java/dev/example/restaurantManager/RelationshipsOrderRestaurantTest.java index a3c8f84..ea9a278 100644 --- a/src/test/java/dev/example/restaurantManager/RelationshipsOrderRestaurantTest.java +++ b/src/test/java/dev/example/restaurantManager/RelationshipsOrderRestaurantTest.java @@ -8,10 +8,9 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.Optional; + +import java.util.*; + import static org.assertj.core.api.Assertions.assertThat; @DataJpaTest @@ -171,6 +170,10 @@ public void TestCreateOrderMenu_stackOverflow () { //orderRestaurantRepository.save(orderRestaurant3); // set menus to orders and save + List orders = menuRestaurant1.getOrders(); + if( orders == null){ + menuRestaurant1.setOrders(new ArrayList<>()); + } menuRestaurant1.getOrders().add(orderRestaurant1); menuRestaurantRepository.save(menuRestaurant1);