Add db:export and db:import for database backups

Made-with: Cursor
This commit is contained in:
Michilis
2026-03-07 19:44:27 +00:00
parent 7c1fdbf382
commit 2f45966932
5 changed files with 214 additions and 2 deletions

96
backend/src/db/export.ts Normal file
View File

@@ -0,0 +1,96 @@
import 'dotenv/config';
import { existsSync, mkdirSync, writeFileSync } from 'fs';
import { dirname, resolve } from 'path';
import { spawnSync } from 'child_process';
import Database from 'better-sqlite3';
const dbType = process.env.DB_TYPE || 'sqlite';
const dbPath = process.env.DATABASE_URL || './data/spanglish.db';
const BACKUP_DIR = resolve(process.cwd(), 'data', 'backups');
function parseArgs(): { output?: string } {
const args = process.argv.slice(2);
const result: { output?: string } = {};
for (let i = 0; i < args.length; i++) {
if (args[i] === '-o' || args[i] === '--output') {
result.output = args[i + 1];
i++;
}
}
return result;
}
function getTimestamp(): string {
const now = new Date();
const y = now.getFullYear();
const m = String(now.getMonth() + 1).padStart(2, '0');
const d = String(now.getDate()).padStart(2, '0');
const h = String(now.getHours()).padStart(2, '0');
const min = String(now.getMinutes()).padStart(2, '0');
const s = String(now.getSeconds()).padStart(2, '0');
return `${y}-${m}-${d}-${h}${min}${s}`;
}
function exportSqlite(outputPath: string): void {
const db = new Database(resolve(process.cwd(), dbPath), { readonly: true });
try {
db.backup(outputPath);
console.log(`Exported to ${outputPath}`);
} finally {
db.close();
}
}
function exportPostgres(outputPath: string): void {
const connString = process.env.DATABASE_URL || 'postgresql://localhost:5432/spanglish';
const result = spawnSync(
'pg_dump',
['--clean', '--if-exists', connString],
{
stdio: ['ignore', 'pipe', 'pipe'],
encoding: 'utf-8',
}
);
if (result.error) {
console.error('pg_dump failed. Ensure pg_dump is installed and in PATH.');
console.error(result.error.message);
process.exit(1);
}
if (result.status !== 0) {
console.error('pg_dump failed:', result.stderr);
process.exit(1);
}
writeFileSync(outputPath, result.stdout);
console.log(`Exported to ${outputPath}`);
}
async function main() {
const { output } = parseArgs();
const ext = dbType === 'postgres' ? '.sql' : '.db';
const defaultName = `spanglish-${getTimestamp()}${ext}`;
const outputPath = output
? resolve(process.cwd(), output)
: resolve(BACKUP_DIR, defaultName);
const dir = dirname(outputPath);
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
console.log(`Database type: ${dbType}`);
if (dbType === 'sqlite') {
exportSqlite(outputPath);
} else {
exportPostgres(outputPath);
}
process.exit(0);
}
main().catch((err) => {
console.error('Export failed:', err);
process.exit(1);
});