DefaultRepositoryGateway
CRUD padrão com KnexDefaultRepository e MapperGateway
Para agregados com CRUD simples em uma única tabela, o projeto padroniza um par de classes base que eliminam boilerplate.
Contrato: DefaultRepositoryGateway
Arquivo: src/app/gateways/default.repository.gateway.ts
export abstract class DefaultRepositoryGateway<
APP,
INFRA,
PRIMARY_KEY extends keyof INFRA,
> {
abstract generateNewId(companyId: number): Promise<number>;
abstract findAll(companyId: number): Promise<APP[]>;
abstract findById(companyId: number, id: INFRA[PRIMARY_KEY]): Promise<Nullable<APP>>;
abstract create(companyId: number, entity: APP, selfIdGeneration?: boolean): Promise<APP>;
abstract update(companyId: number, entity: APP): Promise<APP>;
abstract delete(companyId: number, id: INFRA[PRIMARY_KEY]): Promise<void>;
}Características importantes:
- Todo método recebe
companyIdcomo primeiro parâmetro (multi-tenant). APP= entity da camada application (src/app/entities/).INFRA= tipo da linha do banco (src/infra/database/knex/entities/).PRIMARY_KEY= nome literal da coluna PK (ex.:'CD_FILA'), garantindo type-safety nofindByIdedelete.
Implementação: KnexDefaultRepository
Arquivo: src/infra/database/knex/repositories/knex-default.repository.ts
A classe implementa DefaultRepositoryGateway (não estende o gateway abstrato). Ela recebe no constructor:
| Parâmetro | Exemplo | Função |
|---|---|---|
companyDbGenerator | CompanyKnexProvider | Resolve conexão Knex por empresa |
tableName | 'FILA' | Nome da tabela MSSQL |
primaryKey | 'CD_FILA' | Coluna de chave primária |
mapper | QueueMapper | Conversão APP ↔ INFRA |
Separação de métodos públicos e internos
| Métodos | Retorno | Responsabilidade |
|---|---|---|
findAll, findById, create, update, delete | APP | Aplicam mapper.toEntity() / toPersistence() |
_findAll, _findById, _create, etc. | INFRA | Acesso direto ao Knex, sem mapping |
Isso permite que subclasses estendam lógica de banco reutilizando _-methods quando necessário.
MapperGateway
Arquivo: src/app/gateways/mapper.gateway.ts
export abstract class MapperGateway<APP, INFRA> {
abstract toEntity(payload: INFRA): APP;
abstract toPersistence(entity: APP): INFRA;
}Implementações ficam em src/infra/database/knex/mappers/ e são exportadas como singleton (ex.: QueueMapper). Exemplo simplificado:
// src/infra/database/knex/mappers/queue.ts
class Mapper implements MapperGateway<QueueEntity, Queue> {
toEntity(payload: Queue): QueueEntity {
return new QueueEntity({ /* campos de negócio */ }, payload.CD_FILA);
}
toPersistence(entity: QueueEntity): Queue {
return { CD_FILA: entity.getId(), DESCRICAO: entity.getDescription(), /* ... */ };
}
}
export const QueueMapper = new Mapper();Mappers frequentemente usam helpers de knex/utils.ts (bitToBoolean, booleanToBit, prepareDatesForMssql).
Comportamentos específicos MSSQL
prepareDatesForMssql: normaliza datas antes doinsert/update.removePrimaryKey: remove PK do payload no insert quando o ID é gerado pelo banco.selfIdGeneration: quandotrue, gera ID viaMAX(primaryKey) + 1antes do insert.- Tipos
bitdo SQL Server são convertidos viabitToBoolean/booleanToBit.
Gateway mínimo (só CRUD)
// src/app/gateways/queue.repository.gateway.ts
export abstract class QueueRepositoryGateway extends DefaultRepositoryGateway<
QueueEntity,
Queue,
'CD_FILA'
> {}Repository mínimo (só constructor)
// src/infra/database/knex/repositories/knex-queue.repository.ts
@Injectable()
export class KnexQueueRepository
extends KnexDefaultRepository<QueueEntity, Queue, 'CD_FILA'>
implements QueueRepositoryGateway
{
constructor(companyDbGenerator: CompanyKnexProvider) {
super(companyDbGenerator, 'FILA', 'CD_FILA', QueueMapper);
}
}Gateway estendido (CRUD + queries)
Quando a feature precisa de buscas além do CRUD, o gateway estende DefaultRepositoryGateway e adiciona métodos abstract:
// src/app/gateways/product.repository.gateway.ts (conceitual)
export abstract class ProductRepositoryGateway extends DefaultRepositoryGateway<
ProductEntity, Product, 'CD_PRODUTO'
> {
abstract findByIds(companyId: number, productIds: number[]): Promise<ProductEntity[]>;
}O KnexProductRepository estende KnexDefaultRepository e implementa os métodos extras com queries Knex adicionais.
Fluxo CRUD completo
Próximos tópicos
- Repository customizado — quando o default não basta
- Multi-tenant —
companyIdem todo método