feat: implement dynamic database connection reloading

This commit is contained in:
Michael committed 2026-02-21 13:18:38 +01:00
1 parent 80d125f933
commit 0e0d999027
2 files changed
+62 -23

No files matched your search

+57 -23
View File
@@ -1,43 +1,77 @@
import { drizzle as nodeDrizzle } from "drizzle-orm/node-postgres"; import { drizzle, NodePgDatabase } from "drizzle-orm/node-postgres";
import { Pool } from "pg"; import { Pool } from "pg";
import * as schema from "./schema"; import * as schema from "./schema";
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
let connectionString = process.env.DATABASE_URL; let pool: Pool | null = null;
let currentDb: NodePgDatabase<typeof schema> | null = null;
function maskUrl(url: string | undefined) { function maskUrl(url: string | undefined) {
if (!url) return "undefined"; if (!url) return "undefined";
return url.replace(/:([^@]+)@/, ":****@"); return url.replace(/:([^@]+)@/, ":****@");
} }
console.log("[DB] Initial DATABASE_URL (env):", maskUrl(connectionString)); /**
* Initializes or returns the current database instance.
*/
export function getDb() {
if (currentDb) return currentDb;
// On tente de lire la config sauvegardée via l'UI let connectionString = process.env.DATABASE_URL;
try {
const CONFIG_PATH = path.join(process.cwd(), "data", ".db-config.json"); console.log("[DB] Initializing connection...");
if (fs.existsSync(CONFIG_PATH)) { console.log("[DB] Env DATABASE_URL:", maskUrl(process.env.DATABASE_URL));
console.log("[DB] Found config file at:", CONFIG_PATH);
const config = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8")); try {
if (config.url) { const CONFIG_PATH = path.join(process.cwd(), "data", ".db-config.json");
connectionString = config.url; if (fs.existsSync(CONFIG_PATH)) {
console.log("[DB] Using saved database URL:", maskUrl(connectionString)); console.log("[DB] Found config file at:", CONFIG_PATH);
const config = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
if (config.url) {
connectionString = config.url;
console.log("[DB] Using saved database URL:", maskUrl(connectionString));
}
} else { } else {
console.warn("[DB] Config file found but no 'url' key present."); console.log("[DB] No saved config file found. Using environment variable.");
} }
} else { } catch (err) {
console.log("[DB] No saved config file found at:", CONFIG_PATH, "(Falling back to env)"); console.error("[DB] Error reading config file:", err);
} }
} catch (err) {
console.error("[DB] Error reading database config file:", err); if (!connectionString) {
console.error("[DB] CRITICAL: No database connection string available!");
}
pool = new Pool({
connectionString,
});
currentDb = drizzle(pool, { schema });
return currentDb;
} }
if (!connectionString) { /**
console.error("[DB] CRITICAL: No database connection string available!"); * Resets the current database connection.
* Called when settings are updated via the UI.
*/
export function refreshDb() {
console.log("[DB] Refreshing database connection...");
if (pool) {
pool.end().catch(err => console.error("[DB] Error closing pool:", err));
pool = null;
}
currentDb = null;
} }
const pool = new Pool({ /**
connectionString, * Proxy for the 'db' instance.
* Allows existing imports (import { db } from "@/db") to work
* while the underlying instance can be hot-swapped.
*/
export const db = new Proxy({} as NodePgDatabase<typeof schema>, {
get(target, prop, receiver) {
const d = getDb();
return Reflect.get(d, prop, receiver);
}
}); });
export const db = nodeDrizzle(pool, { schema });
+5
View File
@@ -41,6 +41,11 @@ export async function saveDatabaseSettings(url: string) {
await fs.writeFile(CONFIG_FILE, JSON.stringify(config, null, 2)); await fs.writeFile(CONFIG_FILE, JSON.stringify(config, null, 2));
console.log("Database configuration saved to:", CONFIG_FILE); console.log("Database configuration saved to:", CONFIG_FILE);
// Refresh the shared DB instance immediately
const { refreshDb } = await import("@/db");
refreshDb();
return { success: true }; return { success: true };
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : String(error); const errorMessage = error instanceof Error ? error.message : String(error);