'system', 'action' => 'test.batch', 'description' => "오래된 기록 {$i}", ]); $log->forceFill(['created_at' => now()->subDays(400)])->saveQuietly(); } $deleted = $this->runner()->purge( ActivityLog::where('created_at', '<', now()->subDays(365)) ); $this->assertSame(7, $deleted); $this->assertSame(0, ActivityLog::where('action', 'test.batch')->count()); } /** * 조건 밖의 행은 배치가 몇 회전을 돌아도 건드리지 않는다. */ public function test_keeps_rows_outside_the_condition(): void { foreach (range(1, 5) as $i) { $old = ActivityLog::create([ 'log_type' => 'system', 'action' => 'test.batch.old', 'description' => "오래된 기록 {$i}", ]); $old->forceFill(['created_at' => now()->subDays(400)])->saveQuietly(); } $recent = ActivityLog::create([ 'log_type' => 'system', 'action' => 'test.batch.recent', 'description' => '최근 기록', ]); $this->runner()->purge( ActivityLog::where('created_at', '<', now()->subDays(365)) ); $this->assertDatabaseHas('activity_logs', ['id' => $recent->id]); $this->assertSame(0, ActivityLog::where('action', 'test.batch.old')->count()); } /** * 대상이 없으면 0 을 돌려주고 끝난다 (무한 루프 방지). */ public function test_returns_zero_when_nothing_matches(): void { $deleted = $this->runner()->purge( ActivityLog::where('created_at', '<', now()->subDays(365)) ); $this->assertSame(0, $deleted); } /** * 배치 크기를 작게 잡은 실행기를 만듭니다. * * 기본 배치(1000)로는 여러 회전을 만들려면 그만큼 행을 쌓아야 해서, * 회전 자체를 검증하려면 크기를 줄이는 편이 정확하다. * * @return object purge(Builder): int 를 제공하는 실행기 */ private function runner(): object { return new class { use DeletesInBatches; /** * 조건에 맞는 행을 배치로 삭제합니다. * * 회전을 강제하려고 배치 크기를 2 로 낮춰 호출합니다. * * @param Builder $query 삭제 대상 쿼리 * @return int 삭제된 건수 */ public function purge(Builder $query): int { return $this->deleteInBatches($query, 2); } }; } }