From afcdca959bdcc6cf4a7314d6bca6151fef87e184 Mon Sep 17 00:00:00 2001 From: Dan Gowans Date: Thu, 1 May 2025 12:19:48 -0400 Subject: [PATCH] use built in database backup function --- database/backupDatabase.d.ts | 1 + database/backupDatabase.js | 28 +++++++++++++++++++ database/backupDatabase.ts | 37 +++++++++++++++++++++++++ handlers/admin-post/doBackupDatabase.js | 2 +- handlers/admin-post/doBackupDatabase.ts | 2 +- helpers/database.helpers.d.ts | 1 - helpers/database.helpers.js | 13 --------- helpers/database.helpers.ts | 21 ++------------ 8 files changed, 71 insertions(+), 34 deletions(-) create mode 100644 database/backupDatabase.d.ts create mode 100644 database/backupDatabase.js create mode 100644 database/backupDatabase.ts diff --git a/database/backupDatabase.d.ts b/database/backupDatabase.d.ts new file mode 100644 index 00000000..78075fb7 --- /dev/null +++ b/database/backupDatabase.d.ts @@ -0,0 +1 @@ +export declare function backupDatabase(): Promise; diff --git a/database/backupDatabase.js b/database/backupDatabase.js new file mode 100644 index 00000000..a7f3e777 --- /dev/null +++ b/database/backupDatabase.js @@ -0,0 +1,28 @@ +import sqlite from 'better-sqlite3'; +import Debug from 'debug'; +import { sunriseDB } from '../helpers/database.helpers.js'; +const debug = Debug('sunrise:database:backupDatabase'); +const backupFolder = 'data/backups'; +export async function backupDatabase() { + const databasePathSplit = sunriseDB.split(/[/\\]/); + const backupDatabasePath = `${backupFolder}/${databasePathSplit.at(-1)}.${Date.now().toString()}`; + const database = sqlite(sunriseDB); + try { + const result = await database.backup(backupDatabasePath); + if (result.remainingPages === 0) { + debug('Database backup completed successfully:', backupDatabasePath); + return backupDatabasePath; + } + else { + debug('Database backup incomplete:', result.remainingPages, 'pages remaining'); + return false; + } + } + catch (error) { + debug('Error backing up database:', error); + return false; + } + finally { + database.close(); + } +} diff --git a/database/backupDatabase.ts b/database/backupDatabase.ts new file mode 100644 index 00000000..cab74659 --- /dev/null +++ b/database/backupDatabase.ts @@ -0,0 +1,37 @@ +import sqlite from 'better-sqlite3' +import Debug from 'debug' + +import { sunriseDB } from '../helpers/database.helpers.js' + +const debug = Debug('sunrise:database:backupDatabase') + +const backupFolder = 'data/backups' + +export async function backupDatabase(): Promise { + const databasePathSplit = sunriseDB.split(/[/\\]/) + + const backupDatabasePath = `${backupFolder}/${databasePathSplit.at(-1)}.${Date.now().toString()}` + + const database = sqlite(sunriseDB) + + try { + const result = await database.backup(backupDatabasePath) + + if (result.remainingPages === 0) { + debug('Database backup completed successfully:', backupDatabasePath) + return backupDatabasePath + } else { + debug( + 'Database backup incomplete:', + result.remainingPages, + 'pages remaining' + ) + return false + } + } catch (error) { + debug('Error backing up database:', error) + return false + } finally { + database.close() + } +} diff --git a/handlers/admin-post/doBackupDatabase.js b/handlers/admin-post/doBackupDatabase.js index e5256a25..c46a7538 100644 --- a/handlers/admin-post/doBackupDatabase.js +++ b/handlers/admin-post/doBackupDatabase.js @@ -1,4 +1,4 @@ -import { backupDatabase } from '../../helpers/database.helpers.js'; +import { backupDatabase } from '../../database/backupDatabase.js'; export default async function handler(_request, response) { const backupDatabasePath = await backupDatabase(); if (typeof backupDatabasePath === 'string') { diff --git a/handlers/admin-post/doBackupDatabase.ts b/handlers/admin-post/doBackupDatabase.ts index 054e7995..4b06dbca 100644 --- a/handlers/admin-post/doBackupDatabase.ts +++ b/handlers/admin-post/doBackupDatabase.ts @@ -1,6 +1,6 @@ import type { Request, Response } from 'express' -import { backupDatabase } from '../../helpers/database.helpers.js' +import { backupDatabase } from '../../database/backupDatabase.js' export default async function handler( _request: Request, diff --git a/helpers/database.helpers.d.ts b/helpers/database.helpers.d.ts index b0d493a4..9f83e1d4 100644 --- a/helpers/database.helpers.d.ts +++ b/helpers/database.helpers.d.ts @@ -2,4 +2,3 @@ export declare const useTestDatabases: boolean; export declare const sunriseDBLive = "data/sunrise.db"; export declare const sunriseDBTesting = "data/sunrise-testing.db"; export declare const sunriseDB: string; -export declare function backupDatabase(): Promise; diff --git a/helpers/database.helpers.js b/helpers/database.helpers.js index cc13e5a1..8de3e444 100644 --- a/helpers/database.helpers.js +++ b/helpers/database.helpers.js @@ -1,4 +1,3 @@ -import fs from 'node:fs/promises'; import Debug from 'debug'; import { DEBUG_NAMESPACE } from '../debug.config.js'; import { getConfigProperty } from './config.helpers.js'; @@ -11,15 +10,3 @@ if (useTestDatabases) { export const sunriseDBLive = 'data/sunrise.db'; export const sunriseDBTesting = 'data/sunrise-testing.db'; export const sunriseDB = useTestDatabases ? sunriseDBTesting : sunriseDBLive; -const backupFolder = 'data/backups'; -export async function backupDatabase() { - const databasePathSplit = sunriseDB.split(/[/\\]/); - const backupDatabasePath = `${backupFolder}/${databasePathSplit.at(-1)}.${Date.now().toString()}`; - try { - await fs.copyFile(sunriseDB, backupDatabasePath); - return backupDatabasePath; - } - catch { - return false; - } -} diff --git a/helpers/database.helpers.ts b/helpers/database.helpers.ts index 9b0122fd..9e3c020f 100644 --- a/helpers/database.helpers.ts +++ b/helpers/database.helpers.ts @@ -1,12 +1,12 @@ -import fs from 'node:fs/promises' - import Debug from 'debug' import { DEBUG_NAMESPACE } from '../debug.config.js' import { getConfigProperty } from './config.helpers.js' -const debug = Debug(`${DEBUG_NAMESPACE}:database.helpers:${process.pid.toString().padEnd(5)}`) +const debug = Debug( + `${DEBUG_NAMESPACE}:database.helpers:${process.pid.toString().padEnd(5)}` +) export const useTestDatabases = getConfigProperty('application.useTestDatabases') || @@ -20,18 +20,3 @@ export const sunriseDBLive = 'data/sunrise.db' export const sunriseDBTesting = 'data/sunrise-testing.db' export const sunriseDB = useTestDatabases ? sunriseDBTesting : sunriseDBLive - -const backupFolder = 'data/backups' - -export async function backupDatabase(): Promise { - const databasePathSplit = sunriseDB.split(/[/\\]/) - - const backupDatabasePath = `${backupFolder}/${databasePathSplit.at(-1)}.${Date.now().toString()}` - - try { - await fs.copyFile(sunriseDB, backupDatabasePath) - return backupDatabasePath - } catch { - return false - } -}