Enhance object version removal to exclude point-in-time versions

Add a check to exclude versions associated with points in time before deleting old object versions. This ensures that such versions are not mistakenly removed, providing greater data integrity. Updated tests and repository methods accordingly.
This commit is contained in:
Julien Fastré 2024-09-10 12:06:09 +02:00
parent d33da6519a
commit 669b967899
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
5 changed files with 13 additions and 5 deletions

View File

@ -62,7 +62,7 @@ class StoredObjectVersionRepository implements ObjectRepository
*
* @return iterable returns an iterable with the IDs of the versions
*/
public function findIdsByVersionsOlderThanDateAndNotLastVersion(\DateTimeImmutable $beforeDate): iterable
public function findIdsByVersionsOlderThanDateAndNotLastVersionAndNotPointInTime(\DateTimeImmutable $beforeDate): iterable
{
$results = $this->connection->executeQuery(
self::QUERY_FIND_IDS_BY_VERSIONS_OLDER_THAN_DATE_AND_NOT_LAST_VERSION,
@ -83,6 +83,8 @@ class StoredObjectVersionRepository implements ObjectRepository
sov.createdat < ?::timestamp
AND
sov.version < (SELECT MAX(sub_sov.version) FROM chill_doc.stored_object_version sub_sov WHERE sub_sov.stored_object_id = sov.stored_object_id)
AND
NOT EXISTS (SELECT 1 FROM chill_doc.stored_object_point_in_time sub_poi WHERE sub_poi.stored_object_version_id = sov.id)
SQL;
public function getClassName(): string

View File

@ -50,7 +50,7 @@ final readonly class RemoveOldVersionCronJob implements CronJobInterface
$deleteBeforeDate = $this->clock->now()->sub(new \DateInterval(self::KEEP_INTERVAL));
$maxDeleted = $lastExecutionData[self::LAST_DELETED_KEY] ?? 0;
foreach ($this->storedObjectVersionRepository->findIdsByVersionsOlderThanDateAndNotLastVersion($deleteBeforeDate) as $id) {
foreach ($this->storedObjectVersionRepository->findIdsByVersionsOlderThanDateAndNotLastVersionAndNotPointInTime($deleteBeforeDate) as $id) {
$this->messageBus->dispatch(new RemoveOldVersionMessage($id));
$maxDeleted = max($maxDeleted, $id);
}

View File

@ -18,6 +18,7 @@ use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Clock\ClockInterface;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
/**
@ -49,13 +50,18 @@ final readonly class RemoveOldVersionMessageHandler implements MessageHandlerInt
$this->logger->info(self::LOG_PREFIX.'Received one message', ['storedObjectVersionId' => $message->storedObjectVersionId]);
$storedObjectVersion = $this->storedObjectVersionRepository->find($message->storedObjectVersionId);
$storedObject = $storedObjectVersion->getStoredObject();
if (null === $storedObjectVersion) {
$this->logger->error(self::LOG_PREFIX.'StoredObjectVersion not found in database', ['storedObjectVersionId' => $message->storedObjectVersionId]);
throw new \RuntimeException('StoredObjectVersion not found with id '.$message->storedObjectVersionId);
}
if ($storedObjectVersion->hasPointInTimes()) {
throw new UnrecoverableMessageHandlingException('the stored object version is now associated with a point in time');
}
$storedObject = $storedObjectVersion->getStoredObject();
$this->storedObjectManager->delete($storedObjectVersion);
// to ensure an immediate deletion
$this->entityManager->remove($storedObjectVersion);

View File

@ -35,7 +35,7 @@ class StoredObjectVersionRepositoryTest extends KernelTestCase
$repository = new StoredObjectVersionRepository($this->entityManager);
// get old version, to get a chance to get one
$actual = $repository->findIdsByVersionsOlderThanDateAndNotLastVersion(new \DateTimeImmutable('1970-01-01'));
$actual = $repository->findIdsByVersionsOlderThanDateAndNotLastVersionAndNotPointInTime(new \DateTimeImmutable('1970-01-01'));
self::assertIsIterable($actual);
self::assertContainsOnly('int', $actual);

View File

@ -46,7 +46,7 @@ class RemoveOldVersionCronJobTest extends KernelTestCase
$clock = new MockClock(new \DateTimeImmutable('2024-01-01 00:00:00', new \DateTimeZone('+00:00')));
$repository = $this->createMock(StoredObjectVersionRepository::class);
$repository->expects($this->once())
->method('findIdsByVersionsOlderThanDateAndNotLastVersion')
->method('findIdsByVersionsOlderThanDateAndNotLastVersionAndNotPointInTime')
->with(new \DateTime('2023-10-03 00:00:00', new \DateTimeZone('+00:00')))
->willReturnCallback(function ($arg) {
yield 1;