import { Effect, Scope, Sink, Stream, pipe } from 'effect'; import { EventStreamPosition, EventStore, eventStoreError, EventStoreError, } from '@codeforbreakfast/eventsourcing-store'; import { type InMemoryStore } from './InMemoryStore'; export interface SubscribableEventStore extends EventStore { readonly subscribeToStream: ( streamId: EventStreamPosition['streamId'] ) => Effect.Effect, EventStoreError, Scope.Scope>; } const dropEventsFromStream = (count: number) => (stream: Readonly>) => Stream.drop(stream, count); const readHistoricalEvents = (store: InMemoryStore) => (from: EventStreamPosition) => pipe(from.streamId, store.getHistorical, Effect.map(dropEventsFromStream(from.eventNumber))); const readAllEvents = (store: InMemoryStore) => (from: EventStreamPosition) => pipe(from.streamId, store.get, Effect.map(dropEventsFromStream(from.eventNumber))); const createSubscribeError = (streamId: EventStreamPosition['streamId']) => eventStoreError.subscribe(streamId, `Failed to subscribe to stream: ${String(streamId)}`); const subscribeToStreamWithError = (streamId: EventStreamPosition['streamId']) => (store: InMemoryStore) => pipe(streamId, store.get, Effect.mapError(createSubscribeError(streamId))); const subscribeToAllStreams = (store: InMemoryStore) => store.getAllLiveOnly(); export const makeInMemoryEventStore = ( store: InMemoryStore ): Effect.Effect, never, never> => Effect.succeed({ append: (to: EventStreamPosition) => Sink.foldChunksEffect( to, () => true, (end, chunk) => pipe(chunk, store.append(end)) ), read: readHistoricalEvents(store), subscribe: readAllEvents(store), subscribeAll: () => subscribeToAllStreams(store), }); const addSubscribeMethod = (store: InMemoryStore) => (baseStore: EventStore): SubscribableEventStore => ({ ...baseStore, subscribeToStream: (streamId: EventStreamPosition['streamId']) => pipe(store, subscribeToStreamWithError(streamId)), }); export const makeSubscribableInMemoryEventStore = ( store: InMemoryStore ): Effect.Effect, never, never> => pipe(store, makeInMemoryEventStore, Effect.map(addSubscribeMethod(store)));