diff --git a/src/main/java/io/zipcoder/persistenceapp/controllers/DepartmentController.java b/src/main/java/io/zipcoder/persistenceapp/controllers/DepartmentController.java new file mode 100644 index 0000000..c27f891 --- /dev/null +++ b/src/main/java/io/zipcoder/persistenceapp/controllers/DepartmentController.java @@ -0,0 +1,53 @@ +package io.zipcoder.persistenceapp.controllers; + +import io.zipcoder.persistenceapp.entities.Department; +import io.zipcoder.persistenceapp.services.DepartmentService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +@Controller +public class DepartmentController { + + @Autowired + DepartmentService departmentService; + + @PutMapping("/departments/{id}") + public ResponseEntity updateDepartment (@RequestBody Department department) { + return new ResponseEntity(departmentService.updateDepartment(department), HttpStatus.OK); + } + + @PostMapping("/departments") + public ResponseEntity addDepartment (@RequestBody Department department) { + return new ResponseEntity(departmentService.createDepartment(department), HttpStatus.CREATED); + } + + @GetMapping("/departments/{id}") + public ResponseEntity getDepartment (@PathVariable Integer id) { + return new ResponseEntity(departmentService.getDepartment(id), HttpStatus.OK); + } + + @PostMapping("/departments/{id}-{managerId}") + public ResponseEntity setManager (@PathVariable int id, @PathVariable int managerId) { + Department response = departmentService.setManager(id,managerId); + if (response != null) { + return new ResponseEntity(response, HttpStatus.OK); + } else { + return new ResponseEntity(HttpStatus.BAD_REQUEST); + } + + } + + @PutMapping("/merge/{deptAId}-{deotBId}") + public ResponseEntity mergeDepartments (@PathVariable int deptAId, @PathVariable int deptBId) { + Department response = departmentService.mergeDepartments(deptAId, deptBId); + if (response != null) { + return new ResponseEntity(response, HttpStatus.OK); + } else { + return new ResponseEntity(HttpStatus.BAD_REQUEST); + } + + } +} diff --git a/src/main/java/io/zipcoder/persistenceapp/controllers/EmployeeController.java b/src/main/java/io/zipcoder/persistenceapp/controllers/EmployeeController.java new file mode 100644 index 0000000..98d8247 --- /dev/null +++ b/src/main/java/io/zipcoder/persistenceapp/controllers/EmployeeController.java @@ -0,0 +1,94 @@ +package io.zipcoder.persistenceapp.controllers; + +import io.zipcoder.persistenceapp.entities.Employee; +import io.zipcoder.persistenceapp.services.EmployeeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Controller +public class EmployeeController { + + @Autowired + EmployeeService employeeService; + + @GetMapping("/employees") + public ResponseEntity> getAllEmployees () { + return new ResponseEntity>(employeeService.getAllEmployees(), HttpStatus.OK); + } + + @GetMapping("/employees/{id}") + public ResponseEntity getEmployee (@PathVariable Integer id) { + return new ResponseEntity(employeeService.getEmployee(id), HttpStatus.OK); + } + + @PutMapping("/employees/{id}") + public ResponseEntity updateEmployee (@RequestBody Employee employee) { + return new ResponseEntity(employeeService.updateEmployee(employee), HttpStatus.OK); + } + + @PostMapping("/employees") + public ResponseEntity addEmployee (@RequestBody Employee employee) { + return new ResponseEntity(employeeService.createEmployee(employee), HttpStatus.CREATED); + } + + @DeleteMapping("/employees/{id}") + public ResponseEntity deleteEmployee (@PathVariable Integer id) { + employeeService.deleteEmployee(id); + return new ResponseEntity(HttpStatus.OK); + } + + @DeleteMapping("/employees") + public ResponseEntity deleteEmployees (@RequestBody List employees) { + employeeService.deleteEmployees(employees); + return new ResponseEntity(HttpStatus.OK); + } + + @DeleteMapping("/employees/deptPurge/{deptId}") + public ResponseEntity deleteEmployeesFromDepartment (@PathVariable int deptId) { + employeeService.deleteEmployeesFromDepartment(deptId); + return new ResponseEntity(HttpStatus.OK); + } + + @DeleteMapping("/employees/managerPurge/{managerId}") + public ResponseEntity deleteEmployeesManagedByRecursive (@PathVariable int managerId) { + employeeService.deleteEmployeesManagedByRecursive(managerId); + return new ResponseEntity(HttpStatus.OK); + } + + @DeleteMapping("/employees/managerRemap/{managerId}") + public ResponseEntity deleteEmployeesManagedByRemap (@PathVariable int managerId) { + employeeService.deleteEmployeesManagedByRemap(managerId); + return new ResponseEntity(HttpStatus.OK); + } + + @PostMapping("/employees/{id}-{managerId}") + public ResponseEntity setManager (@PathVariable int id, @PathVariable int managerId) { + return new ResponseEntity(employeeService.setManager(id,managerId), HttpStatus.OK); + } + + @GetMapping("/employees/managed/{managerId}") + public ResponseEntity> getEmployeesManagedBy (@PathVariable int managerId) { + return new ResponseEntity>(employeeService.getEmployeesManagedBy(managerId), HttpStatus.OK); + } + + @GetMapping("/employees/dept/{deptId}") + public ResponseEntity> getEmployeesOfDepartment (@PathVariable int deptId) { + return new ResponseEntity>(employeeService.getEmployeesOfDepartment(deptId), HttpStatus.OK); + } + + @GetMapping("/employees/nomgr") + public ResponseEntity> getEmployeesNoManager () { + return new ResponseEntity>(employeeService.getEmployeesNoManager(), HttpStatus.OK); + } + + @GetMapping("/employees/mgrtree/{id}") + public ResponseEntity> getManagerTree (@PathVariable int id) { + return new ResponseEntity>(employeeService.getManagerTree(id), HttpStatus.OK); + } + +} diff --git a/src/main/java/io/zipcoder/persistenceapp/entities/Department.java b/src/main/java/io/zipcoder/persistenceapp/entities/Department.java new file mode 100644 index 0000000..5b287d1 --- /dev/null +++ b/src/main/java/io/zipcoder/persistenceapp/entities/Department.java @@ -0,0 +1,38 @@ +package io.zipcoder.persistenceapp.entities; + +import javax.persistence.*; + +@Entity +public class Department { + + @Id + @GeneratedValue + private int id; + private String name; + @ManyToOne + private Employee manager; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Employee getManager() { + return manager; + } + + public void setManager(Employee manager) { + this.manager = manager; + } +} diff --git a/src/main/java/io/zipcoder/persistenceapp/entities/Employee.java b/src/main/java/io/zipcoder/persistenceapp/entities/Employee.java new file mode 100644 index 0000000..a064b83 --- /dev/null +++ b/src/main/java/io/zipcoder/persistenceapp/entities/Employee.java @@ -0,0 +1,99 @@ +package io.zipcoder.persistenceapp.entities; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import javax.persistence.*; + +@Entity +@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) +public class Employee { + + @Id + @GeneratedValue + private Integer id; + private String firstName; + private String lastName; + private String title; + private String phoneNumber; + private String email; + @ManyToOne(fetch = FetchType.LAZY) + private Employee manager; + //@ManyToOne(fetch = FetchType.LAZY) + private Integer departmentNum; + + public Employee() { + } + + public Employee(String firstName, String lastName, String title, String phoneNumber, String email) { + this.firstName = firstName; + this.lastName = lastName; + this.title = title; + this.phoneNumber = phoneNumber; + this.email = email; + } + + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Employee getManager() { + return manager; + } + + public void setManager(Employee manager) { + this.manager = manager; + } + + public Integer getDepartmentNum() { + return departmentNum; + } + + public void setDepartmentNum(Integer departmentNum) { + this.departmentNum = departmentNum; + } +} diff --git a/src/main/java/io/zipcoder/persistenceapp/repositories/DepartmentRepository.java b/src/main/java/io/zipcoder/persistenceapp/repositories/DepartmentRepository.java new file mode 100644 index 0000000..98192cc --- /dev/null +++ b/src/main/java/io/zipcoder/persistenceapp/repositories/DepartmentRepository.java @@ -0,0 +1,9 @@ +package io.zipcoder.persistenceapp.repositories; + +import io.zipcoder.persistenceapp.entities.Department; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface DepartmentRepository extends CrudRepository { +} diff --git a/src/main/java/io/zipcoder/persistenceapp/repositories/EmployeeRepository.java b/src/main/java/io/zipcoder/persistenceapp/repositories/EmployeeRepository.java new file mode 100644 index 0000000..4a6d9dc --- /dev/null +++ b/src/main/java/io/zipcoder/persistenceapp/repositories/EmployeeRepository.java @@ -0,0 +1,21 @@ +package io.zipcoder.persistenceapp.repositories; + +import io.zipcoder.persistenceapp.entities.Employee; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface EmployeeRepository extends CrudRepository { + + List findEmployeeByManagerId(int managerId); + + List findEmployeeByDepartmentNum(int departmentId); + + List findEmployeeByManagerIsNull(); + + void deleteEmployeesByDepartmentNum(int departmentId); + + void deleteEmployeesByManagerIn(Iterable managers); +} diff --git a/src/main/java/io/zipcoder/persistenceapp/services/DepartmentService.java b/src/main/java/io/zipcoder/persistenceapp/services/DepartmentService.java new file mode 100644 index 0000000..1bc12f7 --- /dev/null +++ b/src/main/java/io/zipcoder/persistenceapp/services/DepartmentService.java @@ -0,0 +1,59 @@ +package io.zipcoder.persistenceapp.services; + +import io.zipcoder.persistenceapp.entities.Department; +import io.zipcoder.persistenceapp.entities.Department; +import io.zipcoder.persistenceapp.entities.Department; +import io.zipcoder.persistenceapp.entities.Employee; +import io.zipcoder.persistenceapp.repositories.DepartmentRepository; +import io.zipcoder.persistenceapp.repositories.EmployeeRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class DepartmentService { + + @Autowired + DepartmentRepository departmentRepository; + + @Autowired + EmployeeService employeeService; + + public Department createDepartment(Department department) { + return departmentRepository.save(department); + } + public Department updateDepartment(Department department) { + return departmentRepository.save(department); + } + + public Department getDepartment(Integer id) { + return departmentRepository.findOne(id); + } + + public Department setManager(int id, int managerId) { + Department department = getDepartment(id); + Employee manager = employeeService.getEmployee(managerId); + if (department != null && manager != null) { + department.setManager(manager); + return departmentRepository.save(department); + } else { + return null; + } + } + + public Department mergeDepartments(int deptAId, int deptBId) { + Department departmentA = getDepartment(deptAId); + Department departmentB = getDepartment(deptBId); + if (departmentA != null && departmentB != null) { + departmentB.getManager().setDepartmentNum(deptAId); // move mgr + for (Employee e : employeeService.getEmployeesOfDepartment(deptBId)) { + e.setDepartmentNum(deptAId); // move the others + } + departmentRepository.delete(departmentB); + return departmentA; + } else { + return null; + } + + + } +} diff --git a/src/main/java/io/zipcoder/persistenceapp/services/EmployeeService.java b/src/main/java/io/zipcoder/persistenceapp/services/EmployeeService.java new file mode 100644 index 0000000..d1bba18 --- /dev/null +++ b/src/main/java/io/zipcoder/persistenceapp/services/EmployeeService.java @@ -0,0 +1,114 @@ +package io.zipcoder.persistenceapp.services; + +import io.zipcoder.persistenceapp.entities.Employee; +import io.zipcoder.persistenceapp.repositories.EmployeeRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + +@Service +public class EmployeeService { + + @Autowired + EmployeeRepository employeeRepository; + + public Iterable getAllEmployees() { + return employeeRepository.findAll(); + } + + public Employee getEmployee(Integer id) { + return employeeRepository.findOne(id); + } + + public Employee createEmployee(Employee employee) { + return employeeRepository.save(employee); + } + + public void deleteEmployee(Integer id) { + employeeRepository.delete(id); + } + + public void deleteEmployees(List employees) { + employeeRepository.delete(employees); + } + + public void deleteEmployeesFromDepartment(int deptId) { + employeeRepository.deleteEmployeesByDepartmentNum(deptId); + } + + public void deleteEmployeesManagedByRecursive(int managerId) { + Employee manager = getEmployee(managerId); + if (manager != null) { + List toBeDeleted = new ArrayList((List) getEmployeesManagedBy(managerId)); + while (toBeDeleted.size() > 0) { + List nextBatch = new ArrayList<>(); + for (Employee e: toBeDeleted) { + nextBatch.addAll((List) getEmployeesManagedBy(e.getId())); + nextBatch.stream().forEach(em -> em.setManager(null)); + employeeRepository.delete(e); + } + toBeDeleted.clear(); + toBeDeleted.addAll(nextBatch); + } + } + } + + public void deleteEmployeesManagedByRemap(int managerId) { + Employee manager = getEmployee(managerId); + + if (manager != null) { + Employee nextManager = manager.getManager(); // remap employees to this manager + Iterable employees = getEmployeesManagedBy(managerId); + + for (Employee e: employees) { // loop through, remapping them + for (Employee ee : employeeRepository.findEmployeeByManagerId(e.getId())) { + ee.setManager(nextManager); + } + deleteEmployee(e.getId()); + } + deleteEmployee(managerId); + } + } + + public Employee setManager(int id, int managerId) { + Employee employee = getEmployee(id); + Employee manager = getEmployee(managerId); + if (employee != null && manager != null) { + employee.setManager(manager); + return employeeRepository.save(employee); + } else { + return null; + } + } + + public Employee updateEmployee(Employee employee) { + return employeeRepository.save(employee); + } + + public Iterable getEmployeesManagedBy (int managerId) { + return employeeRepository.findEmployeeByManagerId(managerId); + } + + public Iterable getEmployeesOfDepartment (int deptId) { + return employeeRepository.findEmployeeByDepartmentNum(deptId); + } + + public Iterable getEmployeesNoManager () { + return employeeRepository.findEmployeeByManagerIsNull(); + } + + public Iterable getManagerTree(int employeeId) { + Employee employee = getEmployee(employeeId); + List managers = new ArrayList<>(); + Employee current = employee; + while (current.getManager() != null) { + current = current.getManager(); + managers.add(current); + } + return managers; + } +} diff --git a/src/main/resources/application-h2.properties b/src/main/resources/application-h2.properties index 74765cc..bb80899 100644 --- a/src/main/resources/application-h2.properties +++ b/src/main/resources/application-h2.properties @@ -1,4 +1,4 @@ spring.datasource.url=jdbc:h2:mem:testdb;Mode=Oracle spring.datasource.platform=h2 -spring.jpa.hibernate.ddl-auto=none -spring.datasource.continue-on-error=true \ No newline at end of file +spring.jpa.hibernate.ddl-auto=create +spring.datasource.continue-on-error=true diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..6310363 --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1 @@ +INSERT INTO Employee (id, firstName, lastName, title, phoneNumber, email) VALUES (1, "Jim", "Dandy", "Leader", "12345", "aol.com@aol.com"); diff --git a/src/test/java/io/zipcoder/services/EmployeeServiceTest.java b/src/test/java/io/zipcoder/services/EmployeeServiceTest.java new file mode 100644 index 0000000..cd44e33 --- /dev/null +++ b/src/test/java/io/zipcoder/services/EmployeeServiceTest.java @@ -0,0 +1,130 @@ +package io.zipcoder.services; + +import io.zipcoder.persistenceapp.entities.Employee; +import io.zipcoder.persistenceapp.repositories.EmployeeRepository; +import io.zipcoder.persistenceapp.services.EmployeeService; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import java.util.Arrays; +import java.util.List; +import static org.mockito.Mockito.*; + + +@RunWith(MockitoJUnitRunner.class) +public class EmployeeServiceTest { + + @Mock + private EmployeeRepository employeeRepository; + + @InjectMocks + private EmployeeService employeeService; + + @Before + public void setUp() throws Exception { + } + + @Test + public void getAllEmployees() { + when(employeeService.getAllEmployees()).thenReturn(stubEmployees()); + employeeService.getAllEmployees(); + verify(employeeRepository, times(1)).findAll(); + } + + private List stubEmployees() { + Employee e1 = new Employee("Kesha", "Johns", "Poobah", "12345678", "jim@aol.com"); + Employee e2 = new Employee("Kathleen", "Johns2", "Grunt", "87654321", "joe@aol.com"); + e1.setId(3); + e2.setId(5); + return Arrays.asList(e1,e2); + } + + @Test + public void getEmployee() { + when(employeeService.getEmployee(5)).thenReturn(stubEmployees().get(1)); + employeeService.getEmployee(5); + verify(employeeRepository, times(1)).findOne(5); + } + + @Test + public void createEmployee() { + Employee expected = new Employee("Kesha", "Beale", "Writer", "2153002744", "bouncyslim@aol.com"); + doReturn(expected).when(employeeRepository).save(any(Employee.class)); + Employee actual = employeeService.createEmployee(expected); + Assert.assertEquals(expected.toString(), actual.toString()); + } + + @Test + public void createEmployeeNoReturn() { + Employee expected = new Employee("Kesha", "Beale", "Writer", "2153002744", "bouncyslim@aol.com"); + doReturn(expected).when(employeeRepository).save(any(Employee.class)); + employeeService.createEmployee(expected); + ArgumentCaptor captor = ArgumentCaptor.forClass(Employee.class); + verify(employeeRepository, times(1)).save(captor.capture()); + Assert.assertEquals(expected.toString(), captor.getValue().toString()); + } + + @Test + public void setManager() { + Employee e = new Employee("Kesha", "Beale", "Analyst", "2153002744", "bouncyslim@aol.com"); + Employee m = new Employee("Kathleen", "Beale", "Admin", "2158330303", "bealek@hotmail.com"); + e.setId(3); + m.setId(7); + doReturn(e).when(employeeRepository).findOne(3); + doReturn(m).when(employeeRepository).findOne(7); + employeeService.setManager(3,7); + ArgumentCaptor captor = ArgumentCaptor.forClass(Employee.class); + verify(employeeRepository, times(1)).save(captor.capture()); + Assert.assertEquals(m, captor.getValue().getManager()); + } + + @Test + public void setManagerNullE() { + Employee e = new Employee("Kesha", "Beale", "Analyst", "2153002744", "bouncyslim@aol.com"); + Employee m = new Employee("Kathleen", "Beale", "Admin", "2158330303", "bealek@hotmail.com"); + e.setId(4); + m.setId(7); + doReturn(e).when(employeeRepository).findOne(4); + doReturn(m).when(employeeRepository).findOne(7); + employeeService.setManager(3,7); + verify(employeeRepository, times(0)).save(e); + Assert.assertNull(employeeService.setManager(3,7)); + } + + @Test + public void updateEmployee() { + Employee e = new Employee("Kesha", "Beale", "Analyst", "2153002744", "bouncyslim@aol.com"); + employeeService.updateEmployee(e); + verify(employeeRepository, times(1)).save(e); + } + + @Test + public void getEmployeesManagedBy () { + when(employeeService.getEmployeesManagedBy(7)).thenReturn(stubEmployees()); + employeeService.getEmployeesManagedBy(7); + verify(employeeRepository, times(1)).findEmployeeByManagerId(7); + } + + @Test + public void getEmployeesOfDepartment () { + when(employeeService.getEmployeesOfDepartment(7)).thenReturn(stubEmployees()); + employeeService.getEmployeesOfDepartment(7); + verify(employeeRepository, times(1)).findEmployeeByDepartmentNum(7); + } + + @Test + public void getEmployeesNoManager () { + when(employeeService.getEmployeesNoManager()).thenReturn(stubEmployees()); + employeeService.getEmployeesNoManager(); + verify(employeeRepository, times(1)).findEmployeeByManagerIsNull(); + } + + + + +}