UNPKG

evtstore

Version:

Event Sourcing with Node.JS

119 lines (98 loc) 3.13 kB
import { createPersistedAggregate, createProvidedAggregate } from './create-aggregate' import { EventHandler } from './event-handler' import { AggregateStore, ProvidedAggregate, Provider, StorableAggregate, Event, HandlerBookmark, EventMeta, DomainHandlerOpts, } from './types' type StoreOpts = { provider: Provider<any> | Promise<Provider<any>> useCache?: boolean } type StreamEvents<T extends AggregateStore> = { [K in ExtStreams<T>]: StreamAgg<T, K> } type ExtStoreAgg<T extends StorableAggregate, U extends string> = T extends StorableAggregate< any, any, U > ? T : never type StreamAgg<T extends AggregateStore, U extends ExtStreams<T>> = ExtStoreAggEvent< ExtStoreAgg<T[keyof T], U> > type ToStoreAgg<T> = T extends StorableAggregate<infer E, infer A> ? ProvidedAggregate<E, A> : never type Store<T extends AggregateStore> = { [key in keyof T]: ToStoreAgg<T[key]> } & {} type ExtStoreAggEvent<T> = T extends StorableAggregate<infer E, any, any> ? E : never type ExtStreams<T extends AggregateStore> = T[keyof T]['stream'] export function createDomain<Tree extends AggregateStore>(opts: StoreOpts, aggregates: Tree) { return createDomainV2(opts, aggregates) } export function createDomainV2<Tree extends AggregateStore>(opts: StoreOpts, aggregates: Tree) { type EventTree = StreamEvents<Tree> const _store: any = {} for (const [key, storableAgg] of Object.entries(aggregates)) { const aggOpts = { ...storableAgg, provider: opts.provider, useCache: opts.useCache, } _store[key] = aggOpts.persistAggregate && aggOpts.version ? createPersistedAggregate(aggOpts) : createProvidedAggregate(aggOpts) } const createHandler = <S extends ExtStreams<Tree>[]>( bookmark: HandlerBookmark, streams: S, options: DomainHandlerOpts = {} ) => { type Evt = EventTree[S[number]] type CB = (id: string, event: Event, meta: EventMeta) => any const callbacks = new Map<string, CB>() const handler = new EventHandler<Evt>({ bookmark, provider: opts.provider, stream: streams, ...options, }) const handlerCallback = (id: string, event: Event, meta: EventMeta) => { const cb = callbacks.get(`${meta.stream}-${event.type}`) if (!cb) return return cb(id, event as any, meta) } const handle = <Stream extends S[number], Type extends EventTree[Stream]['type']>( stream: Stream, event: Type, callback: ( id: string, event: Extract<EventTree[Stream], { type: Type }>, meta: EventMeta ) => any ) => { callbacks.set(`${stream}-${event}`, callback as any) handler.handle(event, handlerCallback) } return { handle, name: handler.name, start: handler.start, stop: handler.stop, runOnce: handler.runOnce, run: handler.run, setPosition: handler.setPosition, getPosition: handler.getPosition, reset: handler.reset, __handler: handler, } } const domain = _store as Store<Tree> return { domain, createHandler, } }