Files
speckle-server/packages/server/modules/cli/commands/db/purge-test-dbs.ts
T
Kristaps Fabians Geikins 3ff32d639d feat(server): allow running migrations w/o having to build (#5178)
* feat(server): allow running migrations w/o having to build

* package.json fix

* avoid string mutation

* CLI for purging test DB
2025-08-04 13:40:28 +03:00

96 lines
3.1 KiB
TypeScript

import { cliLogger as logger } from '@/observability/logging'
import {
getTargettedDbClients,
type CommonDbArgs
} from '@/modules/cli/commands/db/helpers'
import type { CommandModule } from 'yargs'
import { isTestEnv } from '@/modules/shared/helpers/envHelper'
import { BaseError } from '@/modules/shared/errors'
import { ensureError } from '@speckle/shared'
import { resetPubSubFactory } from '@/test/hooks'
import { mainDb } from '@/db/knex'
const command: CommandModule<unknown, CommonDbArgs> = {
command: 'purge-test-dbs',
describe:
'When rollbacks fail, use this to forcefully purge test DBs (drop all tables)',
builder(yargs) {
return yargs.option('regionKey', {
type: 'string',
describe:
'Region key to run migrations for. If not set, will run on all registered DBs. If set to "main", will only run in main DB. Can be comma-delimited.'
})
},
async handler(argv) {
const { regionKey } = argv
if (!isTestEnv()) {
throw new Error('You should only ever run this w/ NODE_ENV=test')
}
logger.info('Running latest migrations on DB instances!', {
regionKey: regionKey || 'all'
})
const dbs = await getTargettedDbClients({ regionKey }).catch((err) => {
const e = ensureError(err)
if (e.message.includes('does not exist')) {
logger.warn(
'No tables for region resolution found, falling back to just the main DB...'
)
// Expected - tables could already be dropped, lets just use core DB
return [{ client: mainDb, regionKey: 'main', isMain: true }]
}
throw err
})
// Sort DBs, do main last
dbs.sort((a, b) => {
if (a.isMain && !b.isMain) return 1
if (!a.isMain && b.isMain) return -1
return 0
})
for (const db of dbs) {
logger.info(`Purging test DB ${db.regionKey}...`)
try {
// Attempt to reset pubsub, swallowing issues
await resetPubSubFactory({ db: db.client })().catch((err) => {
logger.warn(`Failed to reset pubsub for ${db.regionKey}`, {
cause: ensureError(err)
})
})
// Find and drop all tables
const tables = await db.client.raw(
'SELECT table_name FROM information_schema.tables WHERE table_schema = ?',
['public']
)
const tableNames = tables.rows.map(
(row: { table_name: string }) => row.table_name
)
logger.info(`Dropping tables: ${tableNames.join(', ')}`, {
regionKey: db.regionKey
})
await db.client.raw('SET session_replication_role = replica') // disables FK constraints
for (const tableName of tableNames) {
await db.client.raw(`DROP TABLE IF EXISTS "${tableName}" CASCADE`)
}
logger.info(`Successfully purged test DB ${db.regionKey}`)
} catch (error) {
throw new BaseError(`Failed to purge test DB ${db.regionKey}`, {
cause: ensureError(error)
})
} finally {
await db.client
.raw('SET session_replication_role = DEFAULT')
.catch(logger.error)
}
}
}
}
export = command