diff --git a/pom.xml b/pom.xml index 17fd7ad..83b4779 100644 --- a/pom.xml +++ b/pom.xml @@ -25,13 +25,18 @@ org.springframework.boot - spring-boot-starter-data-jdbc + spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-web - + + org.projectlombok + lombok + 1.18.24 + provided + org.flywaydb flyway-core @@ -49,6 +54,18 @@ spring-boot-starter-test test + + + io.springfox + springfox-swagger2 + 2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + 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..0643b51 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/config/SwaggerConfig.java @@ -0,0 +1,28 @@ +package com.zoomcare.candidatechallenge.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + @Bean + public Docket challengeApi() { + return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).groupName("Candidate Challenge").select() + .apis(RequestHandlerSelectors.basePackage("com.zoomcare.candidatechallenge.controllers")).build(); + + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder().title("Challenge Api").description("The resulting services should allow users to get a list of all top-level employees or to specify an employee by id to return just that employee.") + .contact(new Contact("Gabriel Leoni","","")).version("1.0").build(); + } +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/controllers/EmployeeController.java b/src/main/java/com/zoomcare/candidatechallenge/controllers/EmployeeController.java new file mode 100644 index 0000000..0e99bf2 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/controllers/EmployeeController.java @@ -0,0 +1,35 @@ +package com.zoomcare.candidatechallenge.controllers; + +import java.math.BigInteger; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zoomcare.candidatechallenge.map.EmployeeData; +import com.zoomcare.candidatechallenge.service.EmployeeService; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RestController +@RequestMapping("/employee") +public class EmployeeController { + + @Autowired + private EmployeeService employeeService; + + @GetMapping + public ResponseEntity getEmployee(BigInteger id) { + return employeeService.getEmployeeData(id); + } + + @GetMapping("/topLevel") + public ResponseEntity> getTopLevelEmployee() { + return employeeService.getTopLevelEmployee(); + } + +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/entities/Employee.java b/src/main/java/com/zoomcare/candidatechallenge/entities/Employee.java new file mode 100644 index 0000000..7fc6dbc --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/entities/Employee.java @@ -0,0 +1,28 @@ +package com.zoomcare.candidatechallenge.entities; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +import lombok.Data; + +@Entity +@Data +public class Employee { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private BigInteger id; + + @Column(name = "supervisor_id") + private BigInteger supervisorid; + +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/entities/Property.java b/src/main/java/com/zoomcare/candidatechallenge/entities/Property.java new file mode 100644 index 0000000..7f1e403 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/entities/Property.java @@ -0,0 +1,32 @@ +package com.zoomcare.candidatechallenge.entities; + +import java.math.BigInteger; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.zoomcare.candidatechallenge.repositories.CompositeKey; + +import lombok.Data; + +@Data +@Entity +@IdClass(CompositeKey.class) +public class Property { + + @Id + @JsonIgnore + @Column(name = "employee_id") + private BigInteger employeeId; + + @Id + private String key; + + @Id + private String value; + + +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/map/EmployeeData.java b/src/main/java/com/zoomcare/candidatechallenge/map/EmployeeData.java new file mode 100644 index 0000000..190dfc7 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/map/EmployeeData.java @@ -0,0 +1,19 @@ +package com.zoomcare.candidatechallenge.map; + +import java.util.List; + +import com.zoomcare.candidatechallenge.entities.Employee; +import com.zoomcare.candidatechallenge.entities.Property; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class EmployeeData { + + private Employee employee; + + private List properties; + +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/repositories/CompositeKey.java b/src/main/java/com/zoomcare/candidatechallenge/repositories/CompositeKey.java new file mode 100644 index 0000000..e444d37 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/repositories/CompositeKey.java @@ -0,0 +1,14 @@ +package com.zoomcare.candidatechallenge.repositories; + +import java.io.Serializable; +import java.math.BigInteger; + +public class CompositeKey implements Serializable { + + private BigInteger employeeId; + + private String key; + + private String value; + +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/repositories/EmployeeRepository.java b/src/main/java/com/zoomcare/candidatechallenge/repositories/EmployeeRepository.java new file mode 100644 index 0000000..1b02c62 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/repositories/EmployeeRepository.java @@ -0,0 +1,19 @@ +package com.zoomcare.candidatechallenge.repositories; + +import java.math.BigInteger; +import java.util.List; +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import com.zoomcare.candidatechallenge.entities.Employee; + +@Repository +public interface EmployeeRepository extends JpaRepository{ + + Optional findById(BigInteger id); + + Optional> findAllBySupervisoridIsNull(); +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/repositories/PropertyRepository.java b/src/main/java/com/zoomcare/candidatechallenge/repositories/PropertyRepository.java new file mode 100644 index 0000000..8d794cd --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/repositories/PropertyRepository.java @@ -0,0 +1,19 @@ +package com.zoomcare.candidatechallenge.repositories; + +import java.math.BigInteger; +import java.util.List; +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.zoomcare.candidatechallenge.entities.Property; + +@Repository +public interface PropertyRepository extends JpaRepository{ + + Optional findByEmployeeId(BigInteger employeeId); + + Optional> findAllByEmployeeId(BigInteger employeeId); + +} diff --git a/src/main/java/com/zoomcare/candidatechallenge/service/EmployeeService.java b/src/main/java/com/zoomcare/candidatechallenge/service/EmployeeService.java new file mode 100644 index 0000000..d3c2976 --- /dev/null +++ b/src/main/java/com/zoomcare/candidatechallenge/service/EmployeeService.java @@ -0,0 +1,69 @@ +package com.zoomcare.candidatechallenge.service; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import com.zoomcare.candidatechallenge.entities.Employee; +import com.zoomcare.candidatechallenge.entities.Property; +import com.zoomcare.candidatechallenge.map.EmployeeData; +import com.zoomcare.candidatechallenge.repositories.EmployeeRepository; +import com.zoomcare.candidatechallenge.repositories.PropertyRepository; + +import lombok.extern.log4j.Log4j2; + +@Service +@Log4j2 +public class EmployeeService { + + @Autowired + private EmployeeRepository empRepo; + + @Autowired + private PropertyRepository propRepo; + + public ResponseEntity getEmployeeData(BigInteger id) { + + Optional emp = empRepo.findById(id); + + if(emp.isPresent()) { + Optional> props = propRepo.findAllByEmployeeId(id); + + return new ResponseEntity(EmployeeData.builder().employee(emp.get()).properties(props.get()).build(), HttpStatus.OK); + }else { + log.error("The emploee with id {} does not exist.", id); + return new ResponseEntity(HttpStatus.NOT_FOUND); + } + + } + + public ResponseEntity> getTopLevelEmployee() { + + Optional> topEmpList = empRepo.findAllBySupervisoridIsNull(); + + if(topEmpList.isPresent()) { + List finalList = new ArrayList<>(); + + topEmpList.get().forEach(employee -> { + Optional> props = propRepo.findAllByEmployeeId(employee.getId()); + + finalList.add(EmployeeData.builder().employee(employee).properties(props.get()).build()); + }); + + return new ResponseEntity>(finalList, HttpStatus.OK); + }else { + + log.error("There are no top-level employees"); + return new ResponseEntity>(HttpStatus.NOT_FOUND); + } + + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 4408d17..9a4c36e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,6 +2,12 @@ spring: h2: console: enabled: true + datasource: + url: jdbc:h2:mem:testdb + username: sa + password: sa + driverClassName: org.h2.Driver + management: endpoints: web: