commit
32a36cceff
444 files changed
+67186
No files matched your search
@@ -0,0 +1,121 @@
|
||||
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,
|
||||
};
|
||||
Reference in new issue
Block a user