3.4SQL con Node : PostgreSQL, MySQL, Prisma
Lo esencial en 30 segundos
- Lo relacional estructura : tablas, filas, claves foráneas (PostgreSQL/MySQL), esquema estricto y transacciones ACID para la integridad.
- El SQL se escribe o se genera : SELECT/INSERT/UPDATE/DELETE + JOIN en bruto parametrizado, o métodos de ORM (Prisma/Sequelize) que generan un SQL seguro.
- La seguridad no es negociable : jamás concatenación de datos de usuario (inyección SQL) — consultas parametrizadas u ORM + comprensión del SQL subyacente.
Mini-caso hilado — Salim factura en SQL sin fisuras
Salim, desarrollador junior en Argel, debe facturar : clientes, pedidos y líneas vinculadas, totales por garantizar. El NoSQL flexible ya no basta. Modela tres tablas unidas por claves foráneas (PostgreSQL), escribe sus primeras consultas SELECT/JOIN en parametrizado, y luego pasa a Prisma : esquema declarativo schema.prisma, migración que versiona, cliente tipado prisma.commande.create() y findMany(). Cuando un campo de búsqueda contiene una comilla tramposa, la parametrización la neutraliza : ninguna inyección.
Último episodio del hilo Salim — de Express a ambas familias de bases : la persistencia completa.
1. El modelo relacional y el SQL
La familia SQL / relacional (sobre todo PostgreSQL, potente y open source, y MySQL/MariaDB) organiza los datos en tablas (columnas tipadas), filas (registros) y relaciones formales por claves foráneas (un pedido referencia a un cliente). El lenguaje SQL interroga : SELECT (leer), INSERT (crear), UPDATE, DELETE, JOIN (combinar tablas vinculadas). Garantías fuertes : esquema estricto y transacciones ACID para la coherencia — ideales para datos estructurados y críticos.
Desde Node, dos niveles : el driver en bruto (p. ej. pg para PostgreSQL) donde se escribe el SQL en cadenas — con el imperativo consultas parametrizadas ($1, $2…) pues concatenar entradas de usuario abre la inyección SQL, fallo crítico. O el ORM que genera el SQL en vuestro lugar.
2. Prisma : esquema, migraciones, cliente tipado
Un ORM (Object-Relational Mapper) mapea tablas ↔ objetos JS : se manipula prisma.client.create({ data }) y findMany({ where }) en vez de cadenas SQL — más legible, más productivo, y protegido de inyecciones por parametrización automática. Los corrientes : Prisma (moderno, muy apreciado) y Sequelize (antiguo, probado).
Prisma se distingue por su esquema declarativo (archivo schema.prisma que describe modelos y relaciones), sus migraciones (versionar la evolución del esquema) y su cliente generado y tipado (autocompletado, seguridad de tipos — excelente con TypeScript, sección 5-1). Recomendado para la mayoría de apps ; guardar el SQL en bruto para las consultas muy precisas. Reflejo de Salim : comprender el SQL generado (cargar las relaciones con eficacia, evitar el N+1) en vez de tratar el ORM como caja negra.
🔎 Ejemplo concreto — Prisma : un CRUD tipado y seguro
Salim crea y lista clientes sin escribir SQL.
// schema.prisma declara Client y Commande vinculados (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 bruto equivalente SEGURO (parametrizado, pg) :
// await pool.query('SELECT * FROM clients WHERE email = $1', [emailSaisi]);
Lectura : objetos y métodos lado Prisma, $1 parametrizado lado bruto.
Lección : ambas vías neutralizan la inyección ; la concatenación, jamás.
Vocabulario de la sección
- SQL / relacional
- Bases en tablas, filas y claves foráneas (PostgreSQL, MySQL) ; esquema estricto y transacciones ACID.
Ejemplo sencillo: Clientes, pedidos y líneas vinculados en casa de Salim.
Lo que no es: documentos flexibles sin esquema.
Reflejo: elegirlo para datos vinculados y críticos.
- SQL (lenguaje)
- SELECT (leer), INSERT (crear), UPDATE, DELETE, JOIN (combinar tablas vinculadas).
Ejemplo sencillo: SELECT con JOIN pedidos-clientes de Salim.
Lo que no es: llamadas de métodos de ORM.
Reflejo: saber leer un SELECT/JOIN incluso con un ORM.
- Inyección SQL
- Fallo crítico : una entrada concatenada se vuelve código ejecutado ; se protege con parametrización.
Ejemplo sencillo: Una comilla tramposa neutralizada por $1.
Lo que no es: un simple error de visualización sin gravedad.
Reflejo: no concatenar jamás, parametrizar siempre.
- ORM (Prisma, Sequelize)
- Mapea tablas ↔ objetos JS y genera el SQL : métodos legibles, seguros y productivos.
Ejemplo sencillo: prisma.client.findMany({ where }) en casa de Salim.
Lo que no es: SQL en bruto concatenado a mano.
Reflejo: privilegiar el ORM para el CRUD corriente.
- Prisma (moderno)
- ORM de esquema declarativo (schema.prisma), migraciones versionadas y cliente generado tipado.
Ejemplo sencillo: La migración que añade la tabla de líneas.
Lo que no es: un driver en bruto sin modelo ni tipo.
Reflejo: versionar cada evolución con una migración.
En la práctica — Persistir con una base SQL y un ORM
- Comprended el modelo relacional : tablas, columnas tipadas, filas, relaciones por claves foráneas ; y las operaciones SQL básicas (SELECT, INSERT, UPDATE, DELETE, JOIN).
- Retenede el imperativo de seguridad : no concatenar JAMÁS datos de usuario en SQL (inyección) — consultas parametrizadas u ORM.
- Descubrid un ORM moderno : definid un esquema (Prisma : schema.prisma) y haced un CRUD vía métodos (prisma.user.create/findMany/update/delete).
- Explorad las migraciones Prisma (versionar la evolución del esquema) y el interés del cliente tipado (autocompletado, seguridad de tipos con TypeScript).
Guion listo para decir — presentar su SQL seguro (30 s)
« La facturación está en PostgreSQL : tablas clientes, pedidos y líneas vinculadas por claves foráneas. El CRUD pasa por Prisma, esquema declarativo más migraciones, cliente tipado. El SQL en bruto restante está parametrizado en $1, jamás concatenado : probado con una entrada tramposa, la inyección queda neutralizada. »
Para decir en revisión de seguridad ; mostrar el esquema y una consulta parametrizada.
Modelo copiar-pegar — Prisma + consulta parametrizada
// schema.prisma (extracto ficticio) :
// 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 }
});
// Recordatorio bruto SEGURO (pg) — jamás concatenación :
// await pool.query('SELECT * FROM clients WHERE email = $1', [emailSaisi]);
}
main().catch(console.error);
Independiente
Facturar en PostgreSQL + Prisma : tres tablas vinculadas y un CRUD tipado bastan.
Pyme en Argel
Salim versiona cada añadido de columna con una migración revisada antes del despliegue.
Equipo de producto
Imponer el cliente tipado compartido para consultas coherentes entre equipos.
Principiante
Esta semana : un modelo Prisma, un create y un findMany con where.
✓ Buenas prácticas
- Usar un ORM moderno (Prisma) para la productividad y la seguridad.
- Siempre consultas parametrizadas (jamás concatenación) contra la inyección SQL.
- Comprender el SQL subyacente y cargar las relaciones con eficacia (evitar el N+1).
✗ Errores frecuentes
- Concatenar datos de usuario en una consulta SQL (inyección crítica).
- Tratar el ORM como una caja negra (consultas ineficaces, N+1).
- Ignorar las bases del SQL apoyándose por entero en el ORM.
Puntos clave
- SQL / RELACIONAL (PostgreSQL, MySQL) : datos en TABLAS/FILAS con relaciones por CLAVES FORÁNEAS ; garantías fuertes (ACID).
- Lenguaje SQL : SELECT/INSERT/UPDATE/DELETE + JOIN. Seguridad CRÍTICA : jamás concatenar datos de usuario (INYECCIÓN SQL).
- Un ORM (PRISMA, Sequelize) mapea tablas ↔ objetos y genera el SQL : legible, seguro contra inyecciones, productivo.
- PRISMA : esquema declarativo + migraciones + cliente TIPADO. Dominar SQL + NoSQL = caja de herramientas de persistencia completa.
Reto 48h — aplica mañana
Declarad 1 modelo Prisma y haced un create + findMany, luego reescribid un SELECT en parametrizado $1.
- Cito tablas, claves foráneas y ACID.
- Mi SQL en bruto está parametrizado, jamás concatenado.
- Mi CRUD Prisma pasa por esquema + migración.
Preguntas frecuentes
¿Driver SQL en bruto u ORM (Prisma/Sequelize) : qué elegir?
Para la mayoría de apps, un ORM : productividad (prisma.user.create() conciso), seguridad (parametrización automática anti-inyección), legibilidad y relaciones simples. El driver en bruto (pg) guarda su lugar para el control fino y las consultas precisas. Salim combina : ORM a diario, SQL parametrizado para los informes JOIN complejos.
¿Qué es la inyección SQL y cómo protegerse?
Una entrada de usuario concatenada en SQL puede volverse código ejecutado (elusión de auth, lectura o destrucción de datos). Ejemplo del peligro : ' OR '1'='1 deslizado en un email. Protección : consultas parametrizadas (placeholders $1 que separan código y datos) y ORM que parametrizan por defecto. Jamás concatenación, incluso en prueba — es un saber de seguridad fundamental.
¿Qué práctica protege de una inyección SQL en Node?