3.4SQL avec Node : PostgreSQL, MySQL, Prisma
L'essentiel en 30 secondes
- Le relationnel structure : tables, lignes, clés étrangères (PostgreSQL/MySQL), schéma strict et transactions ACID pour l'intégrité.
- Le SQL s'écrit ou se génère : SELECT/INSERT/UPDATE/DELETE + JOIN en brut paramétré, ou méthodes d'ORM (Prisma/Sequelize) qui génèrent un SQL sûr.
- La sécurité est non négociable : jamais de concaténation de données utilisateur (injection SQL) — requêtes paramétrées ou ORM + compréhension du SQL sous-jacent.
Mini-cas filé — Salim facture en SQL sans faille
Salim, développeur junior à Alger, doit facturer : clients, commandes et lignes liées, totaux à garantir. Le NoSQL souple ne suffit plus. Il modélise trois tables reliées par clés étrangères (PostgreSQL), écrit ses premières requêtes SELECT/JOIN en paramétré, puis passe à Prisma : schéma déclaratif schema.prisma, migration qui versionne, client typé prisma.commande.create() et findMany(). Quand un champ de recherche contient un guillemet piégé, le paramétrage le neutralise : aucune injection.
Dernier épisode du fil Salim — d'Express aux deux familles de bases : la persistance complète.
1. Le modèle relationnel & le SQL
La famille SQL / relationnelle (surtout PostgreSQL, puissant et open source, et MySQL/MariaDB) organise les données en tables (colonnes typées), lignes (enregistrements) et relations formelles par clés étrangères (une commande référence un client). Le langage SQL interroge : SELECT (lire), INSERT (créer), UPDATE, DELETE, JOIN (combiner des tables liées). Garanties fortes : schéma strict et transactions ACID pour la cohérence — idéales pour données structurées et critiques.
Depuis Node, deux niveaux : le driver brut (ex. pg pour PostgreSQL) où l'on écrit le SQL dans des chaînes — avec l'impératif requêtes paramétrées ($1, $2…) car concaténer des entrées utilisateur ouvre l'injection SQL, faille critique. Ou l'ORM qui génère le SQL à votre place.
2. Prisma : schéma, migrations, client typé
Un ORM (Object-Relational Mapper) mappe tables ↔ objets JS : on manipule prisma.client.create({ data }) et findMany({ where }) au lieu de chaînes SQL — plus lisible, plus productif, et protégé des injections par paramétrage automatique. Les courants : Prisma (moderne, très apprécié) et Sequelize (ancien, éprouvé).
Prisma se distingue par son schéma déclaratif (fichier schema.prisma décrivant modèles et relations), ses migrations (versionner l'évolution du schéma) et son client généré et typé (autocomplétion, sécurité des types — excellent avec TypeScript, section 5-1). Recommandé pour la plupart des applis ; garder le SQL brut pour les requêtes très pointues. Réflexe de Salim : comprendre le SQL généré (charger les relations efficacement, éviter le N+1) au lieu de traiter l'ORM en boîte noire.
🔎 Exemple concret — Prisma : un CRUD typé et sûr
Salim crée et liste des clients sans écrire de SQL.
// schema.prisma déclare Client et Commande liés (1-N)
const nouveau = await prisma.client.create({
data: { nom: 'Salim', email: 'salim@exemple-fictif.test' }
});
const actifs = await prisma.client.findMany({
where: { actif: true }
});
// Driver brut équivalent SÛR (paramétré, pg) :
// await pool.query('SELECT * FROM clients WHERE email = $1', [emailSaisi]);
Lecture : objets et méthodes côté Prisma, $1 paramétré côté brut.
Leçon : les deux voies neutralisent l'injection ; la concaténation, jamais.
Vocabulaire de la section
- SQL / relationnel
- Bases en tables, lignes et clés étrangères (PostgreSQL, MySQL) ; schéma strict et transactions ACID.
Exemple simple : Clients, commandes et lignes liés chez Salim.
Ce que ce n'est pas : des documents flexibles sans schéma.
Réflexe : le choisir pour données liées et critiques.
- SQL (langage)
- SELECT (lire), INSERT (créer), UPDATE, DELETE, JOIN (combiner des tables liées).
Exemple simple : SELECT avec JOIN commandes-clients de Salim.
Ce que ce n'est pas : des appels de méthodes d'ORM.
Réflexe : savoir lire un SELECT/JOIN même avec un ORM.
- Injection SQL
- Faille critique : une entrée concaténée devient du code exécuté ; se protège par paramétrage.
Exemple simple : Un guillemet piégé neutralisé par $1.
Ce que ce n'est pas : une simple erreur d'affichage sans gravité.
Réflexe : ne jamais concaténer, toujours paramétrer.
- ORM (Prisma, Sequelize)
- Mappe tables ↔ objets JS et génère le SQL : méthodes lisibles, sûres et productives.
Exemple simple : prisma.client.findMany({ where }) chez Salim.
Ce que ce n'est pas : du SQL brut concaténé à la main.
Réflexe : privilégier l'ORM pour le CRUD courant.
- Prisma (moderne)
- ORM à schéma déclaratif (schema.prisma), migrations versionnées et client généré typé.
Exemple simple : La migration qui ajoute la table lignes.
Ce que ce n'est pas : un driver brut sans modèle ni type.
Réflexe : versionner chaque évolution par une migration.
En pratique — Persister avec une base SQL et un ORM
- Comprenez le modèle relationnel : tables, colonnes typées, lignes, relations par clés étrangères ; et les opérations SQL de base (SELECT, INSERT, UPDATE, DELETE, JOIN).
- Retenez l'impératif de sécurité : ne JAMAIS concaténer des données utilisateur dans du SQL (injection) — requêtes paramétrées ou ORM.
- Découvrez un ORM moderne : définissez un schéma (Prisma : schema.prisma) et faites un CRUD via des méthodes (prisma.user.create/findMany/update/delete).
- Explorez les migrations Prisma (versionner l'évolution du schéma) et l'intérêt du client typé (autocomplétion, sécurité des types avec TypeScript).
Script prêt à dire — présenter son SQL sûr (30 s)
« La facturation est en PostgreSQL : tables clients, commandes et lignes liées par clés étrangères. Le CRUD passe par Prisma, schéma déclaratif plus migrations, client typé. Le SQL brut restant est paramétré en $1, jamais concaténé : testé avec une entrée piégée, l'injection est neutralisée. »
À dire en revue sécu ; montrer le schéma et une requête paramétrée.
Modèle copier-coller — Prisma + requête paramétrée
// schema.prisma (extrait factice) :
// model Client { id Int @id @default(autoincrement())
// nom String
// email String @unique
// commandes Commande[] }
async function main() {
const nouveau = await prisma.client.create({
data: { nom: 'Salim', email: 'salim@exemple-fictif.test' }
});
const liste = await prisma.client.findMany({ where: { actif: true } });
await prisma.client.update({
where: { email: 'salim@exemple-fictif.test' },
data: { actif: false }
});
// Rappel brut SÛR (pg) — jamais de concaténation :
// await pool.query('SELECT * FROM clients WHERE email = $1', [emailSaisi]);
}
main().catch(console.error);
Indépendant
Facturer en PostgreSQL + Prisma : trois tables liées et un CRUD typé suffisent.
PME à Alger
Salim versionne chaque ajout de colonne par une migration relue avant déploiement.
Équipe produit
Imposer le client typé partagé pour des requêtes cohérentes entre équipes.
Débutant
Cette semaine : un modèle Prisma, un create et un findMany avec where.
✓ Bonnes pratiques
- Utiliser un ORM moderne (Prisma) pour la productivité et la sécurité.
- Toujours des requêtes paramétrées (jamais de concaténation) contre l'injection SQL.
- Comprendre le SQL sous-jacent et charger les relations efficacement (éviter le N+1).
✗ Pièges fréquents
- Concaténer des données utilisateur dans une requête SQL (injection critique).
- Traiter l'ORM comme une boîte noire (requêtes inefficaces, N+1).
- Ignorer les bases du SQL en se reposant entièrement sur l'ORM.
Points clés à retenir
- SQL / RELATIONNEL (PostgreSQL, MySQL) : données en TABLES/LIGNES avec relations par CLÉS ÉTRANGÈRES ; garanties fortes (ACID).
- Langage SQL : SELECT/INSERT/UPDATE/DELETE + JOIN. Sécurité CRITIQUE : jamais concaténer des données utilisateur (INJECTION SQL).
- Un ORM (PRISMA, Sequelize) mappe tables ↔ objets et génère le SQL : lisible, sûr contre les injections, productif.
- PRISMA : schéma déclaratif + migrations + client TYPÉ. Maîtriser SQL + NoSQL = boîte à outils de persistance complète.
Défi 48h — appliquez demain
Déclarez 1 modèle Prisma et faites un create + findMany, puis réécrivez un SELECT en paramétré $1.
- Je cite tables, clés étrangères et ACID.
- Mon SQL brut est paramétré, jamais concaténé.
- Mon CRUD Prisma passe par schéma + migration.
Questions fréquentes
Driver SQL brut ou ORM (Prisma/Sequelize) : que choisir ?
Pour la plupart des applis, un ORM : productivité (prisma.user.create() concis), sécurité (paramétrage automatique anti-injection), lisibilité et relations simples. Le driver brut (pg) garde sa place pour le contrôle fin et les requêtes pointues. Salim combine : ORM au quotidien, SQL paramétré pour les rapports JOIN complexes.
Qu'est-ce que l'injection SQL et comment s'en protéger ?
Une entrée utilisateur concaténée dans du SQL peut devenir du code exécuté (contournement d'auth, lecture ou destruction de données). Exemple du danger : ' OR '1'='1 glissé dans un email. Protection : requêtes paramétrées (placeholders $1 séparant code et données) et ORM qui paramètrent par défaut. Jamais de concaténation, même en test — c'est un savoir de sécurité fondamental.
Quelle pratique protège d'une injection SQL en Node ?