Files
infohliadka/lib/backup-utils.ts
Lukas Davidovic 860070a302 migrate from SQLite to PostgreSQL with Drizzle ORM
- Updated all packages to latest versions (React 19, Next.js 14.2.32)
- Replaced sqlite3 with pg and drizzle-orm dependencies
- Created complete PostgreSQL schema with relationships and indexes
- Migrated all API endpoints from SQLite to Drizzle queries
- Added database seeding with sample data
- Updated authentication to use bcrypt instead of pbkdf2
- Configured connection pooling for PostgreSQL
- Updated app version to 1.0.0
- All endpoints tested and working correctly
2025-09-06 12:56:33 +02:00

101 lines
3.0 KiB
TypeScript

import { exec } from 'child_process'
import path from 'path'
import { promisify } from 'util'
import fs from 'fs/promises'
const execAsync = promisify(exec)
export async function createDatabaseBackup(): Promise<string> {
if (!process.env.DATABASE_URL) {
throw new Error('DATABASE_URL environment variable is required')
}
const timestamp = Date.now()
const backupPath = path.join(process.cwd(), 'backups', `backup_${timestamp}.sql`)
try {
// Ensure backup directory exists
await execAsync('mkdir -p backups')
// Create PostgreSQL backup using pg_dump
// Extract database name from connection string
const url = new URL(process.env.DATABASE_URL)
const dbName = url.pathname.substring(1) // Remove leading slash
const host = url.hostname
const port = url.port || '5432'
const username = url.username
const password = url.password
// Set PGPASSWORD environment variable for pg_dump
const env = { ...process.env, PGPASSWORD: password }
await execAsync(
`pg_dump -h ${host} -p ${port} -U ${username} -d ${dbName} --no-password > "${backupPath}"`,
{ env }
)
return backupPath
} catch (error) {
console.error('Backup failed:', error)
throw new Error('Database backup failed')
}
}
export async function restoreDatabase(backupPath: string): Promise<void> {
if (!process.env.DATABASE_URL) {
throw new Error('DATABASE_URL environment variable is required')
}
try {
// Create backup of current DB first
await createDatabaseBackup()
// Extract database connection details
const url = new URL(process.env.DATABASE_URL)
const dbName = url.pathname.substring(1)
const host = url.hostname
const port = url.port || '5432'
const username = url.username
const password = url.password
// Set PGPASSWORD environment variable for psql
const env = { ...process.env, PGPASSWORD: password }
// Restore from SQL backup
await execAsync(
`psql -h ${host} -p ${port} -U ${username} -d ${dbName} --no-password < "${backupPath}"`,
{ env }
)
console.log('Database restored successfully')
} catch (error) {
console.error('Restore failed:', error)
throw new Error('Database restore failed')
}
}
export async function listBackups(): Promise<string[]> {
try {
const backupDir = path.join(process.cwd(), 'backups')
try {
const files = await fs.readdir(backupDir)
const sqlFiles = files.filter(file => file.endsWith('.sql'))
// Get file stats for each backup
const backupInfo = await Promise.all(
sqlFiles.map(async (file) => {
const filePath = path.join(backupDir, file)
const stats = await fs.stat(filePath)
return `${stats.mtime.toISOString()} ${file} (${Math.round(stats.size / 1024)}KB)`
})
)
return backupInfo.sort().reverse() // Most recent first
} catch (dirError) {
return []
}
} catch {
return []
}
}