O problema do acoplamento
Se você espalha consultas SQL (ou chamadas ao ORM) por toda a aplicação, sua lógica de negócio fica acoplada ao banco de dados. Trocar do Postgres por outra fonte, ou escrever testes sem um banco real, fica muito difícil.
A solução: o repositório
Um repositório concentra todo o acesso a dados de uma entidade atrás de um conjunto de funções com nomes do domínio, não do SQL:
criar(dados)buscarPorId(id)listar()atualizar(id, mudancas)remover(id)
O resto do programa chama essas funções e não sabe se por baixo há SQL, um ORM ou um array. Essa fronteira é o que tem valor.
function criarRepoUsuarios(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 criar(usuario) {
const { rows } = await db.query(
"INSERT INTO usuarios (email) VALUES ($1) RETURNING *",
[usuario.email]
);
return rows[0];
},
};
}
Repositórios em memória
Como o repositório é só uma interface (um objeto com funções), você pode implementar um em memória sobre um array para os testes. A lógica que o usa não nota a diferença: em produção recebe o repo real; nos testes, o de memória. É isso que você vai praticar nos exercícios.
As funções do repositório costumam ser
async(devolvemPromise), mesmo que por dentro sejam síncronas, para que a assinatura não mude ao passar de um array para um banco de dados real.