Every probe rewrote its file's row on the HDD (content_type, archive): a new row version on a random page and an entry in each of the five indexes. They now live in file_details on the NVMe; files rows are inserted once. files:move-details copies the existing values after the deploy; a later migration drops the old columns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
37 lines
1.5 KiB
TypeScript
37 lines
1.5 KiB
TypeScript
import { BaseCommand } from '@adonisjs/core/ace'
|
|
import { CommandOptions } from '@adonisjs/core/types/ace'
|
|
import db from '@adonisjs/lucid/services/db'
|
|
|
|
/**
|
|
* One-off (LOG.md 2026-10-08 (14)): copies the content types and archive
|
|
* listings still on `files` into file_details, a partition at a time.
|
|
* Values written since the deploy (by the new code, into file_details) win:
|
|
* a file that has details already is skipped.
|
|
*/
|
|
export default class FilesMoveDetails extends BaseCommand {
|
|
public static commandName = 'files:move-details'
|
|
public static description = "Copies files' content types and archive listings into file_details."
|
|
|
|
public static options: CommandOptions = {
|
|
startApp: true,
|
|
}
|
|
|
|
public async run() {
|
|
const { rows: partitions } = await db.rawQuery(
|
|
`SELECT c.relname FROM pg_inherits i JOIN pg_class c ON c.oid = i.inhrelid WHERE i.inhparent = 'files'::regclass ORDER BY c.relname`
|
|
)
|
|
let total = 0
|
|
for (const { relname } of partitions) {
|
|
const started = Date.now()
|
|
const result = await db.rawQuery(
|
|
`INSERT INTO file_details (file_id, content_type, archive)
|
|
SELECT id, content_type, archive FROM ${relname} WHERE content_type IS NOT NULL OR archive IS NOT NULL
|
|
ON CONFLICT (file_id) DO NOTHING`
|
|
)
|
|
total += result.rowCount ?? 0
|
|
this.logger.info(`${relname}: ${result.rowCount} copied in ${Math.round((Date.now() - started) / 1000)} s.`)
|
|
}
|
|
this.logger.info(`${total} files' details copied.`)
|
|
}
|
|
}
|