test(person): address PR #736 review nits
- AC-3 cascade test: assert an innocent bystander's mention row survives the delete, proving the cascade is scoped to the deleted person (Nora). - Fix integration-test comment: receivers is @ManyToMany(LAZY), not an EAGER @ElementCollection (Sara). - ADR-032: note the @ prefix is kept in the degraded path, stripped in live mentions (Leonie). - Add trailing newline to PersonRepository.java (Felix). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -207,4 +207,4 @@ public interface PersonRepository extends JpaRepository<Person, UUID> {
|
||||
)
|
||||
""", nativeQuery = true)
|
||||
void insertMissingReceiverReference(@Param("source") UUID source, @Param("target") UUID target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,6 +776,7 @@ class PersonRepositoryTest {
|
||||
// AC-3: the @-mention sidecar is a CASCADE soft reference, but the literal "@Name" lives
|
||||
// in transcription_blocks.text and must stay visible as plain text after the person goes.
|
||||
Person mentioned = personRepository.save(Person.builder().firstName("Auguste").lastName("Raddatz").build());
|
||||
Person survivor = personRepository.save(Person.builder().firstName("Clara").lastName("Cram").build());
|
||||
Document doc = documentRepository.save(Document.builder()
|
||||
.title("Brief").originalFilename("brief.pdf")
|
||||
.status(DocumentStatus.UPLOADED).build());
|
||||
@@ -790,12 +791,18 @@ class PersonRepositoryTest {
|
||||
entityManager.createNativeQuery(
|
||||
"INSERT INTO transcription_blocks (id, annotation_id, document_id, text) VALUES (?1, ?2, ?3, ?4)")
|
||||
.setParameter(1, blockId).setParameter(2, annotationId).setParameter(3, doc.getId())
|
||||
.setParameter(4, "Brief an @Auguste Raddatz").executeUpdate();
|
||||
.setParameter(4, "Brief an @Auguste Raddatz und @Clara Cram").executeUpdate();
|
||||
// Two mention rows on the same block: the deleted person and an innocent bystander.
|
||||
entityManager.createNativeQuery(
|
||||
"INSERT INTO transcription_block_mentioned_persons (block_id, person_id, display_name) "
|
||||
+ "VALUES (?1, ?2, ?3)")
|
||||
.setParameter(1, blockId).setParameter(2, mentioned.getId())
|
||||
.setParameter(3, "Auguste Raddatz").executeUpdate();
|
||||
entityManager.createNativeQuery(
|
||||
"INSERT INTO transcription_block_mentioned_persons (block_id, person_id, display_name) "
|
||||
+ "VALUES (?1, ?2, ?3)")
|
||||
.setParameter(1, blockId).setParameter(2, survivor.getId())
|
||||
.setParameter(3, "Clara Cram").executeUpdate();
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
|
||||
@@ -808,9 +815,15 @@ class PersonRepositoryTest {
|
||||
.setParameter(1, mentioned.getId()).getSingleResult();
|
||||
assertThat(mentionRows.longValue()).isZero();
|
||||
|
||||
// The cascade is scoped to the deleted person — the bystander's mention row is untouched.
|
||||
Number survivorRows = (Number) entityManager.createNativeQuery(
|
||||
"SELECT count(*) FROM transcription_block_mentioned_persons WHERE person_id = ?1")
|
||||
.setParameter(1, survivor.getId()).getSingleResult();
|
||||
assertThat(survivorRows.longValue()).isEqualTo(1);
|
||||
|
||||
String text = (String) entityManager.createNativeQuery(
|
||||
"SELECT text FROM transcription_blocks WHERE id = ?1")
|
||||
.setParameter(1, blockId).getSingleResult();
|
||||
assertThat(text).isEqualTo("Brief an @Auguste Raddatz");
|
||||
assertThat(text).isEqualTo("Brief an @Auguste Raddatz und @Clara Cram");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ class PersonServiceIntegrationTest {
|
||||
|
||||
// The ON DELETE cascade fires beneath Hibernate — flush the delete and clear the L1
|
||||
// cache so the asserting reads observe the post-delete database state, not stale
|
||||
// managed entities (the EAGER @ElementCollection on receivers makes this load-bearing).
|
||||
// managed entities still holding the dropped sender/receiver associations.
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
|
||||
|
||||
@@ -45,7 +45,9 @@ letters. This is pinned by a non-negotiable document-survival assertion in
|
||||
stay thin (`deleteById` + the cascade); `reassignSenderToNull` and `deleteReceiverReferences`
|
||||
are deleted.
|
||||
- This *fixes* the pre-existing dead-link-on-deleted-person case — it is not a purely
|
||||
invisible refactor.
|
||||
invisible refactor. Note the read renderer strips the `@` prefix when it emits a live
|
||||
mention link, but the degraded (deleted-person) path leaves the literal `@Name` in the
|
||||
block text as-is — the reader sees `@Auguste Raddatz` as plain text, never a dead link.
|
||||
- DB cascades run below `AuditService`, so the row-level cleanup is intentionally not
|
||||
audit-logged; the person-delete action itself is still logged at the service layer.
|
||||
- The V71 FK validation requires cleaning pre-existing orphan mention rows first; the
|
||||
|
||||
Reference in New Issue
Block a user