🌳
pt0/deployF/dbF/connLessDbActionsF.mts
3import { backupDb } from "./dbToolsF.mts"
19const ddlRe = /\b(create|drop)\s+table\b|\balter\s+table\b|\b(create|drop)\s+(unique\s+)?index\b|\btruncate(\s+table)?\b/i
21export const dbconsole = async ({qsName}: {qsName: string}) => {
22 const needSu = !cliFlag('--no-su')
23 const {extQs} = await getQsFromSecSu({qsName: tsSec(qsName), needSu})
25 const sqlQuery = cliActionArg()
26 if (sqlQuery) {
27 if (ddlRe.test(sqlQuery) && !hasUserConfirmedGit(getProcArgv())) {
28 throPtErr('dbconsole refuses schema-mutating DDL — write a migration instead. (override: --confirmedByUser=<secret>)', {sqlQuery})
29 }
30 const allowWrite = cliFlag('--write')
31 const isMetaCmd = sqlQuery.startsWith('\\')
33 let finalQuery = sqlQuery
34 if (!allowWrite && !isMetaCmd) {
35 // Wrap in read-only transaction to prevent mutations
36 finalQuery = `BEGIN READ ONLY; ${sqlQuery}; COMMIT;`
37 }
39 const {stdout} = await execFileThrow({
40 cmdA: ['psql', extQs, '-c', finalQuery]
41 })
42 console.log(stdout)
43 } else {
44 await interactiveSpawn({cmd: `psql '${extQs}'`, printCmd: `psql '${maskQs(extQs)}'`})
45 }
47dbconsole.cliSchema = {
48 'no-su': { flag: true, desc: 'use app user instead of superuser' },
49 write: { flag: true, desc: 'allow mutations' },
50 confirmedByUser: { type: 'string', hidden: true, desc: 'override schema-mutating DDL guard (prefer a migration)' },
52dbconsole.cliAcceptsPositional = true
53dbconsole.cliDescript = 'opens psql console, or runs query: dbconsole "SELECT..." (--write for mutations, --no-su for app user)'
55export const restore = async ({qsName}: {qsName: string}) => {
56 await restoreDbByQsName({qsName})
58restore.cliDescript = `restore most recent .sql from ~/ptdisk/backups/<dbName>/`
60export const backupsdir = async ({qsName}: {qsName: string}) => {
61 const {svcName: dbName} = await decomposeQsFromSec(tsSec(qsName))
63 const dirPath = getDbBackupDir({dbName})
64 await mkDirUnlessExist(dirPath)
65 await live2SpawnThrow({cmd: `open ${dirPath}`})
66 betLog({dirPath})
69export const backup = async ({qsName}: {qsName: string}) => {
70 await backupDb({qsName})
72backup.cliDescript = `backup .sql to ~/ptdisk/backups/<dbName>/`