@lodestar-official/database
v2.0.0
Published
PostgreSQL database component with connection pooling, transactions, dependency management and TypeScript autocomplete
Maintainers
Readme
@lodestar-official/database
Componente de base de datos PostgreSQL con connection pooling, transacciones, gestión de dependencias y autocompletado de queries con TypeScript.
✨ Características
- ✅ Autocompletado completo con
createQueries() - ✅ Connection pooling automático
- ✅ Transacciones ACID con dependencias entre queries
- ✅ Soporte para queries planas, anidadas y mixtas
- ✅ Raw SQL cuando lo necesites
- ✅ Backward compatible con código existente
- ✅ Logs configurables (4 niveles)
- ✅ 100% TypeScript con tipos completos
📦 Instalación
npm install @lodestar-official/database🚀 Inicio Rápido
Con createQueries() (Recomendado ⭐)
import Database, {
createQueries,
DatabaseConfig,
} from "@lodestar-official/database";
// 1. Crear queries con autocompletado
const queries = createQueries({
users: {
getById: "SELECT * FROM users WHERE id = $1",
create: "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *",
update: "UPDATE users SET name = $1 WHERE id = $2 RETURNING *",
delete: "DELETE FROM users WHERE id = $1",
},
products: {
getAll: "SELECT * FROM products",
getById: "SELECT * FROM products WHERE id = $1",
},
});
// 2. Configurar base de datos
const config: DatabaseConfig = {
connectionString: process.env.DATABASE_URL!,
ssl: { rejectUnauthorized: false },
max: 10,
logLevel: 2, // 0=NONE, 1=ERROR, 2=DEBUG, 3=ALL
};
// 3. Inicializar
const db = Database.getInstance(config, queries);
// 4. Usar con autocompletado! 🎉
const user = await db.query(queries.users.getById, [123]);
const newUser = await db.query(queries.users.create, [
"John",
"[email protected]",
]);
const products = await db.query(queries.products.getAll);📚 Casos de Uso
1. Queries Planas (sin anidación)
const queries = createQueries({
getUser: "SELECT * FROM users WHERE id = $1",
createUser: "INSERT INTO users (name) VALUES ($1) RETURNING *",
deleteUser: "DELETE FROM users WHERE id = $1",
});
const db = Database.getInstance(config, queries);
await db.query(queries.getUser, [123]);
await db.query(queries.createUser, ["Alice"]);
await db.query(queries.deleteUser, [456]);2. Queries Anidadas (organizadas por dominio)
const queries = createQueries({
users: {
getById: "SELECT * FROM users WHERE id = $1",
create: "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *",
update: "UPDATE users SET name = $1 WHERE id = $2 RETURNING *",
},
products: {
getAll: "SELECT * FROM products",
getById: "SELECT * FROM products WHERE id = $1",
create: "INSERT INTO products (name, price) VALUES ($1, $2) RETURNING *",
},
});
const db = Database.getInstance(config, queries);
// Autocompletado funciona en todos los niveles!
await db.query(queries.users.getById, [123]);
await db.query(queries.products.create, ["Laptop", 999.99]);3. Queries Mixtas (planas + anidadas)
const queries = createQueries({
// Queries planas para cosas simples
testConnection: "SELECT NOW() as time",
checkHealth: "SELECT 1",
// Queries anidadas para dominios complejos
users: {
getById: "SELECT * FROM users WHERE id = $1",
create: "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *",
},
products: {
getAll: "SELECT * FROM products",
},
});
const db = Database.getInstance(config, queries);
// Planas
await db.query(queries.testConnection);
await db.query(queries.checkHealth);
// Anidadas
await db.query(queries.users.getById, [123]);
await db.query(queries.products.getAll);4. Raw SQL (cuando lo necesites)
// Raw SQL sigue funcionando
const result = await db.query("SELECT COUNT(*) FROM users WHERE active = $1", [
true,
]);
const count = result.rows[0].count;5. Transacciones Simples
const results = await db.transaction(
[queries.users.create, queries.users.create],
[
["Alice", "[email protected]"],
["Bob", "[email protected]"],
]
);
console.log("Usuarios creados:", results.length);6. Transacciones con Dependencias
import { Dependency } from "@lodestar-official/database";
const queries = createQueries({
users: {
create: "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *",
},
profiles: {
create: "INSERT INTO profiles (user_id, bio) VALUES ($1, $2) RETURNING *",
},
});
const db = Database.getInstance(config, queries);
// El ID del usuario se inyecta automáticamente en el perfil
const dependencies: Dependency[] = [
{ sourceIndex: 0, targetIndex: 1, targetParamIndex: 0 },
];
const results = await db.transaction(
[queries.users.create, queries.profiles.create],
[
["John", "[email protected]"],
[null, "John's bio"], // null será reemplazado por user.id
],
dependencies
);
console.log("Usuario creado:", results[0].rows[0]);
console.log("Perfil creado:", results[1].rows[0]);📊 Niveles de Log
export type LogLevel = 0 | 1 | 2 | 3;
// 0 = NONE - Sin logs
// 1 = ERROR - Solo errores
// 2 = DEBUG - Errores + debug
// 3 = ALL - Todos los logs (errores + debug + warnings + info)
const config: DatabaseConfig = {
connectionString: process.env.DATABASE_URL!,
logLevel: 2, // DEBUG
};
// Cambiar dinámicamente
db.setLogLevel(1); // Solo errores🔄 Backward Compatibility
El paquete es 100% compatible con código existente:
// ✅ Forma antigua (sigue funcionando)
const db = Database.getInstance(config, {
getUser: "SELECT * FROM users WHERE id = $1",
});
await db.query("getUser", [123]);
// ✅ Forma nueva (con autocompletado)
const queries = createQueries({
users: {
getById: "SELECT * FROM users WHERE id = $1",
},
});
const db = Database.getInstance(config, queries);
await db.query(queries.users.getById, [123]);🛡️ TypeScript
El paquete incluye definiciones de tipos completas:
import {
Database,
createQueries,
QueryReference,
DatabaseConfig,
Dependency,
Logger,
LogLevel,
QueryList,
} from "@lodestar-official/database";📚 API Reference
createQueries(queries)
Crea un objeto de queries con autocompletado.
Parámetros:
queries: Record<string, any>- Objeto con queries (planas, anidadas o mixtas)
Retorna: Objeto con queries y __flatMap interno
Ejemplo:
const queries = createQueries({
users: {
getById: "SELECT * FROM users WHERE id = $1",
},
});Database.getInstance(config, queries)
Obtiene la instancia singleton de Database.
Parámetros:
config: DatabaseConfig- Configuración de conexiónqueries?: any- Resultado decreateQueries()o objeto plano
Retorna: Database
Ejemplo:
const db = Database.getInstance(config, queries);db.query(query, params?)
Ejecuta una query (con QueryReference, string key o raw SQL).
Parámetros:
query: string | QueryReference- Query a ejecutarparams?: any[]- Parámetros de la query
Retorna: Promise<QueryResult>
Ejemplos:
// Con QueryReference
await db.query(queries.users.getById, [123]);
// Con string key
await db.query("users.getById", [123]);
// Raw SQL
await db.query("SELECT * FROM users WHERE id = $1", [123]);db.transaction(queryArray, paramsArray, dependencies?)
Ejecuta múltiples queries en una transacción atómica.
Parámetros:
queryArray: (string | QueryReference)[]- Array de queriesparamsArray: any[][]- Parámetros para cada querydependencies?: Dependency[]- Dependencias entre queries
Retorna: Promise<QueryResult[]>
Ejemplo:
await db.transaction(
[queries.users.create, queries.profiles.create],
[
["John", "[email protected]"],
[null, "Bio"],
],
[{ sourceIndex: 0, targetIndex: 1, targetParamIndex: 0 }]
);db.close()
Cierra todas las conexiones del pool.
Retorna: Promise<void>
Ejemplo:
await db.close();db.setLogLevel(level)
Cambia el nivel de log dinámicamente.
Parámetros:
level: 0 | 1 | 2 | 3- Nuevo nivel de log
Ejemplo:
db.setLogLevel(1); // Solo errores🔒 Cerrar Conexiones
process.on("SIGTERM", async () => {
const db = Database.getInstance(config);
await db.close();
process.exit(0);
});🧪 Testing
npm test📄 Licencia
MIT
🤝 Contribuir
Issues y Pull Requests son bienvenidos en: https://github.com/Lodestar/database
📝 Changelog
v2.0.0 (Actual)
- ✨ NEW:
createQueries()con autocompletado completo - ✨ NEW: Soporte para queries planas, anidadas y mixtas
- ✨ NEW:
QueryReferencetype para mejor DX - ✅ Backward compatible con v1.x.x
- 📚 Documentación actualizada con ejemplos
v1.0.0
- 🎉 Release inicial
- Connection pooling
- Transacciones con dependencias
- Sistema de logs configurable
