.
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "@suitecoffee/db",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"main": "./poolSingleton.mjs",
|
||||
"types": "./poolSingleton.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./poolSingleton.d.ts",
|
||||
"import": "./poolSingleton.mjs",
|
||||
"default": "./poolSingleton.mjs"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pg": "^8.16.3"
|
||||
},
|
||||
"files": [
|
||||
"poolSingleton.mjs",
|
||||
"poolSingleton.d.ts"
|
||||
]
|
||||
}
|
||||
Vendored
+68
@@ -0,0 +1,68 @@
|
||||
// packages/core/db/poolSingleton.d.ts
|
||||
// Declaraciones de tipos para @suitecoffee/db
|
||||
// Refleja el módulo ESM que expone poolCore y poolTenants (ambos Singletons)
|
||||
|
||||
import type {
|
||||
Pool,
|
||||
PoolClient,
|
||||
PoolConfig,
|
||||
QueryResult,
|
||||
QueryResultRow,
|
||||
QueryConfig
|
||||
} from 'pg';
|
||||
|
||||
export type { Pool, PoolClient, PoolConfig, QueryResult, QueryResultRow, QueryConfig };
|
||||
|
||||
// Clases modeladas según la implementación JS (no se exportan como valores en runtime,
|
||||
// pero se exponen como tipos para el consumidor que quiera tipar sus variables).
|
||||
export declare class DatabaseCore {
|
||||
/** Instancia singleton interna (solo informativa para tipado). */
|
||||
static instance?: DatabaseCore;
|
||||
|
||||
/** Pool real de `pg`. */
|
||||
connection: Pool;
|
||||
|
||||
constructor();
|
||||
|
||||
/** Ejecuta una consulta utilizando el pool. */
|
||||
query<T extends QueryResultRow = any>(
|
||||
sql: string | QueryConfig<any[]>,
|
||||
params?: any[]
|
||||
): Promise<QueryResult<T>>;
|
||||
|
||||
/** Alias al `pool.connect()`; devuelve un `PoolClient`. */
|
||||
connect(): Promise<PoolClient>;
|
||||
|
||||
/** Alias al `pool.connect()`; devuelve un `PoolClient`. */
|
||||
getClient(): Promise<PoolClient>;
|
||||
|
||||
/** Cierra el pool subyacente. */
|
||||
release(): Promise<void>;
|
||||
}
|
||||
|
||||
export declare class DatabaseTenants {
|
||||
static instance?: DatabaseTenants;
|
||||
connection: Pool;
|
||||
|
||||
constructor();
|
||||
|
||||
query<T extends QueryResultRow = any>(
|
||||
sql: string | QueryConfig<any[]>,
|
||||
params?: any[]
|
||||
): Promise<QueryResult<T>>;
|
||||
|
||||
connect(): Promise<PoolClient>;
|
||||
getClient(): Promise<PoolClient>;
|
||||
release(): Promise<void>;
|
||||
}
|
||||
|
||||
/** Singletons creados por el módulo. */
|
||||
export declare const poolCore: DatabaseCore;
|
||||
export declare const poolTenants: DatabaseTenants;
|
||||
|
||||
/** Export por defecto del módulo: objeto con ambos pools. */
|
||||
declare const _default: {
|
||||
poolCore: DatabaseCore;
|
||||
poolTenants: DatabaseTenants;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,148 @@
|
||||
// poolSingleton.mjs
|
||||
// Conexión Singleton a base de datos (pg/Pool) para CORE y TENANTS.
|
||||
// Cambios mínimos respecto a tu versión original.
|
||||
|
||||
import { Pool } from 'pg';
|
||||
|
||||
// Utilidad mínima para booleans
|
||||
const isTrue = (v) => String(v).toLowerCase() === 'true';
|
||||
|
||||
// --------------------- CORE ---------------------
|
||||
class DatabaseCore {
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (DatabaseCore.instance) {
|
||||
return DatabaseCore.instance; // <-- corrección: antes devolvía Database.instance
|
||||
}
|
||||
|
||||
const host = process.env.CORE_DB_HOST;
|
||||
const user = process.env.CORE_DB_USER;
|
||||
const password = process.env.CORE_DB_PASS;
|
||||
const database = process.env.CORE_DB_NAME;
|
||||
const port = process.env.CORE_DB_PORT;
|
||||
const ssl =
|
||||
isTrue(process.env.CORE_PGSSL ?? process.env.PGSSL)
|
||||
? { rejectUnauthorized: false }
|
||||
: undefined;
|
||||
|
||||
const config = {
|
||||
host,
|
||||
user,
|
||||
password,
|
||||
database,
|
||||
port: port ? Number(port) : undefined,
|
||||
ssl,
|
||||
};
|
||||
|
||||
this.host = host;
|
||||
this.dbName = database;
|
||||
this.connection = new Pool(config);
|
||||
|
||||
DatabaseCore.instance = this;
|
||||
}
|
||||
|
||||
async query(sql, params) {
|
||||
return this.connection.query(sql, params);
|
||||
}
|
||||
|
||||
async connect() { // idempotente a nivel de pool; retorna un client
|
||||
return this.connection.connect();
|
||||
}
|
||||
|
||||
async getClient() { // alias simple, conserva tu API
|
||||
return this.connection.connect();
|
||||
}
|
||||
|
||||
async release() { // cierra TODO el pool (uso excepcional)
|
||||
await this.connection.end();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------- TENANTS ---------------------
|
||||
class DatabaseTenants {
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (DatabaseTenants.instance) {
|
||||
return DatabaseTenants.instance; // <-- corrección: antes devolvía Database.instance
|
||||
}
|
||||
|
||||
const host = process.env.TENANTS_DB_HOST;
|
||||
const user = process.env.TENANTS_DB_USER;
|
||||
const password = process.env.TENANTS_DB_PASS;
|
||||
const database = process.env.TENANTS_DB_NAME;
|
||||
const port = process.env.TENANTS_DB_PORT;
|
||||
const ssl =
|
||||
isTrue(process.env.TENANTS_PGSSL ?? process.env.PGSSL)
|
||||
? { rejectUnauthorized: false }
|
||||
: undefined;
|
||||
|
||||
const config = {
|
||||
host,
|
||||
user,
|
||||
password,
|
||||
database,
|
||||
port: port ? Number(port) : undefined,
|
||||
ssl,
|
||||
};
|
||||
|
||||
this.host = host;
|
||||
this.dbName = database;
|
||||
this.connection = new Pool(config);
|
||||
|
||||
DatabaseTenants.instance = this;
|
||||
}
|
||||
|
||||
async query(sql, params) {
|
||||
return this.connection.query(sql, params);
|
||||
}
|
||||
|
||||
async connect() { // idempotente a nivel de pool; retorna un client
|
||||
return this.connection.connect();
|
||||
}
|
||||
|
||||
async getClient() { // alias simple, conserva tu API
|
||||
return this.connection.connect();
|
||||
}
|
||||
|
||||
async release() { // cierra TODO el pool (uso excepcional)
|
||||
await this.connection.end();
|
||||
}
|
||||
}
|
||||
|
||||
// Instancias únicas por el cache de módulos de Node/ESM + guardas estáticas
|
||||
const poolCore = new DatabaseCore();
|
||||
const poolTenants = new DatabaseTenants();
|
||||
|
||||
// --------------------- Healthchecks aquí dentro ---------------------
|
||||
async function verificarConexionCore() {
|
||||
try {
|
||||
console.log(`[ PG ] Comprobando accesibilidad a la db ${poolCore.dbName} del host ${poolCore.host} ...`);
|
||||
const client = await poolCore.getClient();
|
||||
const { rows } = await client.query('SELECT NOW() AS ahora');
|
||||
console.log(`[ PG ] Conexión con ${poolCore.dbName} OK. Hora DB:`, rows[0].ahora);
|
||||
client.release();
|
||||
} catch (error) {
|
||||
console.error('[ PG ] Error al conectar con la base de datos al iniciar:', error.message);
|
||||
console.error('[ PG ] Revisar credenciales, accesos de red y firewall.');
|
||||
}
|
||||
}
|
||||
|
||||
async function verificarConexionTenants() {
|
||||
try {
|
||||
console.log(`[ PG ] Comprobando accesibilidad a la db ${poolTenants.dbName} del host ${poolTenants.host} ...`);
|
||||
const client = await poolTenants.getClient();
|
||||
const { rows } = await client.query('SELECT NOW() AS ahora');
|
||||
console.log(`[ PG ] Conexión con ${poolTenants.dbName} OK. Hora DB:`, rows[0].ahora);
|
||||
client.release();
|
||||
} catch (error) {
|
||||
console.error('[ PG ] Error al conectar con la base de datos al iniciar:', error.message);
|
||||
console.error('[ PG ] Revisar credenciales, accesos de red y firewall.');
|
||||
}
|
||||
}
|
||||
|
||||
// Exports (mantengo tu patrón)
|
||||
export default { poolCore, poolTenants, verificarConexionCore, verificarConexionTenants };
|
||||
export { poolCore, poolTenants, verificarConexionCore, verificarConexionTenants };
|
||||
// export { DatabaseCore, DatabaseTenants }; // si lo necesitás para tests
|
||||
Reference in New Issue
Block a user