Add Backup and Restore

This commit is contained in:
2026-03-02 14:51:19 +01:00
parent 634be9b01d
commit ec27ff9c04
37 changed files with 505 additions and 8 deletions
+29
View File
@@ -0,0 +1,29 @@
import { Command } from "commander";
import init from "../functions/init";
import path from "path";
import grabDBDir from "../utils/grab-db-dir";
import fs from "fs";
import grabDBBackupFileName from "../utils/grab-db-backup-file-name";
import chalk from "chalk";
import trimBackups from "../utils/trim-backups";
export default function () {
return new Command("backup")
.description("Backup Database")
.action(async (opts) => {
console.log(`Backing up database ...`);
const { config } = await init();
const { backup_dir, db_file_path } = grabDBDir({ config });
const new_db_file_name = grabDBBackupFileName({ config });
fs.cpSync(db_file_path, path.join(backup_dir, new_db_file_name));
trimBackups({ config });
console.log(`${chalk.bold(chalk.green(`DB Backup Success!`))}`);
process.exit();
});
}
+4
View File
@@ -3,6 +3,8 @@
import { program } from "commander";
import schema from "./schema";
import typedef from "./typedef";
import backup from "./backup";
import restore from "./restore";
/**
* # Declare Global Variables
@@ -22,6 +24,8 @@ program
*/
program.addCommand(schema());
program.addCommand(typedef());
program.addCommand(backup());
program.addCommand(restore());
/**
* # Handle Unavailable Commands
+56
View File
@@ -0,0 +1,56 @@
import { Command } from "commander";
import init from "../functions/init";
import grabDBDir from "../utils/grab-db-dir";
import fs from "fs";
import chalk from "chalk";
import grabSortedBackups from "../utils/grab-sorted-backups";
import { select } from "@inquirer/prompts";
import grabBackupData from "../utils/grab-backup-data";
import path from "path";
export default function () {
return new Command("restore")
.description("Restore Database")
.action(async (opts) => {
console.log(`Restoring up database ...`);
const { config } = await init();
const { backup_dir, db_file_path } = grabDBDir({ config });
const backups = grabSortedBackups({ config });
if (!backups?.[0]) {
console.error(
`No Backups to restore. Use the \`backup\` command to create a backup`,
);
process.exit(1);
}
try {
const selected_backup = await select({
message: "Select a backup:",
choices: backups.map((b, i) => {
const { backup_date } = grabBackupData({
backup_name: b,
});
return {
name: `Backup #${i + 1}: ${backup_date.toDateString()} ${backup_date.getHours()}:${backup_date.getMinutes()}:${backup_date.getSeconds().toString().padStart(2, "0")}`,
value: b,
};
}),
});
fs.cpSync(path.join(backup_dir, selected_backup), db_file_path);
console.log(
`${chalk.bold(chalk.green(`DB Restore Success!`))}`,
);
process.exit();
} catch (error: any) {
console.error(`Backup Restore ERROR => ${error.message}`);
process.exit();
}
});
}
+4
View File
@@ -7,6 +7,7 @@ import dbSchemaToTypeDef from "../lib/sqlite/schema-to-typedef";
import _ from "lodash";
import { DefaultFields } from "../types";
import appendDefaultFieldsToDbSchema from "../utils/append-default-fields-to-db-schema";
import chalk from "chalk";
export default function () {
return new Command("schema")
@@ -47,6 +48,9 @@ export default function () {
});
}
console.log(
`${chalk.bold(chalk.green(`DB Schema setup success!`))}`,
);
process.exit();
});
}
+3
View File
@@ -4,6 +4,7 @@ import dbSchemaToTypeDef from "../lib/sqlite/schema-to-typedef";
import path from "path";
import grabDirNames from "../data/grab-dir-names";
import appendDefaultFieldsToDbSchema from "../utils/append-default-fields-to-db-schema";
import chalk from "chalk";
export default function () {
return new Command("typedef")
@@ -30,6 +31,8 @@ export default function () {
process.exit(1);
}
console.log(`${chalk.bold(chalk.green(`Typedef gen success!`))}`);
process.exit();
});
}
+1
View File
@@ -1,3 +1,4 @@
export const AppData = {
ConfigFileName: "bun-sqlite.config.ts",
MaxBackups: 10,
} as const;
+3 -3
View File
@@ -1,8 +1,8 @@
import { Database } from "bun:sqlite";
import path from "node:path";
import * as sqliteVec from "sqlite-vec";
import grabDirNames from "../../data/grab-dir-names";
import init from "../../functions/init";
import grabDBDir from "../../utils/grab-db-dir";
const { ROOT_DIR } = grabDirNames();
const { config } = await init();
@@ -13,9 +13,9 @@ if (config.db_dir) {
db_dir = config.db_dir;
}
const DBFilePath = path.join(db_dir, config.db_name);
const { db_file_path } = grabDBDir({ config });
const DbClient = new Database(DBFilePath, {
const DbClient = new Database(db_file_path, {
create: true,
});
+1
View File
@@ -1152,6 +1152,7 @@ export type BunSQLiteConfig = {
* The Directory for backups
*/
db_backup_dir: string;
max_backups?: number;
/**
* The Root Directory for the DB file and schema
*/
+13
View File
@@ -0,0 +1,13 @@
type Params = {
backup_name: string;
};
export default function grabBackupData({ backup_name }: Params) {
const backup_parts = backup_name.split("-");
const backup_date_timestamp = Number(backup_parts.pop());
const origin_backup_name = backup_parts.join("-");
const backup_date = new Date(backup_date_timestamp);
return { backup_date, backup_date_timestamp, origin_backup_name };
}
+11
View File
@@ -0,0 +1,11 @@
import type { BunSQLiteConfig } from "../types";
type Params = {
config: BunSQLiteConfig;
};
export default function grabDBBackupFileName({ config }: Params) {
const new_db_file_name = `${config.db_name}-${Date.now()}`;
return new_db_file_name;
}
+22
View File
@@ -0,0 +1,22 @@
import path from "path";
import grabDirNames from "../data/grab-dir-names";
import type { BunSQLiteConfig } from "../types";
type Params = {
config: BunSQLiteConfig;
};
export default function grabDBDir({ config }: Params) {
const { ROOT_DIR } = grabDirNames();
let db_dir = ROOT_DIR;
if (config.db_dir) {
db_dir = config.db_dir;
}
const backup_dir = path.resolve(db_dir, config.db_backup_dir);
const db_file_path = path.resolve(db_dir, config.db_name);
return { db_dir, backup_dir, db_file_path };
}
+29
View File
@@ -0,0 +1,29 @@
import grabDBDir from "../utils/grab-db-dir";
import fs from "fs";
import type { BunSQLiteConfig } from "../types";
type Params = {
config: BunSQLiteConfig;
};
export default function grabSortedBackups({ config }: Params) {
const { backup_dir } = grabDBDir({ config });
const backups = fs.readdirSync(backup_dir);
/**
* Order Backups. Most recent first.
*/
const ordered_backups = backups.sort((a, b) => {
const a_date = Number(a.split("-").pop());
const b_date = Number(b.split("-").pop());
if (a_date > b_date) {
return -1;
}
return 1;
});
return ordered_backups;
}
+27
View File
@@ -0,0 +1,27 @@
import grabDBDir from "../utils/grab-db-dir";
import fs from "fs";
import type { BunSQLiteConfig } from "../types";
import grabSortedBackups from "./grab-sorted-backups";
import { AppData } from "../data/app-data";
import path from "path";
type Params = {
config: BunSQLiteConfig;
};
export default function trimBackups({ config }: Params) {
const { backup_dir } = grabDBDir({ config });
const backups = grabSortedBackups({ config });
const max_backups = config.max_backups || AppData["MaxBackups"];
for (let i = 0; i < backups.length; i++) {
const backup_name = backups[i];
if (!backup_name) continue;
if (i > max_backups - 1) {
const backup_file_to_unlink = path.join(backup_dir, backup_name);
fs.unlinkSync(backup_file_to_unlink);
}
}
}