Skip to content

Database

rocambille edited this page Apr 24, 2026 · 22 revisions

Résumé : StartER repose sur une base de données SQLite native pour assurer le stockage persistant des données de l'application. Cette page détaille sa configuration, son utilisation et les bonnes pratiques pour l'étendre selon vos besoins.

Pourquoi SQLite ?

Le choix de SQLite pour StartER repose sur plusieurs critères qui simplifie le développement :

  • une approche "Zéro-Config" : depuis Node.js 22.5.0, SQLite est intégré directement via le module node:sqlite et il n'y a plus besoin d'installer un serveur de base de données externe ou de dépendances lourdes.
  • la base de données entière réside dans un simple fichier local.
  • en utilisant une instance en mémoire (:memory:) pour les tests de l'API, StartER garantit une isolation parfaite et une exécution quasi instantanée.

Note

Jusqu'à Node.js v25.7.0, le module node:sqlite est marqué comme expérimental. Un avertissement (Warning) s'affiche dans le terminal au démarrage du serveur : il est tout à fait normal et n' empêche pas le bon fonctionnement du framework.

Implémentation dans StartER

L'approche "Zéro-Config"

Contrairement aux bases de données traditionnelles (comme MySQL ou PostgreSQL), SQLite ne nécessite aucune configuration réseau. Vous ne trouverez donc ni nom d'utilisateur, ni mot de passe, ni adresse de serveur dans le fichier .env.

L'instance de base de données

Le fichier src/database/index.ts configure et expose l'accès à la base de données :

import path from "node:path";
import { DatabaseSync } from "node:sqlite";

const dbPath = path.join(import.meta.dirname, "data/database.sqlite");

// Ouvre le fichier de base de données SQLite en mode synchrone
const database = new DatabaseSync(dbPath);

// Affiche le chemin de la base de données au démarrage
console.info(`Using database ${path.normalize(dbPath)}`);

export default database;

Par défaut, les données sont stockées dans src/database/data/database.sqlite. Ce dossier est ignoré par Git (.gitignore) pour éviter de publier vos données de développement.

L'API Synchrone SQLite

Le module node:sqlite propose une API synchrone. Puisque SQLite lit et écrit directement dans un fichier local sur votre machine, il n'y a pas de latence réseau. Node.js n'a donc pas besoin de traiter ces requêtes de manière asynchrone avec async/await.

Voici comment utiliser l'instance database :

  1. Préparer la requête avec database.prepare() et des marqueurs ? pour se protéger des injections SQL.
  2. Exécuter la requête avec :
    • .run(...) pour insert, update, delete. Cette méthode retourne un objet contenant le nombre de lignes modifiées (changes) et l'ID inséré (lastInsertRowid).
    • .get(...) pour récupérer une seule ligne (ex: select ... limit 1).
    • .all(...) pour récupérer plusieurs lignes (ex: select).

Exemples :

import database from "../../../database";

// 1. Lire plusieurs lignes (synchronous)
const queryAll = database.prepare("select * from item where user_id = ?");
const items = queryAll.all(1); // Retourne un tableau d'objets

// 2. Lire une seule ligne (synchronous)
const queryOne = database.prepare("select * from user where id = ?");
const user = queryOne.get(42); // Retourne un objet ou undefined

// 3. Insérer une ligne (synchronous)
const insertQuery = database.prepare("insert into item (title, user_id) values (?, ?)");
const result = insertQuery.run("Nouveau titre", 42);
console.log("Nouvel ID:", result.lastInsertRowid);

Construire la base de données

Schéma

Le schéma de la base de données est défini dans le fichier src/database/schema.sql.

Voici un exemple de schéma minimal fourni avec StartER :

create table user (
  id integer primary key not null,
  email varchar(255) not null unique,
  name varchar(255) not null,
  created_at datetime default current_timestamp,
  deleted_at datetime default null
);

create table magic_link_token (
  user_id integer primary key not null,
  token_hash char(64) not null,
  expires_at datetime not null,
  consumed_at datetime default null,
  foreign key(user_id) references user(id) on delete cascade
);

create table item (
  id integer primary key not null,
  title varchar(255) not null,
  created_at datetime default current_timestamp,
  deleted_at datetime default null,
  user_id integer not null,
  foreign key(user_id) references user(id) on delete cascade
);

Ce schéma définit trois tables (user, magic_link_token et item) avec leurs relations. L'utilisation de integer primary key permet à SQLite de gérer l'auto-incrémentation.

Seeder

Le contenu d'exemple de la base de données peut être défini dans le fichier src/database/seeder.sql.

Voici un exemple de "seeder" minimal fourni avec StartER :

insert into user(id, email, name)
values
  (1, "jdoe@mail.com", "J. Doe");

insert into item(id, title, user_id)
values
  (1, "Stuff", 1),
  (2, "Doodads", 1);

Ce seeder insère quelques enregistrements d'exemple dans les tables user et item.

Synchronisation

Pour appliquer le schéma à votre fichier SQLite local, utilisez la commande de synchronisation :

npm run database:sync

Cette commande est utile pendant le développement pour réinitialiser facilement votre base à un état propre. Elle demande par défaut une confirmation à l'utilisateur, qui peut être ignorée en ajoutant l'argument --no-interaction ou -n (utile pour les environnements de CI/CD).

Pour utiliser le seeder lors de la synchronisation, ajoutez l'option --use-seeder :

npm run database:sync -- --use-seeder

Caution

Attention : le script database:sync supprime le fichier de base de données existant pour en créer un nouveau. Toutes les données non sauvegardées dans le seeder seront perdues.

Explorer la base de données

La base de données étant un simple fichier (src/database/data/database.sqlite), vous pouvez facilement l'explorer avec des outils dédiés, sans avoir besoin de lancer un serveur ou un conteneur externe.

Nous recommandons :

  • Si vous utilisez VS Code : l'extension SQLite Viewer permet d'ouvrir et de consulter le fichier .sqlite directement dans votre éditeur.
  • Application de bureau : le logiciel gratuit DB Browser for SQLite pour visualiser, éditer et exécuter des requêtes SQL sur votre fichier.

Bonnes pratiques et cas d'usage

Nous vous recommandons d'inclure les champs suivants dans chaque table, lorsque cela est pertinent :

  • id : identifiant unique (via integer primary key)
  • created_at : date et heure de création
  • deleted_at : date et heure de suppression (pour la suppression douce)

Ces conventions permettent d'assurer la cohérence et la traçabilité des données dans toute l'application.

Utilisez des clés étrangères avec contraintes d'intégrité référentielle pour maintenir la cohérence des données :

foreign key(user_id) references user(id) on delete cascade

Voir aussi

Clone this wiki locally