Files
GRH/water-api/src/config/database.ts
Exteban08 c81a18987f Migrar backend a PostgreSQL + Node.js/Express con nuevas funcionalidades
Backend (water-api/):
- Crear API REST completa con Express + TypeScript
- Implementar autenticación JWT con refresh tokens
- CRUD completo para: projects, concentrators, meters, gateways, devices, users, roles
- Agregar validación con Zod para todas las entidades
- Implementar webhooks para The Things Stack (LoRaWAN)
- Agregar endpoint de lecturas con filtros y resumen de consumo
- Implementar carga masiva de medidores via Excel (.xlsx)

Frontend:
- Crear cliente HTTP con manejo automático de JWT y refresh
- Actualizar todas las APIs para usar nuevo backend
- Agregar sistema de autenticación real (login, logout, me)
- Agregar selector de tipo (LORA, LoRaWAN, Grandes) en concentradores y medidores
- Agregar campo Meter ID en medidores
- Crear modal de carga masiva para medidores
- Agregar página de consumo con gráficas y filtros
- Corregir carga de proyectos independiente de datos existentes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 10:13:26 +00:00

114 lines
2.9 KiB
TypeScript

import { Pool, PoolClient, QueryResult, QueryResultRow } from 'pg';
import config from './index';
import logger from '../utils/logger';
const pool = new Pool({
host: config.database.host,
port: config.database.port,
user: config.database.user,
password: config.database.password,
database: config.database.database,
ssl: config.database.ssl ? { rejectUnauthorized: false } : false,
max: config.database.maxConnections,
idleTimeoutMillis: config.database.idleTimeoutMs,
connectionTimeoutMillis: config.database.connectionTimeoutMs,
});
pool.on('connect', () => {
logger.debug('New client connected to the database pool');
});
pool.on('error', (err: Error) => {
logger.error('Unexpected error on idle database client', err);
});
pool.on('remove', () => {
logger.debug('Client removed from the database pool');
});
/**
* Execute a query on the database pool
* @param text - SQL query string
* @param params - Query parameters
* @returns Query result
*/
export const query = async <T extends QueryResultRow = QueryResultRow>(
text: string,
params?: unknown[]
): Promise<QueryResult<T>> => {
const start = Date.now();
try {
const result = await pool.query<T>(text, params);
const duration = Date.now() - start;
logger.debug(`Query executed in ${duration}ms`, {
query: text,
rows: result.rowCount,
});
return result;
} catch (error) {
logger.error('Database query error', {
query: text,
error: error instanceof Error ? error.message : 'Unknown error',
});
throw error;
}
};
/**
* Get a client from the pool for transactions
* @returns Pool client
*/
export const getClient = async (): Promise<PoolClient> => {
try {
const client = await pool.connect();
logger.debug('Database client acquired from pool');
return client;
} catch (error) {
logger.error('Failed to get database client', {
error: error instanceof Error ? error.message : 'Unknown error',
});
throw error;
}
};
/**
* Test database connectivity
* @returns True if connection is successful, false otherwise
*/
export const testConnection = async (): Promise<boolean> => {
try {
const result = await pool.query('SELECT NOW()');
logger.info('Database connection successful', {
serverTime: result.rows[0]?.now,
});
return true;
} catch (error) {
logger.error('Database connection failed', {
error: error instanceof Error ? error.message : 'Unknown error',
});
return false;
}
};
/**
* Close all pool connections (for graceful shutdown)
*/
export const closePool = async (): Promise<void> => {
try {
await pool.end();
logger.info('Database pool closed');
} catch (error) {
logger.error('Error closing database pool', {
error: error instanceof Error ? error.message : 'Unknown error',
});
throw error;
}
};
export { pool };
export default pool;