evtstore
Version:
Event Sourcing with Node.JS
78 lines (64 loc) • 2.24 kB
text/typescript
import { Event, Provider, StoreEvent, ErrorCallback } from '../src/types'
import { VersionError } from './error'
import { createEventsMapper, toArray } from './util'
export function createProvider<E extends Event>(
initEvents?: Array<StoreEvent<E>>,
onError: ErrorCallback = () => {}
): Provider<E> {
const events: Array<StoreEvent<E>> = initEvents || []
const bms = new Map<string, number>()
let position = 0
const getPosition = async (bm: string) => bms.get(bm) || 0
const setPosition = async (bm: string, pos: number) => {
bms.set(bm, pos)
}
const getEventsFrom = async (stream: string | string[], pos: number, limit: number) => {
const results = events.filter((ev) => toArray(stream).includes(ev.stream) && ev.position > pos)
return limit ? results.slice(0, limit) : results
}
const getLastEventFor = async (stream: string | string[], id?: string) => {
const streams = toArray(stream)
for (let i = events.length - 1; i >= 0; i--) {
const evt = events[i]
if (id && streams.includes(evt.stream) && evt.aggregateId === id) return evt
if (streams.includes(evt.stream)) return evt
}
}
const getEventsFor = async (stream: string, id: string, fromPosition?: number) => {
const filter =
fromPosition === undefined
? (ev: StoreEvent<E>) => ev.stream === stream && ev.aggregateId === id
: (ev: StoreEvent<E>) =>
ev.stream === stream && ev.aggregateId === id && ev.position > fromPosition
return events.filter(filter)
}
const createEvents = createEventsMapper<E>(0)
const append = async (
stream: string,
aggregateId: string,
version: number,
newEvents: StoreEvent<E>[]
) => {
const aggEvents = await getEventsFor(stream, aggregateId)
for (const ev of aggEvents) {
if (ev.version === version) throw new VersionError()
}
const storeEvents: Array<StoreEvent<E>> = newEvents.map((event) => ({
...event,
position: ++position,
}))
events.push(...storeEvents)
return storeEvents
}
return {
driver: 'memory',
onError,
getPosition,
setPosition,
getEventsFor,
getEventsFrom,
getLastEventFor,
createEvents,
append,
}
}