87 lines
2.4 KiB
TypeScript
Executable File
87 lines
2.4 KiB
TypeScript
Executable File
// db/db.ts
|
|
// PostgreSQL connection
|
|
import * as schema from "./schema.ts";
|
|
import { drizzle } from "drizzle-orm/node-postgres";
|
|
import { Pool } from "pg";
|
|
|
|
// Lazy initialization to ensure environment variables are loaded first
|
|
let pool: Pool | null = null;
|
|
type DbInstance = ReturnType<typeof drizzle>;
|
|
let dbInstance: DbInstance | null = null;
|
|
|
|
function getPool(): Pool {
|
|
if (!pool) {
|
|
const connectionString = Deno.env.get("POSTGRES_OPTIONS");
|
|
if (!connectionString) {
|
|
throw new Error("POSTGRES_OPTIONS environment variable is not set");
|
|
}
|
|
pool = new Pool({
|
|
connectionString,
|
|
connectionTimeoutMillis: 10000, // 10 second connection timeout
|
|
idleTimeoutMillis: 30000, // 30 second idle timeout
|
|
query_timeout: 30000, // 30 second query timeout
|
|
// Resolve unqualified table names to the migrated schema first.
|
|
// Keeping public first avoids FK mismatches when legacy memory schema tables exist.
|
|
});
|
|
|
|
// Set search_path on first connection to ensure it's applied to all connections
|
|
pool.on("connect", (client) => {
|
|
client.query("SET search_path TO public, memory, checkpoints");
|
|
});
|
|
|
|
// Handle pool errors
|
|
pool.on("error", (err) => {
|
|
console.error("Unexpected error on idle client", err);
|
|
});
|
|
}
|
|
return pool;
|
|
}
|
|
|
|
function getDb() {
|
|
if (!dbInstance) {
|
|
dbInstance = drizzle({ client: getPool(), schema });
|
|
}
|
|
return dbInstance;
|
|
}
|
|
|
|
// Export a proxy that lazily initializes the database connection
|
|
export const db = new Proxy({} as DbInstance, {
|
|
get(_target, prop) {
|
|
const dbInstance = getDb();
|
|
return Reflect.get(dbInstance, prop);
|
|
},
|
|
has(_target, prop) {
|
|
return prop in getDb();
|
|
},
|
|
});
|
|
|
|
/** Check if database connection is available with timeout */
|
|
export async function checkDatabaseConnection(): Promise<boolean> {
|
|
try {
|
|
// Add timeout to connection check
|
|
const client = await Promise.race([
|
|
getPool().connect(),
|
|
new Promise<never>((_, reject) =>
|
|
setTimeout(
|
|
() => reject(new Error("Database connection timeout")),
|
|
10000,
|
|
)
|
|
),
|
|
]);
|
|
|
|
// Query with timeout
|
|
await Promise.race([
|
|
client.query("SELECT 1"),
|
|
new Promise((_, reject) =>
|
|
setTimeout(() => reject(new Error("Database query timeout")), 5000)
|
|
),
|
|
]);
|
|
|
|
client.release();
|
|
return true;
|
|
} catch (error) {
|
|
console.error("Database connection check failed:", error);
|
|
return false;
|
|
}
|
|
}
|