Skip to content

v2.1.0

Compare
Choose a tag to compare
@idugalic idugalic released this 12 Apr 10:51
· 169 commits to main since this release
054a489

Fmodel provides just enough tactical Domain-Driven Design patterns, optimized for Event Sourcing and CQRS.

The domain components are fully isolated from the application layer and API-related concerns.
It represents a pure declaration (pure functions) of the program logic.
Decider, View, and Saga

The application components orchestrate the execution of the logic by loading the state, executing domain components, and storing a new state.
EventSourcingAggregate, StateStoredAggregate, MaterializedView, and SagaManager

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Learn more

What's Changed

Lowering down the responsibility of the Metadata types in the Application layer.

For example, the EventRepository interface:

export interface IEventRepository<C, E, V, CM, EM> {
  /**
   * Fetch events
   *
   * @param command - Command of type `C`
   *
   * @return list of Events with Version and Event Metadata
   */
  readonly fetch: (command: C) => Promise<readonly (E & V & EM)[]>;

  /**
   * Get the event stream version / sequence
   *
   * @param event - Event of type `E`
   *
   * @return the version / sequence of the event stream that this event belongs to.
   */
  readonly versionProvider: (event: E & EM) => Promise<V | null>;

  /**
   * Save events
   *
   * @param events - list of Events
   * @param commandMetadata - Command Metadata of the command that initiated `events`
   * @param versionProvider - A provider for the Latest Event in this stream and its Version/Sequence
   * @return  a list of newly saved Event(s) of type `E` with Version of type `V` and with Event Metadata of type `EM`
   */
  readonly save: (
    events: readonly E[],
    commandMetadata: CM,
    versionProvider: (e: E) => Promise<V | null>
  ) => Promise<readonly (E & V & EM)[]>;
}

Old interface:

export interface IEventRepository<C, E, V, CM, EM> {
  /**
   * Fetch events
   *
   * @param command - Command of type `C` with metadata of type `CM`
   *
   * @return list of Events with Version and Event Metadata
   */
  readonly fetch: (command: C & CM) => Promise<readonly (E & V & EM)[]>;

  /**
   * Get the latest event stream version / sequence
   *
   * @param event - Event of type `E`
   *
   * @return the latest version / sequence of the event stream that this event belongs to.
   */
  readonly versionProvider: (event: E) => Promise<V | null>;

  /**
   * Save events
   *
   * @param events - list of Events
   * @param commandMetadata - Command Metadata of the command that initiated `events`
   * @param versionProvider - A provider for the Latest Event in this stream and its Version/Sequence
   * @return  a list of newly saved Event(s) of type `E` with Version of type `V` and with Event Metadata of type `EM`
   */
  readonly save: (
    events: readonly E[],
    commandMetadata: CM,
    versionProvider: (e: E) => Promise<V | null>
  ) => Promise<readonly (E & V & EM)[]>;
}

The interface used CM as the param of fetch method, and EM in the versionProvider. This could lead to problems, for example, the C lost the relation with the list of E/Events it produced, as CM could be used to identify the events it needs to fetch.

The relation between:

  • C and the E/Events it can produce
  • E and the Commands we can trigger next
  • List of E and the S/state they can evolve to

is the concern of domain layer, not of the application layer.

Full Changelog: v2.0.1...v2.1.0