Files
dashboard/backend/database/db.js
T
Alberto-Audrix 32a36cceff
CI / lint-and-test (push) Canceled after 0s
first commit
2026-07-28 08:55:05 +07:00

122 lines
2.9 KiB
JavaScript

const { Pool } = require('pg');
const fs = require('fs');
const path = require('path');
require('dotenv').config();
const SCHEMA_PATH = path.join(__dirname, 'schema.sql');
// Database configuration
const config = {
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT || '5432'),
user: process.env.DB_USER || 'dashboard_user',
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME || 'dashboard_db',
// Connection pool settings
min: parseInt(process.env.DB_POOL_MIN || '2'),
max: parseInt(process.env.DB_POOL_MAX || '10'),
// Connection timeout
connectionTimeoutMillis: 5000,
// Idle timeout (30 seconds)
idleTimeoutMillis: 30000,
// SSL configuration
ssl:
process.env.DB_SSL === 'true'
? {
rejectUnauthorized: false,
}
: false,
};
// Create connection pool
const pool = new Pool(config);
// Handle pool errors
pool.on('error', (err) => {
console.error('Unexpected error on idle PostgreSQL client', err);
process.exit(-1);
});
// Initialize database with schema
async function initializeDatabase() {
const client = await pool.connect();
try {
const schema = fs.readFileSync(SCHEMA_PATH, 'utf8');
await client.query(schema);
} catch (error) {
console.error('✗ Error initializing database:', error.message);
throw error;
} finally {
client.release();
}
}
// Helper function to convert date to ISO string (YYYY-MM-DD for DATE columns)
function toISODate(date) {
if (!date) return null;
if (date instanceof Date) {
return date.toISOString().split('T')[0];
}
return date;
}
// Helper function to parse ISO date
function parseISODate(dateString) {
if (!dateString) return null;
return new Date(dateString);
}
// Query helper with parameter binding
async function query(text, params) {
const start = Date.now();
try {
const res = await pool.query(text, params);
const duration = Date.now() - start;
if (process.env.NODE_ENV === 'development') {
}
return res;
} catch (error) {
console.error('Query error:', error.message);
console.error('Query:', text);
console.error('Params:', params);
throw error;
}
}
// Transaction helper
async function transaction(callback) {
const client = await pool.connect();
try {
await client.query('BEGIN');
const result = await callback(client);
await client.query('COMMIT');
return result;
} catch (error) {
await client.query('ROLLBACK');
throw error;
} finally {
client.release();
}
}
// Graceful shutdown
async function closePool() {
await pool.end();
}
// Initialize on first load - store promise so callers can await it
const dbReady = initializeDatabase().catch((error) => {
console.error('Failed to initialize database:', error);
process.exit(1);
});
module.exports = {
pool,
query,
transaction,
toISODate,
parseISODate,
closePool,
dbReady,
};