Skip to content

refactor: inject IRepository in PostgresProjector (DIP)#47

Merged
jorge07 merged 1 commit intojorge07:masterfrom
josecarlospeer-cloud:feat/projector-dip
Feb 22, 2026
Merged

refactor: inject IRepository in PostgresProjector (DIP)#47
jorge07 merged 1 commit intojorge07:masterfrom
josecarlospeer-cloud:feat/projector-dip

Conversation

@josecarlospeer-cloud
Copy link
Contributor

Problem

PostgresProjector injected the concrete PostgresRepository class directly:

@inject("infrastructure.transaction.readModel.repository")
private readonly readModel: PostgresRepository  // ← concrete class

Violation: Dependency Inversion Principle — upper layers should depend on abstractions, not concretions. The Domain already defines IRepository; the projector bypassed it.

Source: Evans (Blue Book) — "Interfaces in Domain, implementations in Infrastructure." Martin, Clean Architecture, ch. 11 (DIP).

Consequence: The projector is untestable without a real database. Any change to PostgresRepository's internals could break the projector at a different layer boundary than intended.

Fix

  1. Add save(dto: ITransactionReadDTO): Promise<void> to IRepository — uses only primitive types, keeps TypeORM out of the Domain interface.

  2. PostgresRepository.save() now maps ITransactionReadDTO → Transactions entity internally. The infrastructure detail stays in Infrastructure.

  3. PostgresProjector now depends only on IRepository and builds the DTO inline from the domain event fields.

  4. Remove dead Transactions.fromCreated() — was only ever called from the projector; no longer needed.

  5. Update InMemoryProjector test double to build the DTO inline (removes its dependency on the deleted factory method).

Tests

All 14 tests pass with no changes to test assertions.

D2.1 from Phase 2 roadmap.

Violation: PostgresProjector injected the concrete PostgresRepository
class instead of the IRepository interface, violating the Dependency
Inversion Principle (Evans, Blue Book — interfaces in Domain, impls
in Infrastructure; Martin, Clean Architecture ch.11).

Consequence: The projector was untestable without a real database
connection, and a compile-time dependency on a concrete infrastructure
class crept into application wiring.

Fix:
- Add save(dto: ITransactionReadDTO): Promise<void> to IRepository
  (keeps TypeORM types out of the Domain interface)
- PostgresRepository.save() now maps ITransactionReadDTO → Transactions
  entity internally; infrastructure detail stays in Infrastructure
- PostgresProjector now depends only on IRepository and builds the DTO
  inline from the domain event
- Remove dead Transactions.fromCreated() factory (no longer called)
- Update InMemoryProjector test double to build DTO inline instead
@jorge07 jorge07 merged commit 6762473 into jorge07:master Feb 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants