refactor(person): thin deletePerson to lean on V71 DB cascade (#684)
Drop the application-layer sender/receiver detach from deletePerson — the V71 ON DELETE constraints now enforce it. Remove the now-unused reassignSenderToNull repository method and rewrite the unit test to assert only the existence check plus deleteById (verifyNoMoreInteractions). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -194,12 +194,6 @@ public interface PersonRepository extends JpaRepository<Person, UUID> {
|
|||||||
@Query(value = "UPDATE documents SET sender_id = :target WHERE sender_id = :source", nativeQuery = true)
|
@Query(value = "UPDATE documents SET sender_id = :target WHERE sender_id = :source", nativeQuery = true)
|
||||||
void reassignSender(@Param("source") UUID source, @Param("target") UUID target);
|
void reassignSender(@Param("source") UUID source, @Param("target") UUID target);
|
||||||
|
|
||||||
// Used by deletePerson: detach a deleted person from documents they sent, so the hard
|
|
||||||
// delete cannot orphan a documents.sender_id FK (the column is nullable).
|
|
||||||
@Modifying
|
|
||||||
@Query(value = "UPDATE documents SET sender_id = NULL WHERE sender_id = :source", nativeQuery = true)
|
|
||||||
void reassignSenderToNull(@Param("source") UUID source);
|
|
||||||
|
|
||||||
@Modifying
|
@Modifying
|
||||||
@Query(value = """
|
@Query(value = """
|
||||||
INSERT INTO document_receivers (document_id, person_id)
|
INSERT INTO document_receivers (document_id, person_id)
|
||||||
|
|||||||
@@ -68,15 +68,13 @@ public class PersonService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hard-deletes a person used by triage. Detaches the person from any documents they
|
* Hard-deletes a person used by triage. Referential integrity is enforced by the database
|
||||||
* sent (nulls sender_id) and from any received-document references first, so the delete
|
* (V71's {@code ON DELETE} constraints: sender_id {@code SET NULL}, receiver and @-mention
|
||||||
* cannot orphan an FK and fail with a 500.
|
* rows {@code CASCADE}), so the service stays thin — it only verifies existence then deletes.
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public void deletePerson(UUID id) {
|
public void deletePerson(UUID id) {
|
||||||
getById(id);
|
getById(id);
|
||||||
personRepository.reassignSenderToNull(id);
|
|
||||||
personRepository.deleteReceiverReferences(id);
|
|
||||||
personRepository.deleteById(id);
|
personRepository.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.any;
|
|||||||
import static org.mockito.ArgumentMatchers.argThat;
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@@ -147,9 +148,11 @@ class PersonServiceTest {
|
|||||||
|
|
||||||
personService.deletePerson(id);
|
personService.deletePerson(id);
|
||||||
|
|
||||||
verify(personRepository).reassignSenderToNull(id);
|
// Integrity is enforced by V71's ON DELETE constraints — the service only checks
|
||||||
verify(personRepository).deleteReceiverReferences(id);
|
// existence then deletes; it no longer detaches sender/receiver references itself.
|
||||||
|
verify(personRepository).findById(id);
|
||||||
verify(personRepository).deleteById(id);
|
verify(personRepository).deleteById(id);
|
||||||
|
verifyNoMoreInteractions(personRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user