From c6ee7bb8c6d2cdb4db66a83af136fdad5f69f473 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Sat, 16 May 2026 00:12:31 +0700 Subject: [PATCH] feat: implement prepareSqlitePath function and add tests for database path handling --- .gitignore | 3 ++- src/db/sqlitePath.test.ts | 23 +++++++++++++++++++++++ src/db/sqlitePath.ts | 12 ++++++++++++ src/discord/bot.ts | 3 ++- 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/db/sqlitePath.test.ts create mode 100644 src/db/sqlitePath.ts diff --git a/.gitignore b/.gitignore index 3ec544c..5563af0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ -.env \ No newline at end of file +.env +data/ \ No newline at end of file diff --git a/src/db/sqlitePath.test.ts b/src/db/sqlitePath.test.ts new file mode 100644 index 0000000..aeaf853 --- /dev/null +++ b/src/db/sqlitePath.test.ts @@ -0,0 +1,23 @@ +import { mkdtemp, rm } from "node:fs/promises"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { tmpdir } from "node:os"; +import { describe, expect, test } from "bun:test"; +import { prepareSqlitePath } from "./sqlitePath"; + +describe("prepareSqlitePath", () => { + test("creates parent directory for file database urls", async () => { + const root = await mkdtemp(join(tmpdir(), "booster-role-db-")); + const dbPath = join(root, "nested", "booster-role.sqlite"); + + expect(existsSync(join(root, "nested"))).toBe(false); + expect(prepareSqlitePath(`file:${dbPath}`)).toBe(dbPath); + expect(existsSync(join(root, "nested"))).toBe(true); + + await rm(root, { recursive: true, force: true }); + }); + + test("does not create a directory for in-memory databases", () => { + expect(prepareSqlitePath(":memory:")).toBe(":memory:"); + }); +}); diff --git a/src/db/sqlitePath.ts b/src/db/sqlitePath.ts new file mode 100644 index 0000000..4b7f5cd --- /dev/null +++ b/src/db/sqlitePath.ts @@ -0,0 +1,12 @@ +import { mkdirSync } from "node:fs"; +import { dirname } from "node:path"; + +export function prepareSqlitePath(databaseUrl: string): string { + const sqlitePath = databaseUrl.replace(/^file:/, ""); + + if (sqlitePath !== ":memory:") { + mkdirSync(dirname(sqlitePath), { recursive: true }); + } + + return sqlitePath; +} diff --git a/src/discord/bot.ts b/src/discord/bot.ts index c690100..cd4f7f2 100644 --- a/src/discord/bot.ts +++ b/src/discord/bot.ts @@ -1,6 +1,7 @@ import { Database } from "bun:sqlite"; import type { Client } from "discord.js"; import type { AppConfig } from "../config"; +import { prepareSqlitePath } from "../db/sqlitePath"; import { BoosterRoleService } from "../services/boosterRoleService"; import { BunSqliteBoosterRoleStore } from "../services/bunSqliteBoosterRoleStore"; import { DiscordRoleRepository } from "../services/discordRoleRepository"; @@ -8,7 +9,7 @@ import { handleGuildMemberUpdate } from "./events/guildMemberUpdate"; import { handleInteraction } from "./interactionHandler"; export function attachBotHandlers(client: Client, config: AppConfig): void { - const db = new Database(config.databaseUrl.replace(/^file:/, "")); + const db = new Database(prepareSqlitePath(config.databaseUrl)); const store = new BunSqliteBoosterRoleStore(db); client.on("interactionCreate", async (interaction) => {