|
8 | 8 | */ |
9 | 9 | namespace OCA\DAV\Migration; |
10 | 10 |
|
11 | | -use OCA\DAV\CalDAV\CalDavBackend; |
12 | | -use OCP\DB\QueryBuilder\IQueryBuilder; |
13 | | -use OCP\IDBConnection; |
| 11 | +use OCA\DAV\BackgroundJob\CleanupOrphanedChildrenJob; |
| 12 | +use OCP\BackgroundJob\IJobList; |
14 | 13 | use OCP\Migration\IOutput; |
15 | 14 | use OCP\Migration\IRepairStep; |
16 | 15 |
|
17 | 16 | class RemoveOrphanEventsAndContacts implements IRepairStep { |
18 | | - |
19 | 17 | public function __construct( |
20 | | - private IDBConnection $connection, |
| 18 | + private readonly IJobList $jobList, |
21 | 19 | ) { |
22 | 20 | } |
23 | 21 |
|
24 | | - /** |
25 | | - * @inheritdoc |
26 | | - */ |
27 | 22 | public function getName(): string { |
28 | | - return 'Clean up orphan event and contact data'; |
| 23 | + return 'Queue jobs to clean up orphan event and contact data'; |
29 | 24 | } |
30 | 25 |
|
31 | | - /** |
32 | | - * @inheritdoc |
33 | | - */ |
34 | | - public function run(IOutput $output) { |
35 | | - $orphanItems = $this->removeOrphanChildren('calendarobjects', 'calendars', 'calendarid'); |
36 | | - $output->info(sprintf('%d events without a calendar have been cleaned up', $orphanItems)); |
37 | | - $orphanItems = $this->removeOrphanChildren('calendarobjects_props', 'calendarobjects', 'objectid'); |
38 | | - $output->info(sprintf('%d properties without an events have been cleaned up', $orphanItems)); |
39 | | - $orphanItems = $this->removeOrphanChildren('calendarchanges', 'calendars', 'calendarid'); |
40 | | - $output->info(sprintf('%d changes without a calendar have been cleaned up', $orphanItems)); |
| 26 | + public function run(IOutput $output): void { |
| 27 | + $this->queueJob('calendarobjects', 'calendars', 'calendarid', '%d events without a calendar have been cleaned up'); |
| 28 | + $this->queueJob('calendarobjects_props', 'calendarobjects', 'objectid', '%d properties without an events have been cleaned up'); |
| 29 | + $this->queueJob('calendarchanges', 'calendars', 'calendarid', '%d changes without a calendar have been cleaned up'); |
41 | 30 |
|
42 | | - $orphanItems = $this->removeOrphanChildren('calendarobjects', 'calendarsubscriptions', 'calendarid'); |
43 | | - $output->info(sprintf('%d cached events without a calendar subscription have been cleaned up', $orphanItems)); |
44 | | - $orphanItems = $this->removeOrphanChildren('calendarchanges', 'calendarsubscriptions', 'calendarid'); |
45 | | - $output->info(sprintf('%d changes without a calendar subscription have been cleaned up', $orphanItems)); |
| 31 | + $this->queueJob('calendarobjects', 'calendarsubscriptions', 'calendarid', '%d cached events without a calendar subscription have been cleaned up'); |
| 32 | + $this->queueJob('calendarchanges', 'calendarsubscriptions', 'calendarid', '%d changes without a calendar subscription have been cleaned up'); |
46 | 33 |
|
47 | | - $orphanItems = $this->removeOrphanChildren('cards', 'addressbooks', 'addressbookid'); |
48 | | - $output->info(sprintf('%d contacts without an addressbook have been cleaned up', $orphanItems)); |
49 | | - $orphanItems = $this->removeOrphanChildren('cards_properties', 'cards', 'cardid'); |
50 | | - $output->info(sprintf('%d properties without a contact have been cleaned up', $orphanItems)); |
51 | | - $orphanItems = $this->removeOrphanChildren('addressbookchanges', 'addressbooks', 'addressbookid'); |
52 | | - $output->info(sprintf('%d changes without an addressbook have been cleaned up', $orphanItems)); |
| 34 | + $this->queueJob('cards', 'addressbooks', 'addressbookid', '%d contacts without an addressbook have been cleaned up'); |
| 35 | + $this->queueJob('cards_properties', 'cards', 'cardid', '%d properties without a contact have been cleaned up'); |
| 36 | + $this->queueJob('addressbookchanges', 'addressbooks', 'addressbookid', '%d changes without an addressbook have been cleaned up'); |
53 | 37 | } |
54 | 38 |
|
55 | | - protected function removeOrphanChildren($childTable, $parentTable, $parentId): int { |
56 | | - $qb = $this->connection->getQueryBuilder(); |
57 | | - |
58 | | - $qb->select('c.id') |
59 | | - ->from($childTable, 'c') |
60 | | - ->leftJoin('c', $parentTable, 'p', $qb->expr()->eq('c.' . $parentId, 'p.id')) |
61 | | - ->where($qb->expr()->isNull('p.id')); |
62 | | - |
63 | | - if (\in_array($parentTable, ['calendars', 'calendarsubscriptions'], true)) { |
64 | | - $calendarType = $parentTable === 'calendarsubscriptions' ? CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION : CalDavBackend::CALENDAR_TYPE_CALENDAR; |
65 | | - $qb->andWhere($qb->expr()->eq('c.calendartype', $qb->createNamedParameter($calendarType, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)); |
66 | | - } |
67 | | - |
68 | | - $result = $qb->executeQuery(); |
69 | | - |
70 | | - $orphanItems = []; |
71 | | - while ($row = $result->fetch()) { |
72 | | - $orphanItems[] = (int)$row['id']; |
73 | | - } |
74 | | - $result->closeCursor(); |
75 | | - |
76 | | - if (!empty($orphanItems)) { |
77 | | - $qb->delete($childTable) |
78 | | - ->where($qb->expr()->in('id', $qb->createParameter('ids'))); |
79 | | - |
80 | | - $orphanItemsBatch = array_chunk($orphanItems, 1000); |
81 | | - foreach ($orphanItemsBatch as $items) { |
82 | | - $qb->setParameter('ids', $items, IQueryBuilder::PARAM_INT_ARRAY); |
83 | | - $qb->executeStatement(); |
84 | | - } |
85 | | - } |
86 | | - |
87 | | - return count($orphanItems); |
| 39 | + private function queueJob( |
| 40 | + string $childTable, |
| 41 | + string $parentTable, |
| 42 | + string $parentId, |
| 43 | + string $logMessage, |
| 44 | + ): void { |
| 45 | + $this->jobList->add(CleanupOrphanedChildrenJob::class, [ |
| 46 | + CleanupOrphanedChildrenJob::ARGUMENT_CHILD_TABLE => $childTable, |
| 47 | + CleanupOrphanedChildrenJob::ARGUMENT_PARENT_TABLE => $parentTable, |
| 48 | + CleanupOrphanedChildrenJob::ARGUMENT_PARENT_ID => $parentId, |
| 49 | + CleanupOrphanedChildrenJob::ARGUMENT_LOG_MESSAGE => $logMessage, |
| 50 | + ]); |
88 | 51 | } |
89 | 52 | } |
0 commit comments