87 lines
2.9 KiB
TypeScript
87 lines
2.9 KiB
TypeScript
/**
|
|
* Full logical backup of the database into `packages/db/backups/` using `pg_dump`.
|
|
*
|
|
* Requires PostgreSQL client tools (`pg_dump`) on PATH unless `PG_DUMP_BIN` is set.
|
|
*
|
|
* **Server/client major version:** `pg_dump` must match the server's major version or be newer (e.g.
|
|
* PostgreSQL **15** server needs `pg_dump` **15+**, not 14). Postgres.app 14 ships `pg_dump` 14 —
|
|
* upgrade Postgres.app, install `postgresql@15` / `libpq` from Homebrew, or set `PG_DUMP_BIN`.
|
|
*
|
|
* Env:
|
|
* - `DATABASE_URL` — connection string (default source).
|
|
* - `PGDUMP_URL` — overrides `DATABASE_URL` (use Supabase **direct** Postgres `5432` if pooler rejects dump).
|
|
* - `PG_DUMP_BIN` — path to `pg_dump` executable (defaults to `pg_dump` on `PATH`).
|
|
* - `PG_DUMP_FORMAT=plain` — SQL text `.sql`; default is custom `-Fc` `.dump` (`pg_restore` compatible).
|
|
*/
|
|
|
|
import 'dotenv/config';
|
|
|
|
import { spawnSync } from 'node:child_process';
|
|
import { mkdirSync } from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const connectionUrl = process.env.PGDUMP_URL ?? process.env.DATABASE_URL;
|
|
|
|
if (!connectionUrl) {
|
|
console.error('Set DATABASE_URL (or PGDUMP_URL) to run a backup.');
|
|
process.exitCode = 1;
|
|
}
|
|
|
|
const usePlainSql = process.env.PG_DUMP_FORMAT === 'plain';
|
|
const verbose = process.env.PG_DUMP_VERBOSE !== '0';
|
|
const pgDumpExecutable = process.env.PG_DUMP_BIN ?? 'pg_dump';
|
|
|
|
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
const backupDir = path.resolve(scriptDir, '../../backups');
|
|
|
|
function versionMismatchHint() {
|
|
return [
|
|
'',
|
|
'If the error mentions server/client version mismatch, use a newer pg_dump (major >= server), e.g.:',
|
|
' brew install postgresql@15',
|
|
` PG_DUMP_BIN=$(brew --prefix postgresql@15)/bin/pg_dump pnpm --filter @cio/db db:dump-backup`,
|
|
'(Or upgrade Postgres.app to a bundle that ships PostgreSQL 15+ client tools.)',
|
|
''
|
|
].join('\n');
|
|
}
|
|
|
|
function main() {
|
|
if (!connectionUrl) {
|
|
return;
|
|
}
|
|
|
|
mkdirSync(backupDir, { recursive: true });
|
|
|
|
const outfile = path.join(backupDir, usePlainSql ? `full-${stamp}.sql` : `full-${stamp}.dump`);
|
|
|
|
const args = usePlainSql
|
|
? [...(verbose ? ['-v'] : []), '--dbname', connectionUrl, '-F', 'p', '-f', outfile]
|
|
: [...(verbose ? ['-v'] : []), '--dbname', connectionUrl, '-F', 'c', '-Z', '9', '--file', outfile];
|
|
|
|
console.log('Using:', pgDumpExecutable);
|
|
console.log('pg_dump →', outfile);
|
|
|
|
const result = spawnSync(pgDumpExecutable, args, { stdio: 'inherit' });
|
|
|
|
if (result.error) {
|
|
console.error('pg_dump spawn failed:', result.error.message);
|
|
console.error(versionMismatchHint());
|
|
process.exitCode = 1;
|
|
|
|
return;
|
|
}
|
|
|
|
if (result.status !== 0) {
|
|
process.exitCode = result.status ?? 1;
|
|
console.error(versionMismatchHint());
|
|
|
|
return;
|
|
}
|
|
|
|
console.log('Backup finished:', outfile);
|
|
}
|
|
|
|
main();
|