El problema del acoplamiento
Si esparces consultas SQL (o llamadas al ORM) por toda la aplicación, tu lógica de negocio queda acoplada a la base de datos. Cambiar de Postgres a otra fuente, o escribir pruebas sin una base real, se vuelve muy difícil.
La solución: el repositorio
Un repositorio concentra todo el acceso a datos de una entidad detrás de un conjunto de funciones con nombres del dominio, no del SQL:
crear(datos)buscarPorId(id)listar()actualizar(id, cambios)borrar(id)
El resto del programa llama a estas funciones y no sabe si por debajo hay SQL, un ORM o un array. Esa frontera es lo valioso.
function crearRepoUsuarios(db) {
return {
async listar() {
const { rows } = await db.query("SELECT * FROM usuarios");
return rows;
},
async buscarPorId(id) {
const { rows } = await db.query(
"SELECT * FROM usuarios WHERE id = $1",
[id]
);
return rows[0];
},
async crear(usuario) {
const { rows } = await db.query(
"INSERT INTO usuarios (email) VALUES ($1) RETURNING *",
[usuario.email]
);
return rows[0];
},
};
}
Repositorios en memoria
Como el repositorio es solo una interfaz (un objeto con funciones), puedes implementar uno en memoria sobre un array para las pruebas. La lógica que lo use no nota la diferencia: en producción recibe el repo real; en los tests, el de memoria. Eso es lo que practicarás en los ejercicios.
Las funciones del repositorio suelen ser
async(devuelvenPromise), aunque por dentro sean síncronas, para que la firma no cambie al pasar de un array a una base de datos real.