fix: db
This commit is contained in:
@@ -2,9 +2,12 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Device;
|
||||
use App\Models\Photo;
|
||||
use App\Services\PhotoPreview;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
@@ -35,66 +38,100 @@ class PrunePhotosBeforeCommand extends Command
|
||||
$q->where('photos.device_id', (int) $deviceFilter);
|
||||
} else {
|
||||
$q->join('devices', 'devices.id', '=', 'photos.device_id')
|
||||
->where('devices.device_id', $deviceFilter)
|
||||
->select('photos.*');
|
||||
->where('devices.device_id', $deviceFilter);
|
||||
}
|
||||
}
|
||||
|
||||
$count = (clone $q)->count();
|
||||
$this->info(sprintf(
|
||||
'%s cutoff=%s photos=%d',
|
||||
'%s cutoff=%s streaming batches of 500 (no pre-count)',
|
||||
$execute ? 'EXECUTE' : 'DRY-RUN',
|
||||
$date,
|
||||
$count,
|
||||
));
|
||||
|
||||
if ($count === 0) {
|
||||
$disk = Storage::disk('local');
|
||||
$seen = 0;
|
||||
$deletedRows = 0;
|
||||
$deletedFiles = 0;
|
||||
$deviceIds = [];
|
||||
|
||||
$this->eachPhotoBatch($q, 500, function (Collection $photos) use (
|
||||
$execute,
|
||||
$disk,
|
||||
&$seen,
|
||||
&$deletedRows,
|
||||
&$deletedFiles,
|
||||
&$deviceIds,
|
||||
): void {
|
||||
$ids = [];
|
||||
foreach ($photos as $photo) {
|
||||
$ids[] = $photo->id;
|
||||
$deviceIds[$photo->device_id] = true;
|
||||
$seen++;
|
||||
if (! $execute) {
|
||||
continue;
|
||||
}
|
||||
$path = trim((string) ($photo->path ?? ''));
|
||||
if ($path !== '' && $disk->delete($path)) {
|
||||
$deletedFiles++;
|
||||
}
|
||||
}
|
||||
if ($execute && $ids !== []) {
|
||||
DB::table('photo_reads')->whereIn('photo_id', $ids)->delete();
|
||||
Photo::query()->whereIn('id', $ids)->delete();
|
||||
$deletedRows += count($ids);
|
||||
}
|
||||
$this->info($execute
|
||||
? sprintf(' deleted_rows=%d deleted_files=%d', $deletedRows, $deletedFiles)
|
||||
: sprintf(' matched=%d', $seen));
|
||||
});
|
||||
|
||||
if ($seen === 0) {
|
||||
$this->info('nothing to prune');
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
if (! $execute) {
|
||||
$this->warn('dry-run only; pass --execute to delete');
|
||||
$this->info(sprintf('dry-run matched_photos=%d devices=%d; pass --execute to delete', $seen, count($deviceIds)));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$disk = Storage::disk('local');
|
||||
$deletedRows = 0;
|
||||
$deletedFiles = 0;
|
||||
$deviceIds = [];
|
||||
|
||||
// Process in chunks to avoid loading everything into memory.
|
||||
$q->select(['photos.id', 'photos.device_id', 'photos.path'])
|
||||
->orderBy('photos.id')
|
||||
->chunk(500, function ($photos) use ($disk, $previews, &$deletedRows, &$deletedFiles, &$deviceIds) {
|
||||
$ids = [];
|
||||
foreach ($photos as $photo) {
|
||||
$ids[] = $photo->id;
|
||||
$path = trim((string) ($photo->path ?? ''));
|
||||
if ($path !== '' && $disk->exists($path)) {
|
||||
$disk->delete($path);
|
||||
$deletedFiles++;
|
||||
}
|
||||
$deviceIds[$photo->device_id] = true;
|
||||
}
|
||||
// Delete PhotoRead markers first (foreign key), then photos.
|
||||
DB::table('photo_reads')->whereIn('photo_id', $ids)->delete();
|
||||
Photo::query()->whereIn('id', $ids)->delete();
|
||||
$deletedRows += count($ids);
|
||||
});
|
||||
|
||||
// Clear preview caches for affected devices.
|
||||
foreach (array_keys($deviceIds) as $deviceId) {
|
||||
$device = \App\Models\Device::find($deviceId);
|
||||
$device = Device::query()->find($deviceId);
|
||||
if ($device) {
|
||||
$previews->forgetForDevice((string) $device->device_id);
|
||||
}
|
||||
}
|
||||
|
||||
$this->info(sprintf('deleted_rows=%d deleted_files=%d devices=%d', $deletedRows, $deletedFiles, count($deviceIds)));
|
||||
$this->info(sprintf(
|
||||
'done deleted_rows=%d deleted_files=%d devices=%d',
|
||||
$deletedRows,
|
||||
$deletedFiles,
|
||||
count($deviceIds),
|
||||
));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable(Collection<int, Photo>): void $fn
|
||||
*/
|
||||
private function eachPhotoBatch(Builder $q, int $size, callable $fn): void
|
||||
{
|
||||
$lastId = 0;
|
||||
while (true) {
|
||||
$photos = (clone $q)
|
||||
->select(['photos.id', 'photos.device_id', 'photos.path'])
|
||||
->where('photos.id', '>', $lastId)
|
||||
->orderBy('photos.id')
|
||||
->limit($size)
|
||||
->get();
|
||||
if ($photos->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
$fn($photos);
|
||||
$lastId = (int) $photos->last()->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user