Skip to content

Write Repository

Repositories provide an abstraction for loading and saving aggregates.

Purpose

  • Hide event store complexity from application layer
  • Provide clean aggregate-oriented API
  • Handle event stream management

Interface

typescript
interface IAccountRepository {
  findById(id: string): Promise<BankAccount | null>;
  save(account: BankAccount): Promise<void>;
}

Implementation

typescript
class AccountRepository implements IAccountRepository {
  constructor(private readonly eventStore: EventStore) {}

  async findById(id: string): Promise<BankAccount | null> {
    const stream = EventStream.for('BankAccount', id);
    const events = [];

    try {
      for await (const batch of this.eventStore.getEvents(stream)) {
        events.push(...batch);
      }
    } catch (error) {
      return null; // Aggregate not found
    }

    if (events.length === 0) return null;

    const account = new BankAccount(id);
    account.loadFromHistory(events);
    return account;
  }

  async save(account: BankAccount): Promise<void> {
    const stream = EventStream.for('BankAccount', account.id);
    const events = account.commit();
    const version = account.version - events.length;

    await this.eventStore.appendEvents(stream, version, events);
  }
}

Usage in Handlers

typescript
class DepositMoneyHandler {
  constructor(private readonly repository: IAccountRepository) {}

  async execute(command: DepositMoneyCommand): Promise<void> {
    const account = await this.repository.findById(command.accountId);
    if (!account) throw new Error('Account not found');

    account.deposit(command.amount);

    await this.repository.save(account);
  }
}

Documentation will be expanded soon.

Released under the MIT License.