diff --git a/pom.xml b/pom.xml index 27c68ac..bf6e3dc 100644 --- a/pom.xml +++ b/pom.xml @@ -25,6 +25,14 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + org.projectlombok lombok @@ -37,7 +45,7 @@ org.springdoc - springdoc-openapi-starter-common + springdoc-openapi-starter-webmvc-ui 2.8.13 diff --git a/src/main/java/com/spijkerman/ivo/threekidfamily/ThreeKidFamilyApplication.java b/src/main/java/com/spijkerman/ivo/threekidfamily/ThreeKidFamilyApplication.java index ea1af2f..85c3a5c 100644 --- a/src/main/java/com/spijkerman/ivo/threekidfamily/ThreeKidFamilyApplication.java +++ b/src/main/java/com/spijkerman/ivo/threekidfamily/ThreeKidFamilyApplication.java @@ -2,7 +2,9 @@ package com.spijkerman.ivo.threekidfamily; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +@EnableJpaRepositories @SpringBootApplication public class ThreeKidFamilyApplication { diff --git a/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/Person.java b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/Person.java new file mode 100644 index 0000000..5541530 --- /dev/null +++ b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/Person.java @@ -0,0 +1,4 @@ +package com.spijkerman.ivo.threekidfamily.domain.person; + +public record Person() { +} diff --git a/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonController.java b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonController.java new file mode 100644 index 0000000..2a5956d --- /dev/null +++ b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonController.java @@ -0,0 +1,38 @@ +package com.spijkerman.ivo.threekidfamily.domain.person; + +import com.spijkerman.ivo.threekidfamily.domain.person.dto.PersonUpsertRequest; +import com.spijkerman.ivo.threekidfamily.domain.person.dto.PersonUpsertResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/v1/people") +@RequiredArgsConstructor +public class PersonController { + + private final PersonService personService; + + @PostMapping + public ResponseEntity> upsertPerson( + @RequestBody PersonUpsertRequest request + ) { + throw new UnsupportedOperationException(); + } + + @GetMapping("/{id}") + public ResponseEntity getPerson( + @PathVariable int id + ) { + throw new UnsupportedOperationException(); + } + + @DeleteMapping + public ResponseEntity deletePeople( + @RequestBody List ids + ) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonEntity.java b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonEntity.java new file mode 100644 index 0000000..d25e826 --- /dev/null +++ b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonEntity.java @@ -0,0 +1,45 @@ +package com.spijkerman.ivo.threekidfamily.domain.person; + +import jakarta.annotation.Nullable; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import lombok.*; + +import java.time.LocalDate; +import java.util.HashSet; +import java.util.Set; + +@Data +@Entity +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PersonEntity { + + @Id + @NonNull + private Integer id; + + @Nullable + private String name; + + @Nullable + private LocalDate birthDate; + + // Store only relation IDs instead of JPA mappings to reduce JPA/Hibernate tomfoolery + @Nullable + private Integer partnerId; + + @NonNull + @Singular + @ElementCollection(fetch = FetchType.EAGER) + private Set childIds = new HashSet<>(); + + @NonNull + @Singular + @ElementCollection(fetch = FetchType.EAGER) + private Set parentIds = new HashSet<>(); + +} diff --git a/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonRepository.java b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonRepository.java new file mode 100644 index 0000000..c6ea303 --- /dev/null +++ b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonRepository.java @@ -0,0 +1,8 @@ +package com.spijkerman.ivo.threekidfamily.domain.person; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PersonRepository extends JpaRepository { +} diff --git a/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonService.java b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonService.java new file mode 100644 index 0000000..6106fe7 --- /dev/null +++ b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/PersonService.java @@ -0,0 +1,44 @@ +package com.spijkerman.ivo.threekidfamily.domain.person; + +import lombok.Locked; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Set; + +@Service +@RequiredArgsConstructor +public class PersonService { + + private final PersonRepository personRepository; + + /** + * Upserts a person to storage, overwriting any existing or conflicting data. + * + * @param person The Person data to be persisted + * @return The IDs of the Persons that have been modified because of this operation. + */ + public @NonNull Set upsertPerson(Person person) { + throw new UnsupportedOperationException(); + } + + /** + * Returns all known data related to that specific user. + * + * @param id The ID of the person to be retrieved. + * @return A Person object, may contain all information, or just the ID. + */ + public Person getPersonById(int id) { + throw new UnsupportedOperationException(); + } + + /** + * Deletes all data related to the specified user, and blacklists that ID from later use. + * @param id The ID of the person to be deleted and blacklisted. + */ + public void deletePersonById(int id) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/dto/PersonUpsertRequest.java b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/dto/PersonUpsertRequest.java new file mode 100644 index 0000000..57dc347 --- /dev/null +++ b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/dto/PersonUpsertRequest.java @@ -0,0 +1,4 @@ +package com.spijkerman.ivo.threekidfamily.domain.person.dto; + +public record PersonUpsertRequest() { +} diff --git a/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/dto/PersonUpsertResponse.java b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/dto/PersonUpsertResponse.java new file mode 100644 index 0000000..b2c1571 --- /dev/null +++ b/src/main/java/com/spijkerman/ivo/threekidfamily/domain/person/dto/PersonUpsertResponse.java @@ -0,0 +1,4 @@ +package com.spijkerman.ivo.threekidfamily.domain.person.dto; + +public record PersonUpsertResponse() { +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 2e720a9..6abf4cc 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -1 +1,5 @@ -spring.application.name: threekidfamily +spring: + datasource: + url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + username: sa + password: password \ No newline at end of file diff --git a/src/test/java/com/spijkerman/ivo/threekidfamily/ThreeKidFamilyApplicationTests.java b/src/test/java/com/spijkerman/ivo/threekidfamily/ThreeKidFamilyApplicationTests.java deleted file mode 100644 index e98569b..0000000 --- a/src/test/java/com/spijkerman/ivo/threekidfamily/ThreeKidFamilyApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.spijkerman.ivo.threekidfamily; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class ThreeKidFamilyApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/src/test/java/com/spijkerman/ivo/threekidfamily/ThreeKidFamilyIT.java b/src/test/java/com/spijkerman/ivo/threekidfamily/ThreeKidFamilyIT.java new file mode 100644 index 0000000..4e0c8a8 --- /dev/null +++ b/src/test/java/com/spijkerman/ivo/threekidfamily/ThreeKidFamilyIT.java @@ -0,0 +1,53 @@ +package com.spijkerman.ivo.threekidfamily; + +import com.spijkerman.ivo.threekidfamily.domain.person.Person; +import com.spijkerman.ivo.threekidfamily.domain.person.PersonEntity; +import com.spijkerman.ivo.threekidfamily.domain.person.PersonRepository; +import com.spijkerman.ivo.threekidfamily.domain.person.PersonService; +import lombok.val; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class ThreeKidFamilyIT { + + @Autowired + private TestRestTemplate restTemplate; + + @Autowired + private PersonRepository personRepository; + + @Test + void contextLoads() { + } + + @Test + void gibberishNotFound() { + val response = restTemplate.exchange("/gibberish", HttpMethod.GET, null, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + } + + @Test + void swaggerUiLoads() { + val response = restTemplate.exchange("/swagger-ui.html", HttpMethod.GET, null, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + } + + @Test + void testDbRoundTrip() { + val given = PersonEntity.builder().id(12).build(); + val saved = personRepository.save(given); + + assertThat(saved).isEqualTo(given); + + val retrieved = personRepository.findById(12); + assertThat(retrieved).isPresent().hasValue(given); + } + +} diff --git a/src/test/resources/application.yaml b/src/test/resources/application.yaml new file mode 100644 index 0000000..5e86f41 --- /dev/null +++ b/src/test/resources/application.yaml @@ -0,0 +1,3 @@ +spring: + jpa: + show-sql: true \ No newline at end of file