From f2e736adbebfbccc8120549e20119f0bbe6268ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20D=C3=ADaz=20Ochoa?= Date: Wed, 8 Mar 2023 17:42:51 -0600 Subject: [PATCH 1/2] FEATURE: Add endpoints for top employees and employee by ID. --- README.md | 3 + pom.xml | 54 +++++++++++ .../advice/EmployeeNotFoundAdvice.java | 19 ++++ .../config/SwaggerConfig.java | 38 ++++++++ .../controller/OrganizationController.java | 45 ++++++++++ .../candidatechallenge/dto/EmployeeDTO.java | 56 ++++++++++++ .../candidatechallenge/dto/PropertyDTO.java | 29 ++++++ .../exception/EmployeeNotFoundException.java | 7 ++ .../mapper/EmployeeMapper.java | 19 ++++ .../mapper/PropertyMapper.java | 18 ++++ .../candidatechallenge/model/Employee.java | 58 ++++++++++++ .../candidatechallenge/model/Property.java | 43 +++++++++ .../repository/EmployeeRepository.java | 17 ++++ .../service/OrganizationService.java | 33 +++++++ src/main/resources/application.yml | 2 + .../OrganizationControllerTest.java | 40 +++++++++ .../service/OrganizationServiceTest.java | 90 +++++++++++++++++++ 17 files changed, 571 insertions(+) create mode 100644 src/main/java/com/zoomcare/candidatechallenge/advice/EmployeeNotFoundAdvice.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/config/SwaggerConfig.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/controller/OrganizationController.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/dto/EmployeeDTO.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/dto/PropertyDTO.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/exception/EmployeeNotFoundException.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/mapper/EmployeeMapper.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/mapper/PropertyMapper.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/model/Employee.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/model/Property.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/repository/EmployeeRepository.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/service/OrganizationService.java create mode 100644 src/test/java/com/zoomcare/candidatechallenge/controller/OrganizationControllerTest.java create mode 100644 src/test/java/com/zoomcare/candidatechallenge/service/OrganizationServiceTest.java diff --git a/README.md b/README.md index be35613..88763d9 100644 --- a/README.md +++ b/README.md @@ -49,3 +49,6 @@ A map of key/value pairs of properties assigned to an employee. 1. Create a Fork of the repository into your personal GitHub space. 2. Implement the feature as described above. 3. Create a Pull Request back to the original project. + +## Swagger docs +The swagger documentation is in [http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html) diff --git a/pom.xml b/pom.xml index 17fd7ad..bc87547 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,7 @@ 1.8 + 1.5.3.Final @@ -23,6 +24,10 @@ org.springframework.boot spring-boot-starter-actuator + + org.springframework.boot + spring-boot-starter-data-jpa + org.springframework.boot spring-boot-starter-data-jdbc @@ -31,6 +36,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-devtools + org.flywaydb @@ -38,6 +47,12 @@ runtime + + org.mapstruct + mapstruct + ${org.mapstruct.version} + + com.h2database h2 @@ -49,6 +64,28 @@ spring-boot-starter-test test + + + junit + junit + + + + org.mockito + mockito-core + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + + io.springfox + springfox-swagger-ui + 2.9.2 + @@ -57,6 +94,23 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + + + diff --git a/src/main/java/com/zoomcare/candidatechallenge/advice/EmployeeNotFoundAdvice.java b/src/main/java/com/zoomcare/candidatechallenge/advice/EmployeeNotFoundAdvice.java new file mode 100644 index 0000000..00017de --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/advice/EmployeeNotFoundAdvice.java @@ -0,0 +1,19 @@ +package com.zoomcare.candidatechallenge.advice; + +import com.zoomcare.candidatechallenge.exception.EmployeeNotFoundException; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ControllerAdvice +public class EmployeeNotFoundAdvice { + + @ResponseBody + @ExceptionHandler(EmployeeNotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + String employeeNotFoundHandler(EmployeeNotFoundException ex){ + return ex.getMessage(); + } +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/config/SwaggerConfig.java b/src/main/java/com/zoomcare/candidatechallenge/config/SwaggerConfig.java new file mode 100644 index 0000000..33f3b23 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/config/SwaggerConfig.java @@ -0,0 +1,38 @@ +package com.zoomcare.candidatechallenge.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +import java.util.Collections; + +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + + @Bean + public Docket apiDocket() { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .apis(RequestHandlerSelectors.basePackage("com.zoomcare.candidatechallenge.controller")) + .paths(PathSelectors.any()) + .build() + .apiInfo(getApiInfo()); + } + + private ApiInfo getApiInfo() { + return new ApiInfo("ZOOM CARE Code Challenge", + "Organization API Description", + "1.0", + null, + null, + "LICENSE", + "", + Collections.emptyList()); + } +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/controller/OrganizationController.java b/src/main/java/com/zoomcare/candidatechallenge/controller/OrganizationController.java new file mode 100644 index 0000000..4c0d181 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/controller/OrganizationController.java @@ -0,0 +1,45 @@ +package com.zoomcare.candidatechallenge.controller; + +import com.zoomcare.candidatechallenge.dto.EmployeeDTO; +import com.zoomcare.candidatechallenge.exception.EmployeeNotFoundException; +import com.zoomcare.candidatechallenge.service.OrganizationService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * Organization Endpoint + */ +@RestController +@RequestMapping("/api/v1/organization") +public class OrganizationController { + + private final OrganizationService organizationService; + + public OrganizationController(OrganizationService organizationService) { + this.organizationService = organizationService; + } + + /** + * Obtain the top-level employees + * @return + */ + @GetMapping("top") + List getAllTopLevelsEmployees(){ + return organizationService.getAllTopLevelsEmployees(); + } + + /** + * Obtain employee by ID + * @param id the employee Identifieer + * @return the employee information requested. + */ + @GetMapping("/{id}") + EmployeeDTO getEmployeeById(@PathVariable("id") Long id){ + return organizationService.findById(id) + .orElseThrow(()-> new EmployeeNotFoundException(id)); + } +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/dto/EmployeeDTO.java b/src/main/java/com/zoomcare/candidatechallenge/dto/EmployeeDTO.java new file mode 100644 index 0000000..1752ca5 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/dto/EmployeeDTO.java @@ -0,0 +1,56 @@ +package com.zoomcare.candidatechallenge.dto; + +import java.util.List; +import java.util.Map; + +public class EmployeeDTO { + + private Long id; + private Long supervisorId; + + private List properties; + + private List employees; + + public EmployeeDTO() { + } + + public EmployeeDTO(Long id, Long supervisorId, List properties, List employees) { + this.id = id; + this.supervisorId = supervisorId; + this.properties = properties; + this.employees = employees; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getSupervisorId() { + return supervisorId; + } + + public void setSupervisorId(Long supervisorId) { + this.supervisorId = supervisorId; + } + + public List getEmployees() { + return employees; + } + + public void setEmployees(List employees) { + this.employees = employees; + } + + public List getProperties() { + return properties; + } + + public void setProperties(List properties) { + this.properties = properties; + } +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/dto/PropertyDTO.java b/src/main/java/com/zoomcare/candidatechallenge/dto/PropertyDTO.java new file mode 100644 index 0000000..ac61dd7 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/dto/PropertyDTO.java @@ -0,0 +1,29 @@ +package com.zoomcare.candidatechallenge.dto; + +import java.io.Serializable; + +public class PropertyDTO implements Serializable { + private String key; + private String value; + + public PropertyDTO(String key, String value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/exception/EmployeeNotFoundException.java b/src/main/java/com/zoomcare/candidatechallenge/exception/EmployeeNotFoundException.java new file mode 100644 index 0000000..82e8f36 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/exception/EmployeeNotFoundException.java @@ -0,0 +1,7 @@ +package com.zoomcare.candidatechallenge.exception; + +public class EmployeeNotFoundException extends RuntimeException { + public EmployeeNotFoundException(Long id) { + super("Could not find employee " + id); + } +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/mapper/EmployeeMapper.java b/src/main/java/com/zoomcare/candidatechallenge/mapper/EmployeeMapper.java new file mode 100644 index 0000000..ec16c99 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/mapper/EmployeeMapper.java @@ -0,0 +1,19 @@ +package com.zoomcare.candidatechallenge.mapper; + +import com.zoomcare.candidatechallenge.dto.EmployeeDTO; +import com.zoomcare.candidatechallenge.model.Employee; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface EmployeeMapper { + + EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class); + + EmployeeDTO employeeToEmployeeDTO(Employee employee); + + List map(List employees); + +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/mapper/PropertyMapper.java b/src/main/java/com/zoomcare/candidatechallenge/mapper/PropertyMapper.java new file mode 100644 index 0000000..c705507 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/mapper/PropertyMapper.java @@ -0,0 +1,18 @@ +package com.zoomcare.candidatechallenge.mapper; + +import com.zoomcare.candidatechallenge.dto.PropertyDTO; +import com.zoomcare.candidatechallenge.model.Property; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface PropertyMapper { + + PropertyMapper INSTANCE = Mappers.getMapper(PropertyMapper.class); + + PropertyDTO map(Property property); + + List map(List properties); +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/model/Employee.java b/src/main/java/com/zoomcare/candidatechallenge/model/Employee.java new file mode 100644 index 0000000..9232644 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/model/Employee.java @@ -0,0 +1,58 @@ +package com.zoomcare.candidatechallenge.model; + +import javax.persistence.*; +import java.util.List; + +/** + * Model for Employee table + */ +@Entity +public class Employee { + + @Id + @GeneratedValue + private Long id; + + @Column(name = "supervisor_id") + private Long supervisorId; + + @OneToMany + @JoinColumn(name = "supervisor_id") + private List employees; + + @OneToMany + @JoinColumn(name = "employee_id") + private List properties; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getSupervisorId() { + return supervisorId; + } + + public void setSupervisorId(Long supervisorId) { + this.supervisorId = supervisorId; + } + + public List getProperties() { + return properties; + } + + public void setProperties(List properties) { + this.properties = properties; + } + + public List getEmployees() { + return employees; + } + + public void setEmployees(List employees) { + this.employees = employees; + } +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/model/Property.java b/src/main/java/com/zoomcare/candidatechallenge/model/Property.java new file mode 100644 index 0000000..db847f3 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/model/Property.java @@ -0,0 +1,43 @@ +package com.zoomcare.candidatechallenge.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import java.io.Serializable; + +/** + * Model for Property table + */ +@Entity +public class Property implements Serializable { + + @Id + @GeneratedValue + private Long employee_id; + private String key; + private String value; + + public Long getEmployee_id() { + return employee_id; + } + + public void setEmployee_id(Long employee_id) { + this.employee_id = employee_id; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/repository/EmployeeRepository.java b/src/main/java/com/zoomcare/candidatechallenge/repository/EmployeeRepository.java new file mode 100644 index 0000000..47eae0c --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/repository/EmployeeRepository.java @@ -0,0 +1,17 @@ +package com.zoomcare.candidatechallenge.repository; + +import com.zoomcare.candidatechallenge.model.Employee; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +/** + * Data Access Layer for the Employee information. + */ +@Repository +public interface EmployeeRepository extends JpaRepository { + List findAllBySupervisorIdIsNull(); + Optional findById(Long id); +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/service/OrganizationService.java b/src/main/java/com/zoomcare/candidatechallenge/service/OrganizationService.java new file mode 100644 index 0000000..6c92939 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/service/OrganizationService.java @@ -0,0 +1,33 @@ +package com.zoomcare.candidatechallenge.service; + +import com.zoomcare.candidatechallenge.dto.EmployeeDTO; +import com.zoomcare.candidatechallenge.mapper.EmployeeMapper; +import com.zoomcare.candidatechallenge.repository.EmployeeRepository; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * Handles organization operations + */ +@Service +public class OrganizationService { + + private EmployeeRepository employeeRepository; + + public OrganizationService(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; + } + + public Optional findById(Long id) { + return employeeRepository.findById(id).map(EmployeeMapper.INSTANCE::employeeToEmployeeDTO); + } + + public List getAllTopLevelsEmployees(){ + return employeeRepository.findAllBySupervisorIdIsNull().stream() + .map(EmployeeMapper.INSTANCE::employeeToEmployeeDTO) + .collect(Collectors.toList()); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 4408d17..eff42ca 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,6 +2,8 @@ spring: h2: console: enabled: true + main: + allow-bean-definition-overriding: true management: endpoints: web: diff --git a/src/test/java/com/zoomcare/candidatechallenge/controller/OrganizationControllerTest.java b/src/test/java/com/zoomcare/candidatechallenge/controller/OrganizationControllerTest.java new file mode 100644 index 0000000..188af7f --- /dev/null +++ b/src/test/java/com/zoomcare/candidatechallenge/controller/OrganizationControllerTest.java @@ -0,0 +1,40 @@ +package com.zoomcare.candidatechallenge.controller; + +import com.zoomcare.candidatechallenge.service.OrganizationService; +import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@WebMvcTest(OrganizationController.class) +public class OrganizationControllerTest extends TestCase { + + @MockBean + private OrganizationService organizationService; + + @Autowired + private MockMvc mvc; + + @Test + public void testGetAllTopLevelsEmployees() throws Exception{ + mvc.perform(MockMvcRequestBuilders.get("/api/v1/organization/top")) + .andDo(print()) + .andExpect(status().isOk()); + } + + @Test + public void testGetEmployeeById() throws Exception{ + mvc.perform(MockMvcRequestBuilders.get("/api/v1/organization/2")) + .andDo(print()) + .andExpect(status().is4xxClientError()); + } +} \ No newline at end of file diff --git a/src/test/java/com/zoomcare/candidatechallenge/service/OrganizationServiceTest.java b/src/test/java/com/zoomcare/candidatechallenge/service/OrganizationServiceTest.java new file mode 100644 index 0000000..e06f6b7 --- /dev/null +++ b/src/test/java/com/zoomcare/candidatechallenge/service/OrganizationServiceTest.java @@ -0,0 +1,90 @@ +package com.zoomcare.candidatechallenge.service; + +import com.zoomcare.candidatechallenge.dto.EmployeeDTO; +import com.zoomcare.candidatechallenge.model.Employee; +import com.zoomcare.candidatechallenge.model.Property; +import com.zoomcare.candidatechallenge.repository.EmployeeRepository; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.when; + +public class OrganizationServiceTest { + + @Mock + private EmployeeRepository employeeRepository; + + private OrganizationService organizationService; + + @Before + public void setUp(){ + MockitoAnnotations.initMocks(this); + organizationService = new OrganizationService(employeeRepository); + } + + @Test + public void testFindById(){ + Long employee_id = 99L; + when(employeeRepository.findById(anyLong())).thenReturn(Optional.of(generateEmployee(employee_id))); + + Optional result = organizationService.findById(employee_id); + assertTrue(result.isPresent()); + assertFalse(result.get().getProperties().isEmpty()); + assertEquals(2,result.get().getProperties().size()); + assertEquals("KEY", result.get().getProperties().get(0).getKey()); + assertEquals("KEY2", result.get().getProperties().get(1).getKey()); + assertFalse(result.get().getEmployees().isEmpty()); + assertEquals(1, result.get().getEmployees().size()); + } + + @Test + public void testGetAllTopLevelsEmployees(){ + List employees = Arrays.asList( + generateEmployee(55L), + generateEmployee(66L), + generateEmployee(77L)); + when(employeeRepository.findAllBySupervisorIdIsNull()).thenReturn(employees); + + List employeeDTOs= organizationService.getAllTopLevelsEmployees(); + + assertFalse(employeeDTOs.isEmpty()); + assertEquals(3, employeeDTOs.size() ); + assertEquals(55L, employeeDTOs.get(0).getId().longValue() ); + assertEquals(66L, employeeDTOs.get(1).getId().longValue() ); + assertEquals(77L, employeeDTOs.get(2).getId().longValue() ); + } + + private Employee generateEmployee(Long employee_id){ + Employee employee = new Employee(); + employee.setId(employee_id); + List properties = new ArrayList<>(); + Property property = new Property(); + property.setEmployee_id(employee_id); + property.setKey("KEY"); + property.setValue("VALUE"); + properties.add(property); + + Property property2 = new Property(); + property2.setEmployee_id(employee_id); + property2.setKey("KEY2"); + property2.setValue("VALUE2"); + properties.add(property2); + + employee.setProperties(properties); + + List employees = new ArrayList<>(); + employees.add(new Employee()); + employee.setEmployees(employees); + + return employee; + } +} \ No newline at end of file From d93a10994798937f57a58ded5913070239e78496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20D=C3=ADaz=20Ochoa?= Date: Thu, 9 Mar 2023 10:26:17 -0600 Subject: [PATCH 2/2] FEATURE: add composite key for property table --- pom.xml | 24 -------------- .../mapper/EmployeeMapper.java | 19 ----------- .../mapper/PropertyMapper.java | 18 ---------- .../model/EntityPropertyPk.java | 33 +++++++++++++++++++ .../candidatechallenge/model/Property.java | 23 ++++--------- .../service/OrganizationService.java | 30 +++++++++++++++-- .../service/OrganizationServiceTest.java | 13 +++++--- 7 files changed, 76 insertions(+), 84 deletions(-) delete mode 100644 src/main/java/com/zoomcare/candidatechallenge/mapper/EmployeeMapper.java delete mode 100644 src/main/java/com/zoomcare/candidatechallenge/mapper/PropertyMapper.java create mode 100644 src/main/java/com/zoomcare/candidatechallenge/model/EntityPropertyPk.java diff --git a/pom.xml b/pom.xml index bc87547..00c67ea 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,6 @@ 1.8 - 1.5.3.Final @@ -47,12 +46,6 @@ runtime - - org.mapstruct - mapstruct - ${org.mapstruct.version} - - com.h2database h2 @@ -94,23 +87,6 @@ org.springframework.boot spring-boot-maven-plugin - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - 1.8 - 1.8 - - - org.mapstruct - mapstruct-processor - ${org.mapstruct.version} - - - - - diff --git a/src/main/java/com/zoomcare/candidatechallenge/mapper/EmployeeMapper.java b/src/main/java/com/zoomcare/candidatechallenge/mapper/EmployeeMapper.java deleted file mode 100644 index ec16c99..0000000 --- a/src/main/java/com/zoomcare/candidatechallenge/mapper/EmployeeMapper.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.zoomcare.candidatechallenge.mapper; - -import com.zoomcare.candidatechallenge.dto.EmployeeDTO; -import com.zoomcare.candidatechallenge.model.Employee; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -import java.util.List; - -@Mapper -public interface EmployeeMapper { - - EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class); - - EmployeeDTO employeeToEmployeeDTO(Employee employee); - - List map(List employees); - -} diff --git a/src/main/java/com/zoomcare/candidatechallenge/mapper/PropertyMapper.java b/src/main/java/com/zoomcare/candidatechallenge/mapper/PropertyMapper.java deleted file mode 100644 index c705507..0000000 --- a/src/main/java/com/zoomcare/candidatechallenge/mapper/PropertyMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.zoomcare.candidatechallenge.mapper; - -import com.zoomcare.candidatechallenge.dto.PropertyDTO; -import com.zoomcare.candidatechallenge.model.Property; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -import java.util.List; - -@Mapper -public interface PropertyMapper { - - PropertyMapper INSTANCE = Mappers.getMapper(PropertyMapper.class); - - PropertyDTO map(Property property); - - List map(List properties); -} diff --git a/src/main/java/com/zoomcare/candidatechallenge/model/EntityPropertyPk.java b/src/main/java/com/zoomcare/candidatechallenge/model/EntityPropertyPk.java new file mode 100644 index 0000000..14b4948 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/model/EntityPropertyPk.java @@ -0,0 +1,33 @@ +package com.zoomcare.candidatechallenge.model; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import java.io.Serializable; + +@Embeddable +public class EntityPropertyPk implements Serializable { + @Column(name = "key") + private String key; + + @ManyToOne + @JoinColumn(name = "employee_id") + private Employee employee; + + public Employee getEmployee() { + return employee; + } + + public void setEmployee(Employee employee) { + this.employee = employee; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/model/Property.java b/src/main/java/com/zoomcare/candidatechallenge/model/Property.java index db847f3..344225a 100644 --- a/src/main/java/com/zoomcare/candidatechallenge/model/Property.java +++ b/src/main/java/com/zoomcare/candidatechallenge/model/Property.java @@ -1,5 +1,6 @@ package com.zoomcare.candidatechallenge.model; +import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @@ -11,26 +12,16 @@ @Entity public class Property implements Serializable { - @Id - @GeneratedValue - private Long employee_id; - private String key; + @EmbeddedId + private EntityPropertyPk id; private String value; - public Long getEmployee_id() { - return employee_id; + public EntityPropertyPk getId() { + return id; } - public void setEmployee_id(Long employee_id) { - this.employee_id = employee_id; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; + public void setId(EntityPropertyPk id) { + this.id = id; } public String getValue() { diff --git a/src/main/java/com/zoomcare/candidatechallenge/service/OrganizationService.java b/src/main/java/com/zoomcare/candidatechallenge/service/OrganizationService.java index 6c92939..ff7b5a2 100644 --- a/src/main/java/com/zoomcare/candidatechallenge/service/OrganizationService.java +++ b/src/main/java/com/zoomcare/candidatechallenge/service/OrganizationService.java @@ -1,10 +1,14 @@ package com.zoomcare.candidatechallenge.service; import com.zoomcare.candidatechallenge.dto.EmployeeDTO; -import com.zoomcare.candidatechallenge.mapper.EmployeeMapper; +import com.zoomcare.candidatechallenge.dto.PropertyDTO; +import com.zoomcare.candidatechallenge.model.Employee; +import com.zoomcare.candidatechallenge.model.Property; import com.zoomcare.candidatechallenge.repository.EmployeeRepository; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -22,12 +26,32 @@ public OrganizationService(EmployeeRepository employeeRepository) { } public Optional findById(Long id) { - return employeeRepository.findById(id).map(EmployeeMapper.INSTANCE::employeeToEmployeeDTO); + return employeeRepository.findById(id).map(this::employeeToEmployeeDTO); } public List getAllTopLevelsEmployees(){ return employeeRepository.findAllBySupervisorIdIsNull().stream() - .map(EmployeeMapper.INSTANCE::employeeToEmployeeDTO) + .map(this::employeeToEmployeeDTO) .collect(Collectors.toList()); } + + private EmployeeDTO employeeToEmployeeDTO(Employee employee){ + EmployeeDTO dto = new EmployeeDTO(); + dto.setId(employee.getId()); + dto.setSupervisorId(employee.getSupervisorId()); + if(!CollectionUtils.isEmpty(employee.getEmployees())){ + dto.setEmployees(employee.getEmployees().stream().map(this::employeeToEmployeeDTO).collect(Collectors.toList())); + } else { + dto.setEmployees(Collections.emptyList()); + } + if(!CollectionUtils.isEmpty(employee.getProperties())){ + dto.setProperties(employee.getProperties().stream().map(this::mapProperty).collect(Collectors.toList())); + } else { + dto.setProperties(Collections.emptyList()); + } + return dto; + } + private PropertyDTO mapProperty(Property property){ + return new PropertyDTO(property.getId().getKey(), property.getValue()); + } } diff --git a/src/test/java/com/zoomcare/candidatechallenge/service/OrganizationServiceTest.java b/src/test/java/com/zoomcare/candidatechallenge/service/OrganizationServiceTest.java index e06f6b7..934bfa5 100644 --- a/src/test/java/com/zoomcare/candidatechallenge/service/OrganizationServiceTest.java +++ b/src/test/java/com/zoomcare/candidatechallenge/service/OrganizationServiceTest.java @@ -2,6 +2,7 @@ import com.zoomcare.candidatechallenge.dto.EmployeeDTO; import com.zoomcare.candidatechallenge.model.Employee; +import com.zoomcare.candidatechallenge.model.EntityPropertyPk; import com.zoomcare.candidatechallenge.model.Property; import com.zoomcare.candidatechallenge.repository.EmployeeRepository; import org.junit.Before; @@ -68,14 +69,18 @@ private Employee generateEmployee(Long employee_id){ employee.setId(employee_id); List properties = new ArrayList<>(); Property property = new Property(); - property.setEmployee_id(employee_id); - property.setKey("KEY"); + EntityPropertyPk pk = new EntityPropertyPk(); + pk.setKey("KEY"); + pk.setEmployee(employee); + property.setId(pk); property.setValue("VALUE"); properties.add(property); Property property2 = new Property(); - property2.setEmployee_id(employee_id); - property2.setKey("KEY2"); + EntityPropertyPk pk2 = new EntityPropertyPk(); + pk2.setKey("KEY2"); + pk2.setEmployee(employee); + property2.setId(pk2); property2.setValue("VALUE2"); properties.add(property2);