Repository API
O Repository<T> é a interface principal para interagir com o banco. Você o obtém a partir da conexão:
const repo = conn.getRepository(User);Cada entidade tem seu próprio repositório tipado. Todos os métodos são assíncronos.
Obtendo um Repository
Seção intitulada “Obtendo um Repository”import { Connection } from 'mirror-orm';
const conn = await Connection.postgres('postgresql://...');const repo = conn.getRepository(User);Consultas
Seção intitulada “Consultas”find(options?)
Seção intitulada “find(options?)”Retorna um array de entidades. Aceita filtros, ordenação, paginação, relações e mais.
const users = await repo.find({ where: { active: true }, orderBy: { createdAt: 'DESC' }, limit: 20, offset: 0, relations: ['profile'],});Opções disponíveis (IFindOptions<T>):
| Opção | Tipo | Descrição |
|---|---|---|
where | Partial<T> | Array<Partial<T>> | Filtros de busca |
orderBy | Partial<Record<keyof T, 'ASC' | 'DESC'>> | Ordenação |
limit | number | Máximo de resultados |
offset | number | Quantos registros pular |
relations | string[] | Relações a carregar |
select | (keyof T)[] | Colunas específicas |
withDeleted | boolean | Incluir registros com soft delete |
lock | 'pessimistic_write' | 'pessimistic_read' | Lock de linha |
filters | string[] | Filtros nomeados da entidade |
findOne(options?)
Seção intitulada “findOne(options?)”Igual ao find, mas retorna T | null. Internamente adiciona LIMIT 1.
const user = await repo.findOne({ where: { email: 'dev@example.com' } });
if (user) { console.log(user.name);}findOneOrFail(options?)
Seção intitulada “findOneOrFail(options?)”Igual ao findOne, mas lança EntityNotFoundError se nenhum resultado for encontrado. Útil quando a ausência do registro é um erro de lógica, não um estado válido.
// Lança EntityNotFoundError se não existirconst user = await repo.findOneOrFail({ where: { id: 1 } });findById(id)
Seção intitulada “findById(id)”Atalho para busca pela chave primária.
const user = await repo.findById(1);const user = await repo.findById('uuid-aqui');findAll()
Seção intitulada “findAll()”Retorna todos os registros da tabela, sem filtros. Respeita soft delete automaticamente.
const all = await repo.findAll();findAndCount(options?)
Seção intitulada “findAndCount(options?)”Retorna [dados, total] em uma única operação — útil para paginação manual.
const [users, total] = await repo.findAndCount({ where: { active: true }, limit: 10, offset: 20,});
console.log(`Exibindo ${users.length} de ${total}`);findPaginated(options)
Seção intitulada “findPaginated(options)”Versão de alto nível da paginação. Recebe page e limit e retorna um objeto com data e meta.
const result = await repo.findPaginated({ where: { active: true }, orderBy: { createdAt: 'DESC' }, page: 2, limit: 10,});
console.log(result.data); // Array<User>console.log(result.meta.total); // total de registrosconsole.log(result.meta.lastPage); // última páginaconsole.log(result.meta.page); // página atualconsole.log(result.meta.limit); // itens por páginafindStream(options?)
Seção intitulada “findStream(options?)”Retorna um AsyncGenerator<T> para processar grandes volumes de dados sem carregar tudo na memória.
for await (const user of repo.findStream({ where: { active: true } })) { await processUser(user);}count(where?)
Seção intitulada “count(where?)”Retorna o número de registros que correspondem ao filtro.
const total = await repo.count({ active: true });const all = await repo.count(); // sem filtroexists(where?)
Seção intitulada “exists(where?)”Retorna true se ao menos um registro corresponder ao filtro. Mais eficiente que count() > 0.
const taken = await repo.exists({ email: 'dev@example.com' });Mutações
Seção intitulada “Mutações”save(entity)
Seção intitulada “save(entity)”Insere ou atualiza uma entidade. O Mirror detecta automaticamente a operação correta:
- Sem PK →
INSERT - Com PK →
UPDATEapenas das colunas que mudaram (dirty checking)
// INSERT — id não está definidoconst user = new User();user.name = 'Alice';user.email = 'alice@example.com';const saved = await repo.save(user);// saved.id agora está preenchido
// UPDATE — só as colunas alteradas vão no SQLsaved.name = 'Alice Smith';await repo.save(saved);// UPDATE users SET name = $1, updated_at = $2 WHERE id = $3Dirty Checking: O Mirror tira um snapshot das colunas no momento do find. No save, compara o estado atual com o snapshot e inclui no UPDATE apenas o que mudou. Se nada mudou, nenhuma query é disparada.
const user = await repo.findById(1);await repo.save(user); // nenhuma query — nada mudouRetorno: a mesma instância mutada (com PK, timestamps e version atualizados).
saveMany(entities)
Seção intitulada “saveMany(entities)”Versão em lote do save. Processa cada entidade individualmente com dirty checking.
const saved = await repo.saveMany([user1, user2, user3]);update(data, where)
Seção intitulada “update(data, where)”Atualiza colunas diretamente por filtro, sem carregar entidades. Retorna o número de linhas afetadas.
const affected = await repo.update( { active: false }, { lastLoginAt: LessThan(thirtyDaysAgo) });Diferente de
save(), oupdate()não passa pelo dirty checking nem dispara lifecycle hooks.
upsert(entity, conflictKeys, options?)
Seção intitulada “upsert(entity, conflictKeys, options?)”INSERT ... ON CONFLICT DO UPDATE. Útil para sincronização de dados externos.
await repo.upsert( product, ['sku'], // coluna(s) de conflito { update: ['price', 'stock'] } // colunas a atualizar no conflito (padrão: todas));Se update for omitido, todas as colunas (exceto PK e createdAt) são atualizadas no conflito.
remove(entity)
Seção intitulada “remove(entity)”Remove uma entidade pelo PK. Se a entidade tiver @DeletedAt, faz soft delete em vez de hard delete.
const user = await repo.findById(1);await repo.remove(user);// Se User tiver @DeletedAt: UPDATE users SET deleted_at = NOW() WHERE id = 1// Se não tiver: DELETE FROM users WHERE id = 1Lança MissingPrimaryKeyError se a entidade não tiver PK.
removeMany(entities)
Seção intitulada “removeMany(entities)”Versão em lote do remove.
await repo.removeMany([user1, user2]);delete(where)
Seção intitulada “delete(where)”Remove por filtro, sem precisar carregar as entidades. Retorna o número de linhas afetadas. Sempre faz hard delete, independente de @DeletedAt.
const deleted = await repo.delete({ active: false });console.log(`${deleted} registros removidos`);Use
remove()quando precisar de soft delete ou cascades. Usedelete()quando quiser deletar em massa de forma direta.
softRestore(entity)
Seção intitulada “softRestore(entity)”Restaura um registro com soft delete, definindo deletedAt = null. Retorna a entidade restaurada.
const user = await repo.findOne({ where: { id: 1 }, withDeleted: true,});
const restored = await repo.softRestore(user);// restored.deletedAt === nullOpções de Query em Detalhe
Seção intitulada “Opções de Query em Detalhe”where — Filtros
Seção intitulada “where — Filtros”Condições simples usam igualdade. Para comparações mais complexas, use os operadores:
import { MoreThan, Like, In, IsNull, Between } from 'mirror-orm';
await repo.find({ where: { age: MoreThan(18), name: Like('%silva%'), status: In(['active', 'pending']), deletedAt: IsNull(), score: Between(80, 100), }});Para condições OR, passe um array de objetos — cada objeto é um grupo AND, os grupos são unidos com OR:
await repo.find({ where: [ { role: 'admin' }, { role: 'moderator', active: true }, ] // WHERE (role = 'admin') OR (role = 'moderator' AND active = true)});Ver Filters & Operators para a referência completa de operadores.
relations — Carregamento de Relações
Seção intitulada “relations — Carregamento de Relações”await repo.find({ relations: ['author', 'tags'] });Suporta dot notation para relações aninhadas:
await repo.find({ relations: ['author', 'author.publisher', 'comments.author'],});Cada relação pode gerar queries adicionais dependendo do tipo. Ver Relacionamentos para detalhes.
select — Colunas Específicas
Seção intitulada “select — Colunas Específicas”Por padrão, todas as colunas (exceto select: false) são incluídas. Para buscar apenas algumas:
await repo.find({ select: ['id', 'name', 'email'],});Quando
selecté usado, ele define exatamente quais colunas são retornadas — inclusive sobrescreveselect: falsenas colunas listadas.
orderBy — Ordenação
Seção intitulada “orderBy — Ordenação”await repo.find({ orderBy: { createdAt: 'DESC', name: 'ASC', }});lock — Locks de Linha
Seção intitulada “lock — Locks de Linha”Usado dentro de transações para controle de concorrência pessimista:
await conn.transaction(async (tx) => { const repo = tx.getRepository(Product);
const product = await repo.findOne({ where: { id: 1 }, lock: 'pessimistic_write', // FOR UPDATE });
product.stock -= 1; await repo.save(product);});| Valor | SQL gerado | Uso |
|---|---|---|
'pessimistic_write' | FOR UPDATE | Leitura exclusiva — bloqueia outras escritas e leituras |
'pessimistic_read' | FOR SHARE | Leitura compartilhada — bloqueia outras escritas |
Ver também: Transactions e Optimistic Locking.
filters — Filtros Nomeados
Seção intitulada “filters — Filtros Nomeados”Aplica filtros globais definidos no @Entity:
@Entity('posts', { filters: { published: { status: 'published' }, recent: { createdAt: MoreThan(sevenDaysAgo) }, }})class Post { ... }
// Ativar por nomeawait repo.find({ filters: ['published', 'recent'] });Útil para condições recorrentes como multi-tenancy, status de publicação ou soft delete customizado.
Referência Rápida
Seção intitulada “Referência Rápida”| Método | Retorno | Notas |
|---|---|---|
find(options?) | T[] | |
findOne(options?) | T | null | |
findOneOrFail(options?) | T | Lança EntityNotFoundError |
findById(id) | T | null | Atalho por PK |
findAll() | T[] | Sem filtros |
findAndCount(options?) | [T[], number] | |
findPaginated(options) | IPaginatedResult<T> | Inclui meta de paginação |
findStream(options?) | AsyncGenerator<T> | Baixo consumo de memória |
count(where?) | number | |
exists(where?) | boolean | |
save(entity) | T | Insert ou update com dirty check |
saveMany(entities) | T[] | |
update(data, where) | number | Afetados, sem hooks |
upsert(entity, keys, opts?) | T | ON CONFLICT |
remove(entity) | void | Soft delete automático se tiver @DeletedAt |
removeMany(entities) | void | |
delete(where) | number | Hard delete por filtro |
softRestore(entity) | T |