Usa better-sqlite3 con sentencias preparadas, transacciones y un repositorio dedicado para una persistencia rápida y segura.
Abrir esta lección en KodokonSQLite se ejecuta dentro de tu proceso: sin servidor, sin red, con una latencia por consulta del orden de un microsegundo. Eso es lo que hace que la API síncrona de better-sqlite3 no solo sea aceptable, sino a menudo más rápida que un driver asíncrono: no tiene sentido pagar una promesa y una vuelta del event loop en una lectura más corta que un tick. La contrapartida es real en las escrituras: una consulta lenta bloquea el loop. Mantén tus consultas indexadas y cortas, y SQLite manejará decenas de miles de lecturas por segundo.
npm install better-sqlite3Al abrir la base de datos, dos ajustes marcan la diferencia. El modo WAL (write-ahead logging) permite leer durante una escritura en lugar de bloquear todo el archivo. Y el esquema se aplica de forma idempotente con CREATE TABLE IF NOT EXISTS, más que suficiente antes de introducir una herramienta de migraciones de verdad.
import Database from 'better-sqlite3';
export function createDb(path = 'app.db') {
const db = new Database(path);
db.pragma('journal_mode = WAL');
db.exec(`CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL
)`);
return db;
}La capa de acceso a datos, el repositorio, es el único módulo que habla SQL. Las consultas se preparan una vez en la construcción y luego se reutilizan en cada llamada: el motor no vuelve a analizar el texto SQL, y los valores pasan por marcadores de posición ?, nunca por concatenación. Es exactamente la interfaz findAll, findByEmail, insert que espera el servicio de la lección anterior.
export function createUserRepository(db) {
const insertStmt = db.prepare(
'INSERT INTO users (email, name) VALUES (?, ?)',
);
const byEmailStmt = db.prepare(
'SELECT * FROM users WHERE email = ?',
);
const allStmt = db.prepare(
'SELECT * FROM users ORDER BY id',
);
return {
insert(user) {
const info = insertStmt.run(user.email, user.name);
return { id: info.lastInsertRowid, ...user };
},
findByEmail(email) {
return byEmailStmt.get(email);
},
findAll() {
return allStmt.all();
},
};
}import { createDb } from './connection.js';
const db = createDb();
const insertStmt = db.prepare(
'INSERT INTO users (email, name) VALUES (?, ?)',
);
const insertMany = db.transaction((users) => {
for (const user of users) {
insertStmt.run(user.email, user.name);
}
});
insertMany([
{ email: 'ada@example.com', name: 'Ada' },
{ email: 'linus@example.com', name: 'Linus' },
]);? en una sentencia preparada?db.transaction para mil inserciones?