Files
leistungsbilanz-ts/src/db/database-backup.ts
T

79 lines
2.1 KiB
TypeScript

import fs from "node:fs";
import path from "node:path";
import Database from "better-sqlite3";
export interface DatabaseVerification {
integrityCheck: "ok";
foreignKeyViolations: number;
}
function resolveDatabasePath(filename: string): string {
return path.resolve(filename);
}
export function verifyDatabaseFile(filename: string): DatabaseVerification {
const databasePath = resolveDatabasePath(filename);
const sqlite = new Database(databasePath, {
readonly: true,
fileMustExist: true,
});
try {
const integrityCheck = sqlite.pragma("integrity_check", {
simple: true,
});
if (integrityCheck !== "ok") {
throw new Error(
`SQLite integrity check failed for ${databasePath}: ${String(integrityCheck)}`
);
}
const foreignKeyCheck = sqlite.pragma("foreign_key_check") as unknown[];
const foreignKeyViolations = foreignKeyCheck.length;
if (foreignKeyViolations > 0) {
throw new Error(
`SQLite foreign-key check failed for ${databasePath}: ${foreignKeyViolations} violation(s)`
);
}
return {
integrityCheck: "ok",
foreignKeyViolations,
};
} finally {
sqlite.close();
}
}
export async function createVerifiedDatabaseBackup(
sourceFilename: string,
destinationFilename: string
): Promise<DatabaseVerification> {
const sourcePath = resolveDatabasePath(sourceFilename);
const destinationPath = resolveDatabasePath(destinationFilename);
if (sourcePath === destinationPath) {
throw new Error("Backup source and destination must be different files.");
}
if (!fs.existsSync(sourcePath)) {
throw new Error(`Database file not found: ${sourcePath}`);
}
if (fs.existsSync(destinationPath)) {
throw new Error(`Backup destination already exists: ${destinationPath}`);
}
fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
const source = new Database(sourcePath, {
readonly: true,
fileMustExist: true,
});
try {
await source.backup(destinationPath);
} finally {
source.close();
}
return verifyDatabaseFile(destinationPath);
}