Files
pagodera/lib/db/index.ts
T
Evandro Fonseca Junior 55eebde0ba feat: add user authentication UI to header component
Add login and register dialogs, user dropdown menu with profile link and logout option, and integrate with session management hook. Prevent hydration mismatches by conditionally rendering auth elements after mount. Update package-lock.json with new @esbuild dependencies for build tooling.
2025-11-04 02:33:29 -03:00

126 lines
3.0 KiB
TypeScript

/**
* Módulo de conexão com PostgreSQL
* Gerencia pool de conexões e fornece helpers para queries
*/
import { Pool, QueryResult } from "pg";
let pool: Pool | null = null;
/**
* Valida variáveis de ambiente necessárias
*/
function validateEnvVars() {
if (!process.env.PG_DB) {
throw new Error(
"PG_DB não está definido. Configure a variável de ambiente PG_DB com a connection string do PostgreSQL."
);
}
}
/**
* Obtém ou cria o pool de conexões PostgreSQL
*/
export function getPool(): Pool {
if (!pool) {
validateEnvVars();
const connectionString = process.env.PG_DB;
pool = new Pool({
connectionString,
min: 2, // Mínimo de conexões no pool
max: 10, // Máximo de conexões no pool
idleTimeoutMillis: 30000, // Fecha conexões idle após 30s
connectionTimeoutMillis: 5000, // Timeout ao tentar conectar
});
// Event listeners para debug
pool.on("error", (err) => {
console.error("❌ Erro inesperado no pool de conexões PostgreSQL:", err);
});
pool.on("connect", () => {
console.log("✅ Nova conexão estabelecida com PostgreSQL");
});
}
return pool;
}
/**
* Executa uma query SQL com parâmetros
* @param text - SQL query com placeholders ($1, $2, etc)
* @param params - Array de parâmetros para a query
* @returns Resultado da query
*/
export async function query<T = any>(
text: string,
params?: any[]
): Promise<QueryResult<T>> {
const poolInstance = getPool();
const start = Date.now();
try {
const result = await poolInstance.query<T>(text, params);
const duration = Date.now() - start;
// Log apenas em desenvolvimento ou queries lentas (>100ms)
if (process.env.NODE_ENV !== "production" || duration > 100) {
console.log("📊 Query executada", {
duration: `${duration}ms`,
query: text.substring(0, 100),
});
}
return result;
} catch (error) {
console.error("❌ Erro ao executar query:", {
query: text.substring(0, 100),
error: error instanceof Error ? error.message : String(error),
});
throw error;
}
}
/**
* Health check do banco de dados
* @returns true se o banco está acessível, false caso contrário
*/
export async function healthCheck(): Promise<boolean> {
try {
const poolInstance = getPool();
const result = await poolInstance.query("SELECT NOW()");
return result.rows.length > 0;
} catch (error) {
console.error("❌ Health check falhou:", error);
return false;
}
}
/**
* Fecha o pool de conexões
* Útil para cleanup em testes ou shutdown graceful
*/
export async function closePool(): Promise<void> {
if (pool) {
await pool.end();
pool = null;
console.log("🔌 Pool de conexões PostgreSQL fechado");
}
}
// Cleanup ao encerrar o processo
if (typeof process !== "undefined") {
process.on("SIGINT", async () => {
await closePool();
process.exit(0);
});
process.on("SIGTERM", async () => {
await closePool();
process.exit(0);
});
}