diff --git a/backend/src/main/java/org/raddatz/familienarchiv/person/PersonRepository.java b/backend/src/main/java/org/raddatz/familienarchiv/person/PersonRepository.java index 9e14e48e..18c2e8a4 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/person/PersonRepository.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/person/PersonRepository.java @@ -67,7 +67,9 @@ public interface PersonRepository extends JpaRepository { SELECT p.id, p.title, p.first_name AS firstName, p.last_name AS lastName, p.person_type AS personType, p.alias, CAST(EXTRACT(YEAR FROM p.birth_date) AS int) AS birthYear, - CAST(EXTRACT(YEAR FROM p.death_date) AS int) AS deathYear, p.notes, + CAST(EXTRACT(YEAR FROM p.death_date) AS int) AS deathYear, + p.birth_date AS birthDate, p.birth_date_precision AS birthDatePrecision, + p.death_date AS deathDate, p.death_date_precision AS deathDatePrecision, p.notes, p.family_member AS familyMember, p.provisional AS provisional, (SELECT COUNT(*) FROM documents d WHERE d.sender_id = p.id) + (SELECT COUNT(*) FROM document_receivers dr WHERE dr.person_id = p.id) AS documentCount @@ -81,7 +83,9 @@ public interface PersonRepository extends JpaRepository { SELECT p.id, p.title, p.first_name AS firstName, p.last_name AS lastName, p.person_type AS personType, p.alias, CAST(EXTRACT(YEAR FROM p.birth_date) AS int) AS birthYear, - CAST(EXTRACT(YEAR FROM p.death_date) AS int) AS deathYear, p.notes, + CAST(EXTRACT(YEAR FROM p.death_date) AS int) AS deathYear, + p.birth_date AS birthDate, p.birth_date_precision AS birthDatePrecision, + p.death_date AS deathDate, p.death_date_precision AS deathDatePrecision, p.notes, p.family_member AS familyMember, p.provisional AS provisional, (SELECT COUNT(*) FROM documents d WHERE d.sender_id = p.id) + (SELECT COUNT(*) FROM document_receivers dr WHERE dr.person_id = p.id) AS documentCount @@ -103,7 +107,9 @@ public interface PersonRepository extends JpaRepository { SELECT p.id, p.title, p.first_name AS firstName, p.last_name AS lastName, p.person_type AS personType, p.alias, CAST(EXTRACT(YEAR FROM p.birth_date) AS int) AS birthYear, - CAST(EXTRACT(YEAR FROM p.death_date) AS int) AS deathYear, p.notes, + CAST(EXTRACT(YEAR FROM p.death_date) AS int) AS deathYear, + p.birth_date AS birthDate, p.birth_date_precision AS birthDatePrecision, + p.death_date AS deathDate, p.death_date_precision AS deathDatePrecision, p.notes, p.family_member AS familyMember, p.provisional AS provisional, (SELECT COUNT(*) FROM documents d WHERE d.sender_id = p.id) + (SELECT COUNT(*) FROM document_receivers dr WHERE dr.person_id = p.id) AS documentCount @@ -143,7 +149,9 @@ public interface PersonRepository extends JpaRepository { SELECT p.id, p.title, p.first_name AS firstName, p.last_name AS lastName, p.person_type AS personType, p.alias, CAST(EXTRACT(YEAR FROM p.birth_date) AS int) AS birthYear, - CAST(EXTRACT(YEAR FROM p.death_date) AS int) AS deathYear, p.notes, + CAST(EXTRACT(YEAR FROM p.death_date) AS int) AS deathYear, + p.birth_date AS birthDate, p.birth_date_precision AS birthDatePrecision, + p.death_date AS deathDate, p.death_date_precision AS deathDatePrecision, p.notes, p.family_member AS familyMember, p.provisional AS provisional, (SELECT COUNT(*) FROM documents d WHERE d.sender_id = p.id) + (SELECT COUNT(*) FROM document_receivers dr WHERE dr.person_id = p.id) AS documentCount diff --git a/backend/src/main/java/org/raddatz/familienarchiv/person/PersonSummaryDTO.java b/backend/src/main/java/org/raddatz/familienarchiv/person/PersonSummaryDTO.java index 9a92d257..90facef4 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/person/PersonSummaryDTO.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/person/PersonSummaryDTO.java @@ -1,5 +1,8 @@ package org.raddatz.familienarchiv.person; +import org.raddatz.familienarchiv.document.DatePrecision; + +import java.time.LocalDate; import java.util.UUID; /** @@ -16,6 +19,13 @@ public interface PersonSummaryDTO { String getAlias(); Integer getBirthYear(); Integer getDeathYear(); + // Full date + precision alongside the derived years: list consumers that render + // precise life dates (mention dropdown) read these; year-only consumers keep + // the cheaper getBirthYear/getDeathYear. + LocalDate getBirthDate(); + DatePrecision getBirthDatePrecision(); + LocalDate getDeathDate(); + DatePrecision getDeathDatePrecision(); String getNotes(); boolean isFamilyMember(); boolean isProvisional(); diff --git a/backend/src/test/java/org/raddatz/familienarchiv/person/PersonControllerTest.java b/backend/src/test/java/org/raddatz/familienarchiv/person/PersonControllerTest.java index 60231c94..10b6adc8 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/person/PersonControllerTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/person/PersonControllerTest.java @@ -217,6 +217,14 @@ class PersonControllerTest { public String getAlias() { return null; } public Integer getBirthYear() { return null; } public Integer getDeathYear() { return null; } + public java.time.LocalDate getBirthDate() { return null; } + public org.raddatz.familienarchiv.document.DatePrecision getBirthDatePrecision() { + return org.raddatz.familienarchiv.document.DatePrecision.UNKNOWN; + } + public java.time.LocalDate getDeathDate() { return null; } + public org.raddatz.familienarchiv.document.DatePrecision getDeathDatePrecision() { + return org.raddatz.familienarchiv.document.DatePrecision.UNKNOWN; + } public String getNotes() { return null; } public boolean isFamilyMember() { return false; } public boolean isProvisional() { return false; } diff --git a/backend/src/test/java/org/raddatz/familienarchiv/person/PersonRepositoryTest.java b/backend/src/test/java/org/raddatz/familienarchiv/person/PersonRepositoryTest.java index add77786..38587b69 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/person/PersonRepositoryTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/person/PersonRepositoryTest.java @@ -970,4 +970,89 @@ class PersonRepositoryTest { assertThat(found.get(0).getBirthYear()).isEqualTo(1920); assertThat(found.get(0).getDeathYear()).isNull(); } + + // ─── #773 follow-up: full date + precision exposed on the summary projection ── + // (the mention dropdown renders precise life dates from the list endpoint) + + @Test + void findAllWithDocumentCount_exposesDateAndPrecisionFields() { + personRepository.save(Person.builder() + .firstName("Maria").lastName("Praezise") + .birthDate(LocalDate.of(1901, 3, 14)).birthDatePrecision(DatePrecision.DAY) + .deathDate(LocalDate.of(1972, 1, 1)).deathDatePrecision(DatePrecision.YEAR) + .build()); + personRepository.save(Person.builder() + .firstName("Nora").lastName("Datenlos") + .build()); + entityManager.flush(); + + List all = personRepository.findAllWithDocumentCount(); + + PersonSummaryDTO dated = all.stream() + .filter(p -> "Praezise".equals(p.getLastName())).findFirst().orElseThrow(); + assertThat(dated.getBirthDate()).isEqualTo(LocalDate.of(1901, 3, 14)); + assertThat(dated.getBirthDatePrecision()).isEqualTo(DatePrecision.DAY); + assertThat(dated.getDeathDate()).isEqualTo(LocalDate.of(1972, 1, 1)); + assertThat(dated.getDeathDatePrecision()).isEqualTo(DatePrecision.YEAR); + PersonSummaryDTO undated = all.stream() + .filter(p -> "Datenlos".equals(p.getLastName())).findFirst().orElseThrow(); + assertThat(undated.getBirthDate()).isNull(); + assertThat(undated.getBirthDatePrecision()).isEqualTo(DatePrecision.UNKNOWN); + assertThat(undated.getDeathDate()).isNull(); + assertThat(undated.getDeathDatePrecision()).isEqualTo(DatePrecision.UNKNOWN); + } + + @Test + void searchWithDocumentCount_exposesDateAndPrecisionFields() { + personRepository.save(Person.builder() + .firstName("Herbert").lastName("Suchbar") + .birthDate(LocalDate.of(1899, 1, 1)).birthDatePrecision(DatePrecision.YEAR) + .deathDate(LocalDate.of(1972, 6, 12)).deathDatePrecision(DatePrecision.DAY) + .build()); + entityManager.flush(); + + List found = personRepository.searchWithDocumentCount("Suchbar"); + + assertThat(found).hasSize(1); + assertThat(found.get(0).getBirthDate()).isEqualTo(LocalDate.of(1899, 1, 1)); + assertThat(found.get(0).getBirthDatePrecision()).isEqualTo(DatePrecision.YEAR); + assertThat(found.get(0).getDeathDate()).isEqualTo(LocalDate.of(1972, 6, 12)); + assertThat(found.get(0).getDeathDatePrecision()).isEqualTo(DatePrecision.DAY); + } + + @Test + void findTopByDocumentCount_exposesDateAndPrecisionFields() { + personRepository.save(Person.builder() + .firstName("Top").lastName("Dokumentiert") + .birthDate(LocalDate.of(1910, 5, 1)).birthDatePrecision(DatePrecision.MONTH) + .build()); + entityManager.flush(); + + List top = personRepository.findTopByDocumentCount(10); + + PersonSummaryDTO found = top.stream() + .filter(p -> "Dokumentiert".equals(p.getLastName())).findFirst().orElseThrow(); + assertThat(found.getBirthDate()).isEqualTo(LocalDate.of(1910, 5, 1)); + assertThat(found.getBirthDatePrecision()).isEqualTo(DatePrecision.MONTH); + assertThat(found.getDeathDate()).isNull(); + assertThat(found.getDeathDatePrecision()).isEqualTo(DatePrecision.UNKNOWN); + } + + @Test + void findByFilter_exposesDateAndPrecisionFields() { + personRepository.save(Person.builder() + .firstName("Gefiltert").lastName("Genau") + .deathDate(LocalDate.of(1944, 11, 2)).deathDatePrecision(DatePrecision.DAY) + .build()); + entityManager.flush(); + + List found = personRepository.findByFilter( + null, null, null, null, false, "Gefiltert", 10, 0); + + assertThat(found).hasSize(1); + assertThat(found.get(0).getBirthDate()).isNull(); + assertThat(found.get(0).getBirthDatePrecision()).isEqualTo(DatePrecision.UNKNOWN); + assertThat(found.get(0).getDeathDate()).isEqualTo(LocalDate.of(1944, 11, 2)); + assertThat(found.get(0).getDeathDatePrecision()).isEqualTo(DatePrecision.DAY); + } }