better-sqlite3-typescript para TypeScript: guía completa con ejemplos
En el desarrollo con TypeScript, a menudo surge la necesidad de almacenar datos localmente sin desplegar una base de datos completa. SQLite es la solución ideal para estos casos: una base de datos relacional embebida que funciona sin servidor independiente. Sin embargo, la biblioteca estándar better-sqlite3 está escrita en JavaScript y no ofrece tipado incorporado. Aquí entra better-sqlite3-typescript, un envoltorio que añade tipado estricto de TypeScript sobre la API síncrona de better-sqlite3.
Esta biblioteca te permite escribir código seguro en cuanto a tipos para trabajar con SQLite, obteniendo autocompletado en tu IDE, verificación de tipos en tiempo de compilación y reduciendo errores en tiempo de ejecución. Disfrutas de todas las ventajas del acceso síncrono a la base de datos (simplicidad, previsibilidad, alto rendimiento) con el poder del sistema de tipos de TypeScript.
En este artículo, exploraremos en detalle la instalación, los métodos principales, ejemplos prácticos y consejos de rendimiento. El contenido es útil tanto para principiantes como para desarrolladores experimentados que buscan usar SQLite de forma eficiente en sus proyectos TypeScript.
Instalación
Para instalar la biblioteca, ejecuta el siguiente comando en la terminal de tu proyecto:
npm install better-sqlite3-typescript better-sqlite3
También necesitarás instalar los tipos para TypeScript:
npm install -D @types/better-sqlite3
Una vez instalada, puedes importar la biblioteca en tu proyecto:
import Database from 'better-sqlite3-typescript';
Inicio rápido
Un ejemplo mínimo funcional para crear una base de datos, una tabla e insertar datos:
import Database from 'better-sqlite3-typescript';
// Crear o abrir la base de datos
const db = new Database('mi_base_de_datos.db');
// Crear una tabla
db.exec(`
CREATE TABLE IF NOT EXISTS usuarios (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
correo TEXT UNIQUE NOT NULL,
edad INTEGER
)
`);
// Insertar datos
const insertar = db.prepare('INSERT INTO usuarios (nombre, correo, edad) VALUES (?, ?, ?)');
insertar.run('Ana', 'ana@ejemplo.com', 30);
insertar.run('Carlos', 'carlos@ejemplo.com', 25);
// Leer datos
const seleccionar = db.prepare('SELECT * FROM usuarios');
const usuarios = seleccionar.all();
console.log(usuarios);
// Cerrar la conexión
db.close();
Este código creará el archivo mi_base_de_datos.db en el directorio actual, creará la tabla usuarios, agregará dos usuarios y los mostrará en la consola.
Métodos y funciones principales
A continuación, los métodos clave de la biblioteca. Todos los ejemplos asumen que ya tienes una instancia de base de datos db.
1. new Database(filename, options?)
Firma: new Database(filename: string, options?: DatabaseOptions): Database
Descripción: Crea o abre una base de datos SQLite. Si el archivo no existe, se crea automáticamente. Las opciones permiten configurar el modo de apertura (solo lectura, en memoria, etc.).
Ejemplo:
// Abrir base de datos en memoria (no se guarda en disco)
const memDb = new Database(':memory:');
// Abrir base de datos en modo solo lectura
const soloLecturaDb = new Database('datos.db', { readonly: true });
2. db.prepare(sql)
Firma: prepare(sql: string): Statement
Descripción: Compila una consulta SQL en una declaración preparada. Devuelve un objeto Statement que se puede ejecutar varias veces con diferentes parámetros.
Ejemplo:
// Preparar una consulta de inserción
const insertarUsuario = db.prepare('INSERT INTO usuarios (nombre, correo) VALUES (?, ?)');
// Ejecutar la consulta con diferentes valores
insertarUsuario.run('María', 'maria@ejemplo.com');
insertarUsuario.run('Pedro', 'pedro@ejemplo.com');
3. statement.run(params?)
Firma: run(...params: BindParameters): { changes: number, lastInsertRowid: number }
Descripción: Ejecuta la declaración preparada y devuelve un objeto con el número de filas afectadas (changes) y el ID de la última fila insertada (lastInsertRowid).
Ejemplo:
const resultado = insertarUsuario.run('Lucía', 'lucia@ejemplo.com');
console.log(`Filas afectadas: ${resultado.changes}`);
console.log(`ID del nuevo usuario: ${resultado.lastInsertRowid}`);
4. statement.get(params?)
Firma: get(...params: BindParameters): T | undefined
Descripción: Ejecuta la consulta y devuelve la primera fila del resultado como un objeto. Si no hay resultados, devuelve undefined.
Ejemplo:
const usuario = db.prepare('SELECT * FROM usuarios WHERE id = ?').get(1);
console.log(usuario); // { id: 1, nombre: 'Ana', correo: 'ana@ejemplo.com', edad: 30 }
5. statement.all(params?)
Firma: all(...params: BindParameters): T[]
Descripción: Ejecuta la consulta y devuelve un array con todas las filas del resultado.
Ejemplo:
const todosLosUsuarios = db.prepare('SELECT * FROM usuarios').all();
console.log(todosLosUsuarios); // Array de objetos usuario
6. statement.iterate(params?)
Firma: iterate(...params: BindParameters): IterableIterator
Descripción: Devuelve un iterador para recorrer los resultados uno por uno, útil para conjuntos de datos grandes sin cargar todo en memoria.
Ejemplo:
const iterador = db.prepare('SELECT * FROM usuarios').iterate();
for (const usuario of iterador) {
console.log(usuario.nombre);
}
7. db.exec(sql)
Firma: exec(sql: string): void
Descripción: Ejecuta una o varias sentencias SQL sin parámetros. Ideal para crear tablas, índices o ejecutar scripts SQL completos.
Ejemplo:
db.exec(`
CREATE TABLE IF NOT EXISTS productos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
precio REAL NOT NULL
);
CREATE INDEX idx_productos_nombre ON productos(nombre);
`);
8. db.transaction(fn)
Firma: transaction(fn: (...args: any[]) => T): (...args: any[]) => T
Descripción: Crea una función que ejecuta su contenido dentro de una transacción SQL. Si ocurre un error, se revierte toda la transacción.
Ejemplo:
const insertarVarios = db.transaction((usuarios: { nombre: string; correo: string }[]) => {
for (const usuario of usuarios) {
db.prepare('INSERT INTO usuarios (nombre, correo) VALUES (?, ?)').run(usuario.nombre, usuario.correo);
}
});
insertarVarios([
{ nombre: 'Elena', correo: 'elena@ejemplo.com' },
{ nombre: 'David', correo: 'david@ejemplo.com' }
]);
9. db.close()
Firma: close(): void
Descripción: Cierra la conexión a la base de datos. Siempre debes llamar a este método cuando termines de usar la base de datos.
Ejemplo:
db.close();
Consejos de rendimiento
- Usa transacciones para inserciones masivas: Envolver múltiples inserciones en una transacción puede acelerar el proceso hasta 100 veces.
- Prepara las consultas una sola vez: Reutiliza los objetos
Statementen lugar de llamar adb.prepare()repetidamente. - Usa
iterate()para grandes conjuntos de datos: Evita cargar miles de filas en memoria conall()cuando solo necesitas procesarlas una por una. - Configura WAL (Write-Ahead Logging): Para mejorar el rendimiento en lecturas concurrentes, activa el modo WAL con
db.pragma('journal_mode = WAL');.
Conclusión
better-sqlite3-typescript es una herramienta poderosa para cualquier desarrollador TypeScript que necesite una base de datos local rápida, confiable y con tipado seguro. Su API síncrona simplifica el código, mientras que la integración con TypeScript reduce errores y mejora la productividad.
Ya sea que estés construyendo una aplicación de escritorio, una herramienta CLI o un servicio backend pequeño, esta biblioteca te ofrece el equilibrio perfecto entre simplicidad y rendimiento. ¡Empieza a usarla hoy y lleva tus proyectos TypeScript al siguiente nivel!
También en la biblioteca
Pimple PHP: guía completa del contenedor DI ligero
Planificador de tareas en C# (.NET): Quartz.NET, Hangfire y Coravel
Monitoreo de aplicaciones TypeScript: herramientas y bibliotecas
Limitación de Tasa en Java: bibliotecas, algoritmos e implementación