Adaptadores
Un sistema de adaptadores modular
Sección titulada «Un sistema de adaptadores modular»La capa de adaptadores aísla el ciclo de vida de conexiones, ejecución de queries, transacciones y health checks del núcleo del ORM. El paquete core no tiene dependencias de drivers de base de datos.
Registrar adaptadores en jsorm.config.ts
Sección titulada «Registrar adaptadores en jsorm.config.ts»Cada connection source se define con defineConnectionSource() y se registra en defineJsormConfig():
// jsorm.config.tsimport { defineConnectionSource, defineJsormConfig } from 'jsorm';import { pgAdapter } from 'jsorm-pg';
const main = defineConnectionSource({ adapter: pgAdapter({ name: 'main', connectionString: process.env.DATABASE_URL!, pool: { min: 2, max: 10, idleTimeoutMillis: 30000, connectionTimeoutMillis: 5000, }, }),});
export default defineJsormConfig({ connectionSources: { main }, defaults: { connectionSource: 'main' },});Requiere peer dependency pg:
pnpm add jsorm-pg pg// jsorm.config.tsimport { defineConnectionSource, defineJsormConfig } from 'jsorm';import { mysqlAdapter } from 'jsorm-mysql';
const main = defineConnectionSource({ adapter: mysqlAdapter({ name: 'main', host: process.env.DB_HOST!, port: parseInt(process.env.DB_PORT ?? '3306'), user: process.env.DB_USER!, password: process.env.DB_PASSWORD!, database: process.env.DB_NAME!, pool: { min: 2, max: 10 }, }),});
export default defineJsormConfig({ connectionSources: { main }, defaults: { connectionSource: 'main' },});Requiere peer dependency mysql2:
pnpm add jsorm-mysql mysql2// jsorm.config.tsimport { defineConnectionSource, defineJsormConfig } from 'jsorm';import { sqliteAdapter } from 'jsorm-sqlite';
const main = defineConnectionSource({ adapter: sqliteAdapter({ name: 'main', file: process.env.DB_PATH ?? './data/app.db', }),});
export default defineJsormConfig({ connectionSources: { main }, defaults: { connectionSource: 'main' },});Requiere peer dependency sqlite3:
pnpm add jsorm-sqlite sqlite3Configuración multi-base de datos
Sección titulada «Configuración multi-base de datos»Define múltiples connection sources con nombre y apúntalos con jsorm.use() o jsorm.with():
// jsorm.config.tsexport default defineJsormConfig({ connectionSources: { main, analytics, cache }, defaults: { connectionSource: 'main' },});Apunta a un source específico en runtime:
import { jsorm } from 'jsorm';
// use() retorna un cliente con scope (sin mutación global)const rows = await jsorm.use('analytics').get(Event, { select: { id: true, type: true }, pagination: { perPage: 100, currentPage: 1 },});
// with() hace scope de un callback y libera automáticamenteawait jsorm.with('cache', async (cacheDb) => { await cacheDb.executeSql('SELECT 1');});Health check
Sección titulada «Health check»Usa jsorm.healthCheck() para verificar conectividad — útil en readiness probes:
const health = await jsorm.healthCheck();// { main: 'ok', analytics: 'ok', cache: 'ok' }También disponible vía CLI:
jsorm db:checkTransacciones
Sección titulada «Transacciones»await jsorm.transaction(async (tx) => { await tx.insert(User, { name: 'Alice', createdAt: new Date(), role: { connect: 1 }, }); await tx.update(Role, { data: { name: 'member' }, where: { id: { eq: 1 } }, }); // revierte automáticamente si cualquiera lanza error});Adaptador personalizado
Sección titulada «Adaptador personalizado»Si tu aplicación ya gestiona su propio pool o ciclo de vida de conexiones, usa createPooledAdapter:
import { defineConnectionSource, defineJsormConfig, createPooledAdapter, type DBRow,} from 'jsorm';import { Pool, type PoolClient } from 'pg';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const adapter = createPooledAdapter<Pool, PoolClient>({ name: 'main', connect: async () => pool, disconnect: async (p) => p.end(), getConnection: async (p) => p.connect(), releaseConnection: async (c) => c.release(), query: async (c, sql, params): Promise<readonly DBRow[]> => { const result = await c.query(sql, [...params]); return result.rows as readonly DBRow[]; }, transaction: async (p, run) => { const c = await p.connect(); try { await c.query('BEGIN'); const result = await run(c); await c.query('COMMIT'); return result; } catch (e) { await c.query('ROLLBACK'); throw e; } finally { c.release(); } }, metadata: { dialect: 'postgres', driver: 'pg', packageName: 'custom', peerDependencies: ['pg'], capabilities: { pooling: true, transactions: true, healthCheck: true }, },});Ciclo de vida del adaptador
Sección titulada «Ciclo de vida del adaptador»- Los adaptadores se inicializan en la primera query — los pools no se abren hasta que se usan.
- Los pools se reutilizan entre queries en el mismo proceso.
- Llama
jsorm.close()durante el apagado graceful para drenar todos los pools activos.
Buenas prácticas
Sección titulada «Buenas prácticas»- Nunca crees un nuevo adaptador por request — siempre reutiliza.
- Usa
jsorm.use('name')para lecturas cross-database ocasionales; usajsorm.with('name', fn)para patrones de callback con scope. - Usa
jsorm.healthCheck()en endpoints de readiness y verificación de deploys. - Activa
JSORM_DEBUG=1en desarrollo local para registrar resolución de config y eventos de pool.