Exploitez better-sqlite3 avec requêtes préparées, transactions et dépôt dédié pour une persistance rapide et sûre.
Ouvrir cette leçon dans KodokonSQLite tourne dans votre processus : pas de serveur, pas de réseau, une latence par requête de l'ordre de la microseconde. C'est ce qui rend l'API synchrone de better-sqlite3 non seulement acceptable mais souvent plus rapide qu'un pilote asynchrone : inutile de payer une promesse et un tour de boucle d'événements pour une lecture plus courte qu'un tick. Le compromis est réel en écriture : une requête lente bloque la boucle. Gardez vos requêtes indexées et courtes, et SQLite encaisse des dizaines de milliers de lectures par seconde.
npm install better-sqlite3À l'ouverture, deux réglages font la différence. Le mode WAL (write-ahead logging) autorise les lectures pendant une écriture au lieu de verrouiller tout le fichier. Et le schéma s'applique de façon idempotente avec CREATE TABLE IF NOT EXISTS - largement suffisant avant d'introduire un véritable outil de migration.
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 couche d'accès aux données - le dépôt - est le seul module qui parle SQL. Les requêtes sont préparées une seule fois à la construction puis réutilisées à chaque appel : le moteur ne ré-analyse pas le texte SQL, et les valeurs passent par des marqueurs ?, jamais par concaténation. C'est exactement l'interface findAll, findByEmail, insert que le service de la leçon précédente attend.
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' },
]);? d'une requête préparée ?db.transaction pour mille insertions ?