@event-driven-io/emmett-postgresql 0.19.0 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/eventStore/postgreSQLEventStore.ts","../../emmett/src/validation/index.ts","../../emmett/src/errors/index.ts","../../emmett/src/validation/dates.ts","../../emmett/src/config/plugins/index.ts","../../emmett/src/eventStore/eventStore.ts","../../emmett/src/eventStore/expectedVersion.ts","../../emmett/src/eventStore/inMemoryEventStore.ts","../../emmett/src/commandHandling/handleCommand.ts","../../emmett/src/commandHandling/handleCommandWithDecider.ts","../../emmett/src/typing/command.ts","../../emmett/src/typing/event.ts","../../emmett/src/typing/workflow.ts","../../emmett/src/messageBus/index.ts","../../emmett/src/projections/index.ts","../../emmett/src/serialization/json/JSONParser.ts","../../emmett/src/streaming/binaryArrays.ts","../../emmett/src/streaming/collect.ts","../../emmett/src/streaming/decoders/binary.ts","../../emmett/src/streaming/decoders/string.ts","../../emmett/src/streaming/decoders/json.ts","../../emmett/src/streaming/decoders/object.ts","../../emmett/src/streaming/decoders/composite.ts","../../emmett/src/streaming/restream.ts","../../emmett/src/utils/deepEquals.ts","../../emmett/src/utils/iterators.ts","../../emmett/src/utils/merge.ts","../../emmett/src/testing/assertions.ts","../../emmett/src/testing/deciderSpecification.ts","../../emmett/src/testing/wrapEventStore.ts","../src/eventStore/projections/index.ts","../src/eventStore/projections/pongo/pongoProjectionSpec.ts","../src/eventStore/projections/pongo/projections.ts","../src/eventStore/projections/postgresProjectionSpec.ts","../src/eventStore/schema/index.ts","../src/eventStore/schema/appendToStream.ts","../src/eventStore/schema/typing.ts","../src/eventStore/schema/tables.ts","../src/eventStore/schema/readStream.ts"],"sourcesContent":["import {\n dumbo,\n type MigrationStyle,\n type NodePostgresClientConnection,\n type NodePostgresConnector,\n type NodePostgresPool,\n type NodePostgresPoolClientConnection,\n} from '@event-driven-io/dumbo';\nimport {\n ExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type DefaultStreamVersionType,\n type Event,\n type EventStore,\n type EventStoreSession,\n type EventStoreSessionFactory,\n type ExpectedStreamVersion,\n type ProjectionRegistration,\n type ReadEventMetadataWithGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport pg from 'pg';\nimport {\n handleProjections,\n type PostgreSQLProjectionHandlerContext,\n} from './projections';\nimport {\n appendToStream,\n createEventStoreSchema,\n readStream,\n schemaSQL,\n type AppendToStreamPreCommitHook,\n} from './schema';\n\nexport interface PostgresEventStore\n extends EventStore<\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n >,\n EventStoreSessionFactory<PostgresEventStore, DefaultStreamVersionType> {\n close(): Promise<void>;\n schema: {\n sql(): string;\n print(): void;\n migrate(): Promise<void>;\n };\n}\n\ntype PostgresEventStorePooledOptions =\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: true;\n pool: pg.Pool;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pool: pg.Pool;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: true;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n };\n\ntype PostgresEventStoreNotPooledOptions =\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: false;\n client: pg.Client;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n client: pg.Client;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: false;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n connection:\n | NodePostgresPoolClientConnection\n | NodePostgresClientConnection;\n pooled?: false;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n dumbo: NodePostgresPool;\n pooled?: false;\n };\n\nexport type PostgresEventStoreConnectionOptions =\n | PostgresEventStorePooledOptions\n | PostgresEventStoreNotPooledOptions;\n\nexport type PostgresEventStoreOptions = {\n projections?: ProjectionRegistration<\n 'inline',\n PostgreSQLProjectionHandlerContext\n >[];\n schema?: { autoMigration?: MigrationStyle };\n connectionOptions?: PostgresEventStoreConnectionOptions;\n};\n\nexport const defaultPostgreSQLOptions: PostgresEventStoreOptions = {\n projections: [],\n schema: { autoMigration: 'CreateOrUpdate' },\n};\n\nexport const getPostgreSQLEventStore = (\n connectionString: string,\n options: PostgresEventStoreOptions = defaultPostgreSQLOptions,\n): PostgresEventStore => {\n const poolOptions = {\n connectionString,\n ...(options.connectionOptions ? options.connectionOptions : {}),\n };\n const pool = 'dumbo' in poolOptions ? poolOptions.dumbo : dumbo(poolOptions);\n let migrateSchema: Promise<void>;\n\n const autoGenerateSchema =\n options.schema?.autoMigration === undefined ||\n options.schema?.autoMigration !== 'None';\n\n const ensureSchemaExists = () => {\n if (!autoGenerateSchema) return Promise.resolve();\n\n if (!migrateSchema) {\n migrateSchema = createEventStoreSchema(pool);\n }\n return migrateSchema;\n };\n\n const inlineProjections = (options.projections ?? [])\n .filter(({ type }) => type === 'inline')\n .map(({ projection }) => projection);\n\n const preCommitHook: AppendToStreamPreCommitHook | undefined =\n inlineProjections.length > 0\n ? (events, { transaction }) =>\n handleProjections({\n projections: inlineProjections,\n connection: {\n connectionString,\n transaction,\n },\n events,\n })\n : undefined;\n\n return {\n schema: {\n sql: () => schemaSQL.join(''),\n print: () => console.log(schemaSQL.join('')),\n migrate: async () => {\n await (migrateSchema = createEventStoreSchema(pool));\n },\n },\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n const { evolve, initialState, read } = options;\n\n const expectedStreamVersion = read?.expectedStreamVersion;\n\n let state = initialState();\n\n const result = await this.readStream<EventType>(streamName, options.read);\n\n if (result === null) return null;\n\n const currentStreamVersion = result.currentStreamVersion;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n );\n\n for (const event of result.events) {\n if (!event) continue;\n\n state = evolve(state, event);\n }\n\n return {\n currentStreamVersion: currentStreamVersion,\n state,\n };\n },\n\n readStream: async <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<\n ReadStreamResult<\n EventType,\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n >\n > => {\n await ensureSchemaExists();\n return readStream<EventType>(pool.execute, streamName, options);\n },\n\n appendToStream: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> => {\n await ensureSchemaExists();\n // TODO: This has to be smarter when we introduce urn-based resolution\n const [firstPart, ...rest] = streamName.split('-');\n\n const streamType =\n firstPart && rest.length > 0 ? firstPart : 'emt:unknown';\n\n const appendResult = await appendToStream(\n pool,\n streamName,\n streamType,\n events,\n {\n ...options,\n preCommitHook,\n },\n );\n\n if (!appendResult.success)\n throw new ExpectedVersionConflictError<bigint>(\n -1n, //TODO: Return actual version in case of error\n options?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n );\n\n return { nextExpectedStreamVersion: appendResult.nextStreamPosition };\n },\n close: () => pool.close(),\n\n async withSession<T = unknown>(\n callback: (\n session: EventStoreSession<\n PostgresEventStore,\n DefaultStreamVersionType\n >,\n ) => Promise<T>,\n ): Promise<T> {\n return await pool.withConnection(async (connection) => {\n const storeOptions: PostgresEventStoreOptions = {\n ...options,\n connectionOptions: {\n connection,\n },\n };\n\n const eventStore = getPostgreSQLEventStore(\n connectionString,\n storeOptions,\n );\n\n return callback({\n eventStore,\n close: () => Promise.resolve(),\n });\n });\n },\n };\n};\n\nconst matchesExpectedVersion = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nconst assertExpectedVersionMatchesCurrent = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n","import { ValidationError } from '../errors';\n\nexport const enum ValidationErrors {\n NOT_A_NONEMPTY_STRING = 'NOT_A_NONEMPTY_STRING',\n NOT_A_POSITIVE_NUMBER = 'NOT_A_POSITIVE_NUMBER',\n NOT_AN_UNSIGNED_BIGINT = 'NOT_AN_UNSIGNED_BIGINT',\n}\n\nexport const isNumber = (val: unknown): val is number =>\n typeof val === 'number' && val === val;\n\nexport const isString = (val: unknown): val is string =>\n typeof val === 'string';\n\nexport const assertNotEmptyString = (value: unknown): string => {\n if (!isString(value) || value.length === 0) {\n throw new ValidationError(ValidationErrors.NOT_A_NONEMPTY_STRING);\n }\n return value;\n};\n\nexport const assertPositiveNumber = (value: unknown): number => {\n if (!isNumber(value) || value <= 0) {\n throw new ValidationError(ValidationErrors.NOT_A_POSITIVE_NUMBER);\n }\n return value;\n};\n\nexport const assertUnsignedBigInt = (value: string): bigint => {\n const number = BigInt(value);\n if (number < 0) {\n throw new ValidationError(ValidationErrors.NOT_AN_UNSIGNED_BIGINT);\n }\n return number;\n};\n\nexport * from './dates';\n","import { isNumber, isString } from '../validation';\n\nexport type ErrorConstructor<ErrorType extends Error> = new (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ...args: any[]\n) => ErrorType;\n\nexport const isErrorConstructor = <ErrorType extends Error>(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n expect: Function,\n): expect is ErrorConstructor<ErrorType> => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return (\n typeof expect === 'function' &&\n expect.prototype &&\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n expect.prototype.constructor === expect\n );\n};\n\nexport class EmmettError extends Error {\n public errorCode: number;\n\n constructor(\n options?: { errorCode: number; message?: string } | string | number,\n ) {\n const errorCode =\n options && typeof options === 'object' && 'errorCode' in options\n ? options.errorCode\n : isNumber(options)\n ? options\n : 500;\n const message =\n options && typeof options === 'object' && 'message' in options\n ? options.message\n : isString(options)\n ? options\n : `Error with status code '${errorCode}' ocurred during Emmett processing`;\n\n super(message);\n this.errorCode = errorCode;\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, EmmettError.prototype);\n }\n}\n\nexport class ConcurrencyError extends EmmettError {\n constructor(\n public current: string | undefined,\n public expected: string,\n message?: string,\n ) {\n super({\n errorCode: 412,\n message:\n message ??\n `Expected version ${expected.toString()} does not match current ${current?.toString()}`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyError.prototype);\n }\n}\n\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 400,\n message: message ?? `Validation Error ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class IllegalStateError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 403,\n message: message ?? `Illegal State ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, IllegalStateError.prototype);\n }\n}\n\nexport class NotFoundError extends EmmettError {\n constructor(options?: { id: string; type: string; message?: string }) {\n super({\n errorCode: 404,\n message:\n options?.message ??\n (options?.id\n ? options.type\n ? `${options.type} with ${options.id} was not found during Emmett processing`\n : `State with ${options.id} was not found during Emmett processing`\n : options?.type\n ? `${options.type} was not found during Emmett processing`\n : 'State was not found during Emmett processing'),\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n","import { ValidationError } from '../errors';\n\nexport const formatDateToUtcYYYYMMDD = (date: Date) => {\n // Use the 'en-CA' locale which formats as 'yyyy-mm-dd'\n const formatter = new Intl.DateTimeFormat('en-CA', {\n timeZone: 'UTC',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n });\n\n // Format the date\n return formatter.format(date);\n};\n\n// Function to validate 'yyyy-mm-dd' format\nexport const isValidYYYYMMDD = (dateString: string) => {\n const regex = /^\\d{4}-\\d{2}-\\d{2}$/;\n return regex.test(dateString);\n};\n\nexport const parseDateFromUtcYYYYMMDD = (dateString: string) => {\n const date = new Date(dateString + 'T00:00:00Z');\n\n if (!isValidYYYYMMDD(dateString)) {\n throw new ValidationError('Invalid date format, must be yyyy-mm-dd');\n }\n\n if (isNaN(date.getTime())) {\n throw new ValidationError('Invalid date format');\n }\n\n return date;\n};\n","import { Command as CliCommand } from 'commander';\n\nexport type EmmettPluginConfig =\n | {\n name: string;\n register: EmmettPluginRegistration[];\n }\n | string;\n\nexport type EmmettPluginType = 'cli';\n\nexport type EmmettCliPluginRegistration = { pluginType: 'cli'; path?: string };\n\nexport type EmmettPluginRegistration = EmmettCliPluginRegistration;\n\nexport type EmmettCliPlugin = {\n pluginType: 'cli';\n name: string;\n registerCommands: (program: CliCommand) => Promise<void> | void;\n};\n\nexport type EmmettPlugin = EmmettCliPlugin;\n\nexport const isPluginConfig = (\n plugin: Partial<EmmettPluginConfig> | string | undefined,\n): plugin is EmmettPluginConfig =>\n plugin !== undefined &&\n (typeof plugin === 'string' ||\n ('name' in plugin &&\n plugin.name !== undefined &&\n typeof plugin.name === 'string'));\n","import type { Event, ReadEvent, ReadEventMetadata } from '../typing';\nimport type { ExpectedStreamVersion } from './expectedVersion';\n\n// #region event-store\nexport interface EventStore<\n StreamVersion = DefaultStreamVersionType,\n ReadEventMetadataType extends ReadEventMetadata = ReadEventMetadata,\n> {\n aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n StreamVersion,\n ReadEventMetadataType\n >,\n ): Promise<AggregateStreamResult<State, StreamVersion> | null>;\n\n readStream<EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions<StreamVersion>,\n ): Promise<ReadStreamResult<EventType, StreamVersion, ReadEventMetadataType>>;\n\n appendToStream<EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<StreamVersion>,\n ): Promise<AppendToStreamResult<StreamVersion>>;\n}\n\nexport type EventStoreSession<\n EventStoreType extends EventStore<StreamVersion>,\n StreamVersion = DefaultStreamVersionType,\n> = {\n eventStore: EventStoreType;\n close: () => Promise<void>;\n};\n\nexport interface EventStoreSessionFactory<\n EventStoreType extends EventStore<StreamVersion>,\n StreamVersion = DefaultStreamVersionType,\n> {\n withSession<T = unknown>(\n callback: (\n session: EventStoreSession<EventStoreType, StreamVersion>,\n ) => Promise<T>,\n ): Promise<T>;\n}\n\nexport type DefaultStreamVersionType = bigint;\n// #endregion event-store\n\nexport const canCreateEventStoreSession = <\n Store extends EventStore<StreamVersion>,\n StreamVersion = DefaultStreamVersionType,\n>(\n eventStore: Store | EventStoreSessionFactory<Store, StreamVersion>,\n): eventStore is EventStoreSessionFactory<Store, StreamVersion> =>\n 'withSession' in eventStore;\n\nexport const nulloSessionFactory = <\n EventStoreType extends EventStore<StreamVersion>,\n StreamVersion = DefaultStreamVersionType,\n>(\n eventStore: EventStoreType,\n): EventStoreSessionFactory<EventStoreType, StreamVersion> => ({\n withSession: (callback) => {\n const nulloSession: EventStoreSession<EventStoreType, StreamVersion> = {\n eventStore,\n close: () => Promise.resolve(),\n };\n\n return callback(nulloSession);\n },\n});\n\n////////////////////////////////////////////////////////////////////\n/// ReadStream types\n////////////////////////////////////////////////////////////////////\n\nexport type ReadStreamOptions<StreamVersion = DefaultStreamVersionType> = (\n | {\n from: StreamVersion;\n }\n | { to: StreamVersion }\n | { from: StreamVersion; maxCount?: bigint }\n | {\n expectedStreamVersion: ExpectedStreamVersion<StreamVersion>;\n }\n) & {\n expectedStreamVersion?: ExpectedStreamVersion<StreamVersion>;\n};\n\nexport type ReadStreamResult<\n EventType extends Event,\n StreamVersion = DefaultStreamVersionType,\n ReadEventMetadataType extends ReadEventMetadata = ReadEventMetadata,\n> = {\n currentStreamVersion: StreamVersion;\n events: ReadEvent<EventType, ReadEventMetadataType>[];\n} | null;\n\n////////////////////////////////////////////////////////////////////\n/// AggregateStream types\n////////////////////////////////////////////////////////////////////\n\ntype Evolve<\n State,\n EventType extends Event,\n ReadEventMetadataType extends ReadEventMetadata = ReadEventMetadata,\n> =\n | ((currentState: State, event: EventType) => State)\n | ((\n currentState: State,\n event: ReadEvent<EventType, ReadEventMetadataType>,\n ) => State)\n | ((currentState: State, event: ReadEvent<EventType>) => State);\n\nexport type AggregateStreamOptions<\n State,\n EventType extends Event,\n StreamVersion = DefaultStreamVersionType,\n ReadEventMetadataType extends ReadEventMetadata = ReadEventMetadata,\n> = {\n evolve: Evolve<State, EventType, ReadEventMetadataType>;\n initialState: () => State;\n read?: ReadStreamOptions<StreamVersion>;\n};\n\nexport type AggregateStreamResult<\n State,\n StreamVersion = DefaultStreamVersionType,\n> = {\n currentStreamVersion: StreamVersion;\n state: State;\n};\n\n////////////////////////////////////////////////////////////////////\n/// AppendToStream types\n////////////////////////////////////////////////////////////////////\n\nexport type AppendToStreamOptions<StreamVersion = DefaultStreamVersionType> = {\n expectedStreamVersion?: ExpectedStreamVersion<StreamVersion>;\n};\n\nexport type AppendToStreamResult<StreamVersion = DefaultStreamVersionType> = {\n nextExpectedStreamVersion: StreamVersion;\n};\n","import { ConcurrencyError } from '../errors';\nimport type { Flavour } from '../typing';\nimport type { DefaultStreamVersionType } from './eventStore';\n\nexport type ExpectedStreamVersion<VersionType = DefaultStreamVersionType> =\n | ExpectedStreamVersionWithValue<VersionType>\n | ExpectedStreamVersionGeneral;\n\nexport type ExpectedStreamVersionWithValue<\n VersionType = DefaultStreamVersionType,\n> = Flavour<VersionType, 'StreamVersion'>;\n\nexport type ExpectedStreamVersionGeneral = Flavour<\n 'STREAM_EXISTS' | 'STREAM_DOES_NOT_EXIST' | 'NO_CONCURRENCY_CHECK',\n 'StreamVersion'\n>;\n\nexport const STREAM_EXISTS = 'STREAM_EXISTS' as ExpectedStreamVersionGeneral;\nexport const STREAM_DOES_NOT_EXIST =\n 'STREAM_DOES_NOT_EXIST' as ExpectedStreamVersionGeneral;\nexport const NO_CONCURRENCY_CHECK =\n 'NO_CONCURRENCY_CHECK' as ExpectedStreamVersionGeneral;\n\nexport const matchesExpectedVersion = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion>,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nexport const assertExpectedVersionMatchesCurrent = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion> | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n\nexport class ExpectedVersionConflictError<\n VersionType = DefaultStreamVersionType,\n> extends ConcurrencyError {\n constructor(\n current: VersionType | undefined,\n expected: ExpectedStreamVersion<VersionType>,\n ) {\n super(current?.toString(), expected?.toString());\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);\n }\n}\n","import { v4 as randomUUID } from 'uuid';\nimport type {\n Event,\n ReadEvent,\n ReadEventMetadataWithGlobalPosition,\n} from '../typing';\nimport {\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type DefaultStreamVersionType,\n type EventStore,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\n\nexport type EventHandler<E extends Event = Event> = (\n eventEnvelope: ReadEvent<E>,\n) => void;\n\nexport const getInMemoryEventStore = (): EventStore<\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n> => {\n const streams = new Map<string, ReadEvent[]>();\n\n const getAllEventsCount = () => {\n return Array.from<ReadEvent[]>(streams.values())\n .map((s) => s.length)\n .reduce((p, c) => p + c, 0);\n };\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n const { evolve, initialState, read } = options;\n\n const result = await this.readStream<EventType>(streamName, read);\n\n if (!result) return null;\n\n const events = result?.events ?? [];\n\n return {\n currentStreamVersion: BigInt(events.length),\n state: events.reduce(evolve, initialState()),\n };\n },\n\n readStream: <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<\n ReadStreamResult<\n EventType,\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n >\n > => {\n const events = streams.get(streamName);\n const currentStreamVersion = events ? BigInt(events.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n );\n\n const from = Number(options && 'from' in options ? options.from : 0);\n const to = Number(\n options && 'to' in options\n ? options.to\n : options && 'maxCount' in options && options.maxCount\n ? options.from + options.maxCount\n : (events?.length ?? 1),\n );\n\n const resultEvents =\n events && events.length > 0\n ? events\n .map(\n (e) =>\n e as ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >,\n )\n .slice(from, to)\n : [];\n\n const result: ReadStreamResult<\n EventType,\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n > =\n events && events.length > 0\n ? {\n currentStreamVersion: currentStreamVersion!,\n events: resultEvents,\n }\n : null;\n\n return Promise.resolve(result);\n },\n\n appendToStream: <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> => {\n const currentEvents = streams.get(streamName) ?? [];\n const currentStreamVersion =\n currentEvents.length > 0 ? BigInt(currentEvents.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n );\n\n const eventEnvelopes: ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >[] = events.map((event, index) => {\n return {\n ...event,\n metadata: {\n ...(event.metadata ?? {}),\n streamName,\n eventId: randomUUID(),\n streamPosition: BigInt(currentEvents.length + index + 1),\n globalPosition: BigInt(getAllEventsCount() + index + 1),\n },\n };\n });\n\n const positionOfLastEventInTheStream = BigInt(\n eventEnvelopes.slice(-1)[0]!.metadata.streamPosition,\n );\n\n streams.set(streamName, [...currentEvents, ...eventEnvelopes]);\n\n const result: AppendToStreamResult = {\n nextExpectedStreamVersion: positionOfLastEventInTheStream,\n };\n\n return Promise.resolve(result);\n },\n };\n};\n","import {\n canCreateEventStoreSession,\n NO_CONCURRENCY_CHECK,\n nulloSessionFactory,\n STREAM_DOES_NOT_EXIST,\n type AppendToStreamResult,\n type DefaultStreamVersionType,\n type EventStore,\n type EventStoreSession,\n type ExpectedStreamVersion,\n} from '../eventStore';\nimport type { Event } from '../typing';\n\n// #region command-handler\nexport type CommandHandlerResult<\n State,\n StreamEvent extends Event,\n StreamVersion = DefaultStreamVersionType,\n> = AppendToStreamResult<StreamVersion> & {\n newState: State;\n newEvents: StreamEvent[];\n};\n\nexport const CommandHandler =\n <State, StreamEvent extends Event, StreamVersion = DefaultStreamVersionType>(\n evolve: (state: State, event: StreamEvent) => State,\n initialState: () => State,\n mapToStreamId: (id: string) => string = (id) => id,\n ) =>\n async <Store extends EventStore<StreamVersion>>(\n store: Store,\n id: string,\n handle: (state: State) => StreamEvent | StreamEvent[],\n options?: Parameters<Store['appendToStream']>[2] & {\n expectedStreamVersion?: ExpectedStreamVersion<StreamVersion>;\n },\n ): Promise<CommandHandlerResult<State, StreamEvent, StreamVersion>> => {\n const result = await withSession<\n Store,\n StreamVersion,\n CommandHandlerResult<State, StreamEvent, StreamVersion>\n >(store, async ({ eventStore }) => {\n const streamName = mapToStreamId(id);\n\n // 1. Aggregate the stream\n const aggregationResult = await eventStore.aggregateStream<\n State,\n StreamEvent\n >(streamName, {\n evolve,\n initialState,\n read: {\n // expected stream version is passed to fail fast\n // if stream is in the wrong state\n expectedStreamVersion:\n options?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n },\n });\n\n // 2. Use the aggregate state or the initial one (when e.g. stream does not exist)\n const state = aggregationResult?.state ?? initialState();\n const currentStreamVersion = aggregationResult?.currentStreamVersion;\n\n // 3. Run business logic\n const result = handle(state);\n\n const newEvents = Array.isArray(result) ? result : [result];\n\n // Either use:\n // - provided expected stream version,\n // - current stream version got from stream aggregation,\n // - or expect stream not to exists otherwise.\n const expectedStreamVersion: ExpectedStreamVersion<StreamVersion> =\n options?.expectedStreamVersion ??\n currentStreamVersion ??\n STREAM_DOES_NOT_EXIST;\n\n // 4. Append result to the stream\n const appendResult = await eventStore.appendToStream(\n streamName,\n newEvents,\n {\n ...options,\n expectedStreamVersion,\n },\n );\n\n // 5. Return result with updated state\n return {\n ...appendResult,\n newEvents,\n newState: newEvents.reduce(evolve, state),\n };\n });\n\n return result;\n };\n// #endregion command-handler\n\nconst withSession = <\n EventStoreType extends EventStore<StreamVersion>,\n StreamVersion = DefaultStreamVersionType,\n T = unknown,\n>(\n eventStore: EventStoreType,\n callback: (\n session: EventStoreSession<EventStoreType, StreamVersion>,\n ) => Promise<T>,\n) => {\n const sessionFactory = canCreateEventStoreSession<\n EventStoreType,\n StreamVersion\n >(eventStore)\n ? eventStore\n : nulloSessionFactory<EventStoreType, StreamVersion>(eventStore);\n\n return sessionFactory.withSession(callback);\n};\n","import type {\n DefaultStreamVersionType,\n EventStore,\n ExpectedStreamVersion,\n} from '../eventStore';\nimport type { Command, Event } from '../typing';\nimport type { Decider } from '../typing/decider';\nimport { CommandHandler } from './handleCommand';\n\n// #region command-handler\nexport const DeciderCommandHandler =\n <\n State,\n CommandType extends Command,\n StreamEvent extends Event,\n StreamVersion = DefaultStreamVersionType,\n >(\n { decide, evolve, initialState }: Decider<State, CommandType, StreamEvent>,\n mapToStreamId: (id: string) => string = (id) => id,\n ) =>\n async (\n eventStore: EventStore<StreamVersion>,\n id: string,\n command: CommandType,\n options?: {\n expectedStreamVersion?: ExpectedStreamVersion<StreamVersion>;\n },\n ) =>\n CommandHandler<State, StreamEvent, StreamVersion>(\n evolve,\n initialState,\n mapToStreamId,\n )(eventStore, id, (state) => decide(command, state), options);\n// #endregion command-handler\n","import type { DefaultRecord, Flavour } from './';\nexport type Command<\n CommandType extends string = string,\n CommandData extends DefaultRecord = DefaultRecord,\n CommandMetaData extends DefaultRecord = DefaultCommandMetadata,\n> = Flavour<\n Readonly<{\n type: CommandType;\n data: Readonly<CommandData>;\n metadata?: CommandMetaData | undefined;\n }>,\n 'Command'\n>;\n\nexport type CommandTypeOf<T extends Command> = T['type'];\nexport type CommandDataOf<T extends Command> = T['data'];\nexport type CommandMetaDataOf<T extends Command> = T['metadata'];\n\nexport type CreateCommandType<\n CommandType extends string,\n CommandData extends DefaultRecord,\n CommandMetaData extends DefaultRecord | undefined,\n> = Readonly<{\n type: CommandType;\n data: CommandData;\n metadata?: CommandMetaData;\n}>;\n\nexport const command = <CommandType extends Command>(\n type: CommandTypeOf<CommandType>,\n data: CommandDataOf<CommandType>,\n metadata?: CommandMetaDataOf<CommandType>,\n): CreateCommandType<\n CommandTypeOf<CommandType>,\n CommandDataOf<CommandType>,\n CommandMetaDataOf<CommandType>\n> => {\n return {\n type,\n data,\n metadata,\n };\n};\n\nexport type DefaultCommandMetadata = { now: Date };\n","import type { DefaultRecord, Flavour } from './';\n\nexport type Event<\n EventType extends string = string,\n EventData extends DefaultRecord = DefaultRecord,\n EventMetaData extends DefaultRecord = DefaultRecord,\n> = Flavour<\n Readonly<{\n type: EventType;\n data: EventData;\n metadata?: EventMetaData;\n }>,\n 'Event'\n>;\n\nexport type EventTypeOf<T extends Event> = T['type'];\nexport type EventDataOf<T extends Event> = T['data'];\nexport type EventMetaDataOf<T extends Event> = T['metadata'];\n\nexport type CanHandle<T extends Event> = EventTypeOf<T>[];\n\nexport type CreateEventType<\n EventType extends string,\n EventData extends DefaultRecord,\n EventMetaData extends DefaultRecord | undefined,\n> = Readonly<{\n type: EventType;\n data: EventData;\n metadata?: EventMetaData;\n}>;\n\nexport const event = <EventType extends Event>(\n type: EventTypeOf<EventType>,\n data: EventDataOf<EventType>,\n metadata?: EventMetaDataOf<EventType>,\n): CreateEventType<\n EventTypeOf<EventType>,\n EventDataOf<EventType>,\n EventMetaDataOf<EventType>\n> => {\n return {\n type,\n data,\n metadata,\n };\n};\n\nexport type ReadEvent<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n> = CreateEventType<\n EventTypeOf<EventType>,\n EventDataOf<EventType>,\n EventMetaDataType\n> &\n EventType & { metadata: EventMetaDataType };\n\nexport type ReadEventMetadata = Readonly<{\n eventId: string;\n streamPosition: bigint;\n streamName: string;\n}>;\n\nexport type ReadEventMetadataWithGlobalPosition = ReadEventMetadata & {\n globalPosition: bigint;\n};\n","import type { Command } from './command';\nimport type { Event } from './event';\n\n/// Inspired by https://blog.bittacklr.be/the-workflow-pattern.html\n\nexport type Workflow<\n Input extends Event | Command,\n State,\n Output extends Event | Command,\n> = {\n decide: (command: Input, state: State) => WorkflowOutput<Output>[];\n evolve: (currentState: State, event: WorkflowEvent<Output>) => State;\n initialState: () => State;\n};\n\nexport type WorkflowEvent<Output extends Command | Event> = Extract<\n Output,\n { __brand?: 'Event' }\n>;\n\nexport type WorkflowCommand<Output extends Command | Event> = Extract<\n Output,\n { __brand?: 'Command' }\n>;\n\nexport type WorkflowOutput<TOutput extends Command | Event> =\n | { kind: 'Reply'; message: TOutput }\n | { kind: 'Send'; message: WorkflowCommand<TOutput> }\n | { kind: 'Publish'; message: WorkflowEvent<TOutput> }\n | {\n kind: 'Schedule';\n message: TOutput;\n when: { afterInMs: number } | { at: Date };\n }\n | { kind: 'Complete' }\n | { kind: 'Accept' }\n | { kind: 'Ignore'; reason: string }\n | { kind: 'Error'; reason: string };\n\nexport const reply = <TOutput extends Command | Event>(\n message: TOutput,\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Reply',\n message,\n };\n};\n\nexport const send = <TOutput extends Command | Event>(\n message: WorkflowCommand<TOutput>,\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Send',\n message,\n };\n};\n\nexport const publish = <TOutput extends Command | Event>(\n message: WorkflowEvent<TOutput>,\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Publish',\n message,\n };\n};\n\nexport const schedule = <TOutput extends Command | Event>(\n message: TOutput,\n when: { afterInMs: number } | { at: Date },\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Schedule',\n message,\n when,\n };\n};\n\nexport const complete = <\n TOutput extends Command | Event,\n>(): WorkflowOutput<TOutput> => {\n return {\n kind: 'Complete',\n };\n};\n\nexport const ignore = <TOutput extends Command | Event>(\n reason: string,\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Ignore',\n reason,\n };\n};\n\nexport const error = <TOutput extends Command | Event>(\n reason: string,\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Error',\n reason,\n };\n};\n\nexport const accept = <\n TOutput extends Command | Event,\n>(): WorkflowOutput<TOutput> => {\n return { kind: 'Accept' };\n};\n","import { EmmettError } from '../errors';\nimport {\n type Command,\n type CommandTypeOf,\n type Event,\n type EventTypeOf,\n} from '../typing';\n\nexport interface CommandSender {\n send<CommandType extends Command = Command>(\n command: CommandType,\n ): Promise<void>;\n}\n\nexport interface EventsPublisher {\n publish<EventType extends Event = Event>(event: EventType): Promise<void>;\n}\n\nexport type ScheduleOptions = { afterInMs: number } | { at: Date };\n\nexport interface MessageScheduler<CommandOrEvent extends Command | Event> {\n schedule<MessageType extends CommandOrEvent>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void;\n}\n\nexport interface CommandBus extends CommandSender, MessageScheduler<Command> {}\n\nexport interface EventBus extends EventsPublisher, MessageScheduler<Event> {}\n\nexport interface MessageBus extends CommandBus, EventBus {\n schedule<MessageType extends Command | Event>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void;\n}\n\ntype CommandHandler<CommandType extends Command = Command> = (\n command: CommandType,\n) => Promise<void> | void;\n\nexport interface CommandProcessor {\n handle<CommandType extends Command>(\n commandHandler: CommandHandler<CommandType>,\n ...commandTypes: CommandTypeOf<CommandType>[]\n ): void;\n}\n\ntype EventHandler<EventType extends Event = Event> = (\n event: EventType,\n) => Promise<void> | void;\n\nexport interface EventProcessor {\n subscribe<EventType extends Event>(\n eventHandler: EventHandler<EventType>,\n ...eventTypes: EventTypeOf<EventType>[]\n ): void;\n}\n\nexport type ScheduledMessage = {\n message: Event | Command;\n options?: ScheduleOptions;\n};\n\nexport interface ScheduledMessageProcessor {\n dequeue(): ScheduledMessage[];\n}\n\nexport type MessageHandler = CommandHandler | EventHandler;\n\nexport type MessageProcessor = EventProcessor | CommandProcessor;\n\nexport const getInMemoryMessageBus = (): MessageBus &\n EventProcessor &\n CommandProcessor &\n ScheduledMessageProcessor => {\n const allHandlers = new Map<string, MessageHandler[]>();\n let pendingMessages: ScheduledMessage[] = [];\n\n return {\n send: async <CommandType extends Command = Command>(\n command: CommandType,\n ): Promise<void> => {\n const handlers = allHandlers.get(command.type);\n\n if (handlers === undefined || handlers.length === 0)\n throw new EmmettError(\n `No handler registered for command ${command.type}!`,\n );\n\n const commandHandler = handlers[0] as CommandHandler<CommandType>;\n\n await commandHandler(command);\n },\n\n publish: async <EventType extends Event = Event>(\n event: EventType,\n ): Promise<void> => {\n const handlers = allHandlers.get(event.type) ?? [];\n\n for (const handler of handlers) {\n const eventHandler = handler as EventHandler<EventType>;\n\n await eventHandler(event);\n }\n },\n\n schedule: <MessageType extends Command | Event>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void => {\n pendingMessages = [...pendingMessages, { message, options: when }];\n },\n\n handle: <CommandType extends Command>(\n commandHandler: CommandHandler<CommandType>,\n ...commandTypes: CommandTypeOf<CommandType>[]\n ): void => {\n const alreadyRegistered = [...allHandlers.keys()].filter((registered) =>\n commandTypes.includes(registered),\n );\n\n if (alreadyRegistered.length > 0)\n throw new EmmettError(\n `Cannot register handler for commands ${alreadyRegistered.join(', ')} as they're already registered!`,\n );\n for (const commandType of commandTypes) {\n allHandlers.set(commandType, [commandHandler as MessageHandler]);\n }\n },\n\n subscribe<EventType extends Event>(\n eventHandler: EventHandler<EventType>,\n ...eventTypes: EventTypeOf<EventType>[]\n ): void {\n for (const eventType of eventTypes) {\n if (!allHandlers.has(eventType)) allHandlers.set(eventType, []);\n\n allHandlers.set(eventType, [\n ...(allHandlers.get(eventType) ?? []),\n eventHandler as MessageHandler,\n ]);\n }\n },\n\n dequeue: (): ScheduledMessage[] => {\n const pending = pendingMessages;\n pendingMessages = [];\n return pending;\n },\n };\n};\n","import type {\n CanHandle,\n DefaultRecord,\n Event,\n EventMetaDataOf,\n ReadEvent,\n ReadEventMetadata,\n} from '../typing';\n\nexport type ProjectionHandlingType = 'inline' | 'async';\n\nexport type ProjectionHandler<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = (\n events: ReadEvent<EventType, EventMetaDataType>[],\n context: ProjectionHandlerContext,\n) => Promise<void> | void;\n\nexport interface ProjectionDefinition<\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> {\n name?: string;\n canHandle: CanHandle<Event>;\n handle: ProjectionHandler<Event, ReadEventMetadata, ProjectionHandlerContext>;\n}\n\nexport interface TypedProjectionDefinition<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> {\n name?: string;\n canHandle: CanHandle<EventType>;\n handle: ProjectionHandler<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n >;\n}\n\nexport type ProjectionRegistration<\n HandlingType extends ProjectionHandlingType,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n type: HandlingType;\n projection: ProjectionDefinition<ProjectionHandlerContext>;\n};\n\nexport const projection = <\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n ProjectionDefintionType extends TypedProjectionDefinition<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n > = ProjectionDefinition<ProjectionHandlerContext>,\n>(\n definition: ProjectionDefintionType,\n): ProjectionDefintionType => definition;\n\nexport const inlineProjections = <\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n ProjectionDefintionType extends\n ProjectionDefinition<ProjectionHandlerContext> = ProjectionDefinition<ProjectionHandlerContext>,\n>(\n definitions: ProjectionDefintionType[],\n): ProjectionRegistration<'inline', ProjectionHandlerContext>[] =>\n definitions.map((projection) => ({ type: 'inline', projection }));\n\nexport const asyncProjections = <\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n ProjectionDefintionType extends\n ProjectionDefinition<ProjectionHandlerContext> = ProjectionDefinition<ProjectionHandlerContext>,\n>(\n definitions: ProjectionDefintionType[],\n): ProjectionRegistration<'async', ProjectionHandlerContext>[] =>\n definitions.map((projection) => ({ type: 'async', projection }));\n\nexport const projections = {\n inline: inlineProjections,\n async: asyncProjections,\n};\n","export class ParseError extends Error {\n constructor(text: string) {\n super(`Cannot parse! ${text}`);\n }\n}\n\nexport type Mapper<From, To = From> =\n | ((value: unknown) => To)\n | ((value: Partial<From>) => To)\n | ((value: From) => To)\n | ((value: Partial<To>) => To)\n | ((value: To) => To)\n | ((value: Partial<To | From>) => To)\n | ((value: To | From) => To);\n\nexport type MapperArgs<From, To = From> = Partial<From> &\n From &\n Partial<To> &\n To;\n\nexport type ParseOptions<From, To = From> = {\n reviver?: (key: string, value: unknown) => unknown;\n map?: Mapper<From, To>;\n typeCheck?: <To>(value: unknown) => value is To;\n};\n\nexport type StringifyOptions<From, To = From> = {\n map?: Mapper<From, To>;\n};\n\nexport const JSONParser = {\n stringify: <From, To = From>(\n value: From,\n options?: StringifyOptions<From, To>,\n ) => {\n return JSON.stringify(\n options?.map ? options.map(value as MapperArgs<From, To>) : value,\n //TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n (_, v) => (typeof v === 'bigint' ? v.toString() : v),\n );\n },\n parse: <From, To = From>(\n text: string,\n options?: ParseOptions<From, To>,\n ): To | undefined => {\n const parsed: unknown = JSON.parse(text, options?.reviver);\n\n if (options?.typeCheck && !options?.typeCheck<To>(parsed))\n throw new ParseError(text);\n\n return options?.map\n ? options.map(parsed as MapperArgs<From, To>)\n : (parsed as To | undefined);\n },\n};\n","export const concatUint8Arrays = (chunks: Uint8Array[]): Uint8Array => {\n const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n return result;\n};\n","import type { ReadableStream } from 'web-streams-polyfill';\n\nexport const collectStream = async <T>(\n reader: ReadableStream<T>,\n): Promise<T[]> => {\n const results: T[] = [];\n\n for await (const value of reader) {\n results.push(value as T);\n }\n return results;\n};\n","import type { Decoder } from '.';\nimport { concatUint8Arrays } from '../binaryArrays';\n\nexport class BinaryJsonDecoder<Decoded>\n implements Decoder<Uint8Array, Decoded>\n{\n private buffer: Uint8Array[] = [];\n\n addToBuffer(data: Uint8Array): void {\n this.buffer.push(data);\n }\n\n clearBuffer(): void {\n this.buffer = [];\n }\n\n hasCompleteMessage(): boolean {\n const combined = concatUint8Arrays(this.buffer);\n const text = new TextDecoder().decode(combined);\n return text.includes('\\n');\n }\n\n decode(): Decoded | null {\n if (!this.hasCompleteMessage()) {\n return null;\n }\n\n const combined = concatUint8Arrays(this.buffer);\n const text = new TextDecoder().decode(combined);\n const delimiterIndex = text.indexOf('\\n');\n\n if (delimiterIndex === -1) {\n return null;\n }\n\n const jsonString = text.slice(0, delimiterIndex);\n const remaining = new Uint8Array(combined.buffer, delimiterIndex + 1);\n this.buffer = remaining.byteLength > 0 ? [remaining] : [];\n\n return JSON.parse(jsonString) as Decoded;\n }\n}\n","import type { Decoder } from '.';\n\nexport class StringDecoder<Decoded> implements Decoder<string, Decoded> {\n protected buffer: string[] = [];\n\n constructor(private transform: (input: string) => Decoded) {\n this.transform = transform;\n }\n\n addToBuffer(data: string): void {\n this.buffer.push(data);\n }\n\n clearBuffer(): void {\n this.buffer = [];\n }\n\n hasCompleteMessage(): boolean {\n return this.buffer.some((chunk) => chunk.includes('\\n'));\n }\n\n decode(): Decoded | null {\n const completeString = this.buffer.join('');\n\n if (!this.hasCompleteMessage()) {\n if (completeString.trim().length > 0) {\n throw new Error('Unterminated string in JSON at position');\n }\n return null;\n }\n\n const delimiterIndex = completeString.indexOf('\\n');\n const message = completeString.slice(0, delimiterIndex).trim();\n this.buffer = [completeString.slice(delimiterIndex + 1)];\n\n return this.transform(message);\n }\n}\n","import { StringDecoder } from './string';\n\nexport class JsonDecoder<Decoded> extends StringDecoder<Decoded> {\n constructor() {\n super((jsonString) => JSON.parse(jsonString) as Decoded);\n }\n}\n","import type { Decoder } from '.';\n\nexport class ObjectDecoder<Decoded> implements Decoder<Decoded, Decoded> {\n private buffer: Decoded | null = null;\n\n addToBuffer(data: Decoded): void {\n this.buffer = data;\n }\n\n clearBuffer(): void {\n this.buffer = null;\n }\n\n hasCompleteMessage(): boolean {\n return this.buffer !== null;\n }\n\n decode(): Decoded | null {\n if (!this.hasCompleteMessage() || !this.buffer) {\n return null;\n }\n\n const data = this.buffer;\n this.clearBuffer();\n return data as Decoded;\n }\n}\n","import type { Decoder } from '.';\nimport { BinaryJsonDecoder } from './binary';\nimport { JsonDecoder } from './json';\nimport { ObjectDecoder } from './object';\n\nexport class CompositeDecoder<Decoded> implements Decoder<unknown, Decoded> {\n constructor(\n private decoders: [(data: unknown) => boolean, Decoder<unknown, Decoded>][],\n ) {}\n\n private decoderFor(data: unknown): Decoder<unknown, unknown> | null {\n const decoder = this.decoders.find((d) => d[0](data));\n\n if (!decoder) return null;\n\n return decoder[1];\n }\n\n addToBuffer(data: unknown): void {\n this.decoderFor(data)?.addToBuffer(data);\n }\n\n clearBuffer(): void {\n for (const decoder of this.decoders.map((d) => d[1])) {\n decoder.clearBuffer();\n }\n }\n\n hasCompleteMessage(): boolean {\n return this.decoders.some((d) => d[1].hasCompleteMessage());\n }\n\n decode(): Decoded | null {\n const decoder = this.decoders\n .map((d) => d[1])\n .find((d) => d.hasCompleteMessage());\n\n return decoder?.decode() ?? null;\n }\n}\n\nexport class DefaultDecoder<Decoded> extends CompositeDecoder<Decoded> {\n constructor() {\n super([\n [(data) => typeof data === 'string', new JsonDecoder<Decoded>()],\n [(data) => data instanceof Uint8Array, new BinaryJsonDecoder<Decoded>()],\n [(data) => typeof data === 'object', new ObjectDecoder<Decoded>()],\n ]);\n }\n}\n","import retry from 'async-retry';\nimport {\n ReadableStream,\n ReadableStreamDefaultReader,\n TransformStream,\n TransformStreamDefaultController,\n} from 'web-streams-polyfill';\nimport type { Decoder } from './decoders';\nimport { DefaultDecoder } from './decoders/composite';\n\nexport const restream = <\n Source = unknown,\n Transformed = Source,\n StreamType = object,\n>(\n createSourceStream: () => ReadableStream<StreamType>,\n transform: (input: Source) => Transformed = (source) =>\n source as unknown as Transformed,\n retryOptions: retry.Options = { forever: true, minTimeout: 25 },\n decoder: Decoder<StreamType, Source> = new DefaultDecoder<Source>(),\n): ReadableStream<Transformed> =>\n new TransformStream<Source, Transformed>({\n start(controller) {\n retry(\n () => onRestream(createSourceStream, controller, transform, decoder),\n retryOptions,\n ).catch((error) => {\n controller.error(error);\n });\n },\n }).readable;\n\nconst onRestream = async <StreamType, Source, Transformed = Source>(\n createSourceStream: () => ReadableStream<StreamType>,\n controller: TransformStreamDefaultController<Transformed>,\n transform: (input: Source) => Transformed,\n decoder: Decoder<StreamType, Source>,\n): Promise<void> => {\n const sourceStream = createSourceStream();\n const reader = sourceStream.getReader();\n try {\n let done: boolean;\n\n do {\n done = await restreamChunk(reader, controller, transform, decoder);\n } while (!done);\n } finally {\n reader.releaseLock();\n }\n};\n\nconst restreamChunk = async <StreamType, Source, Transformed = Source>(\n reader: ReadableStreamDefaultReader<StreamType>,\n controller: TransformStreamDefaultController<Transformed>,\n transform: (input: Source) => Transformed,\n decoder: Decoder<StreamType, Source>,\n): Promise<boolean> => {\n const { done: isDone, value } = await reader.read();\n\n if (value) decoder.addToBuffer(value);\n\n if (!isDone && !decoder.hasCompleteMessage()) return false;\n\n decodeAndTransform(decoder, transform, controller);\n\n if (isDone) {\n controller.terminate();\n }\n\n return isDone;\n};\n\nconst decodeAndTransform = <StreamType, Source, Transformed = Source>(\n decoder: Decoder<StreamType, Source>,\n transform: (input: Source) => Transformed,\n controller: TransformStreamDefaultController<Transformed>,\n) => {\n try {\n const decoded = decoder.decode();\n if (!decoded) return;\n\n const transformed = transform(decoded);\n controller.enqueue(transformed);\n } catch (error) {\n controller.error(new Error(`Decoding error: ${error?.toString()}`));\n }\n};\n","export const deepEquals = <T>(left: T, right: T): boolean => {\n if (isEquatable(left)) {\n return left.equals(right);\n }\n\n if (Array.isArray(left)) {\n return (\n Array.isArray(right) &&\n left.length === right.length &&\n left.every((val, index) => deepEquals(val, right[index]))\n );\n }\n\n if (\n typeof left !== 'object' ||\n typeof right !== 'object' ||\n left === null ||\n right === null\n ) {\n return left === right;\n }\n\n if (Array.isArray(right)) return false;\n\n const keys1 = Object.keys(left);\n const keys2 = Object.keys(right);\n\n if (\n keys1.length !== keys2.length ||\n !keys1.every((key) => keys2.includes(key))\n )\n return false;\n\n for (const key in left) {\n if (left[key] instanceof Function && right[key] instanceof Function)\n continue;\n\n const isEqual = deepEquals(left[key], right[key]);\n if (!isEqual) {\n return false;\n }\n }\n\n return true;\n};\n\nexport type Equatable<T> = { equals: (right: T) => boolean } & T;\n\nexport const isEquatable = <T>(left: T): left is Equatable<T> => {\n return (\n left &&\n typeof left === 'object' &&\n 'equals' in left &&\n typeof left['equals'] === 'function'\n );\n};\n","export const sum = (\n iterator: Iterator<number, number, number> | Iterator<number>,\n) => {\n let value,\n done: boolean | undefined,\n sum = 0;\n do {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n ({ value, done } = iterator.next());\n sum += value || 0;\n } while (!done);\n return sum;\n};\n","export const merge = <T>(\n array: T[],\n item: T,\n where: (current: T) => boolean,\n onExisting: (current: T) => T,\n onNotFound: () => T | undefined = () => undefined,\n) => {\n let wasFound = false;\n\n const result = array\n // merge the existing item if matches condition\n .map((p: T) => {\n if (!where(p)) return p;\n\n wasFound = true;\n return onExisting(p);\n })\n // filter out item if undefined was returned\n // for cases of removal\n .filter((p) => p !== undefined)\n // make TypeScript happy\n .map((p) => {\n if (!p) throw Error('That should not happen');\n\n return p;\n });\n\n // if item was not found and onNotFound action is defined\n // try to generate new item\n if (!wasFound) {\n const result = onNotFound();\n\n if (result !== undefined) return [...array, item];\n }\n\n return result;\n};\n","import { JSONParser } from '../serialization';\nimport type { DefaultRecord } from '../typing';\nimport { deepEquals } from '../utils';\n\nexport class AssertionError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\nexport const isSubset = (superObj: unknown, subObj: unknown): boolean => {\n const sup = superObj as DefaultRecord;\n const sub = subObj as DefaultRecord;\n\n assertOk(sup);\n assertOk(sub);\n\n return Object.keys(sub).every((ele: string) => {\n if (typeof sub[ele] == 'object') {\n return isSubset(sup[ele], sub[ele]);\n }\n return sub[ele] === sup[ele];\n });\n};\n\nexport const assertFails = (message?: string) => {\n throw new AssertionError(message ?? 'That should not ever happened, right?');\n};\n\nexport const assertThrowsAsync = async <TError extends Error>(\n fun: () => Promise<void>,\n errorCheck?: (error: Error) => boolean,\n): Promise<TError> => {\n try {\n await fun();\n throw new AssertionError(\"Function didn't throw expected error\");\n } catch (error) {\n const typedError = error as TError;\n if (errorCheck) assertTrue(errorCheck(typedError));\n return typedError;\n }\n};\n\nexport const assertThrows = <TError extends Error>(\n fun: () => void,\n errorCheck?: (error: Error) => boolean,\n): TError => {\n try {\n fun();\n throw new AssertionError(\"Function didn't throw expected error\");\n } catch (error) {\n const typedError = error as TError;\n if (errorCheck) assertTrue(errorCheck(typedError));\n return typedError;\n }\n};\nexport const assertMatches = (\n actual: unknown,\n expected: unknown,\n message?: string,\n) => {\n if (!isSubset(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONParser.stringify(expected)}\\nis not subset of\\n${JSONParser.stringify(actual)}`,\n );\n};\n\nexport const assertDeepEqual = <T = unknown>(\n actual: T,\n expected: T,\n message?: string,\n) => {\n if (!deepEquals(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONParser.stringify(expected)}\\nis not equal to\\n${JSONParser.stringify(actual)}`,\n );\n};\n\nexport const assertNotDeepEqual = <T = unknown>(\n actual: T,\n expected: T,\n message?: string,\n) => {\n if (deepEquals(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONParser.stringify(expected)}\\nis equals to\\n${JSONParser.stringify(actual)}`,\n );\n};\n\nexport const assertThat = <T>(item: T) => {\n return {\n isEqualTo: (other: T) => assertTrue(deepEquals(item, other)),\n };\n};\n\nexport function assertFalse(\n condition: boolean,\n message?: string,\n): asserts condition is false {\n if (condition) throw new AssertionError(message ?? `Condition is false`);\n}\n\nexport function assertTrue(\n condition: boolean,\n message?: string,\n): asserts condition is true {\n if (!condition) throw new AssertionError(message ?? `Condition is false`);\n}\n\nexport function assertOk<T>(\n obj: T | null | undefined,\n message?: string,\n): asserts obj is T {\n if (!obj) throw new AssertionError(message ?? `Condition is not truthy`);\n}\n\nexport function assertEqual<T>(\n expected: T | null | undefined,\n actual: T | null | undefined,\n message?: string,\n): void {\n if (expected !== actual)\n throw new AssertionError(\n `${message ?? 'Objects are not equal'}:\\nExpected: ${JSONParser.stringify(expected)}\\nActual:${JSONParser.stringify(actual)}`,\n );\n}\n\nexport function assertNotEqual<T>(\n obj: T | null | undefined,\n other: T | null | undefined,\n message?: string,\n): void {\n if (obj === other)\n throw new AssertionError(\n message ?? `Objects are equal: ${JSONParser.stringify(obj)}`,\n );\n}\n\nexport function assertIsNotNull<T extends object | bigint>(\n result: T | null,\n): asserts result is T {\n assertNotEqual(result, null);\n assertOk(result);\n}\n\nexport function assertIsNull<T extends object>(\n result: T | null,\n): asserts result is null {\n assertEqual(result, null);\n}\n\ntype Call = {\n arguments: unknown[];\n result: unknown;\n target: unknown;\n this: unknown;\n};\n\nexport type ArgumentMatcher = (arg: unknown) => boolean;\n\nexport const argValue =\n <T>(value: T): ArgumentMatcher =>\n (arg) =>\n deepEquals(arg, value);\n\nexport const argMatches =\n <T>(matches: (arg: T) => boolean): ArgumentMatcher =>\n (arg) =>\n matches(arg as T);\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport type MockedFunction = Function & { mock?: { calls: Call[] } };\n\nexport function verifyThat(fn: MockedFunction) {\n return {\n calledTimes: (times: number) => {\n assertEqual(fn.mock?.calls?.length, times);\n },\n notCalled: () => {\n assertEqual(fn?.mock?.calls?.length, 0);\n },\n called: () => {\n assertTrue(\n fn.mock?.calls.length !== undefined && fn.mock.calls.length > 0,\n );\n },\n calledWith: (...args: unknown[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls.some((call) => deepEquals(call.arguments, args)),\n );\n },\n calledOnceWith: (...args: unknown[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length === 1 &&\n fn.mock.calls.some((call) => deepEquals(call.arguments, args)),\n );\n },\n calledWithArgumentMatching: (...matches: ArgumentMatcher[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined && fn.mock.calls.length >= 1,\n );\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls.some(\n (call) =>\n call.arguments &&\n call.arguments.length >= matches.length &&\n matches.every((match, index) => match(call.arguments[index])),\n ),\n );\n },\n notCalledWithArgumentMatching: (...matches: ArgumentMatcher[]) => {\n assertFalse(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls[0]!.arguments &&\n fn.mock.calls[0]!.arguments.length >= matches.length &&\n matches.every((match, index) =>\n match(fn.mock!.calls[0]!.arguments[index]),\n ),\n );\n },\n };\n}\n\nexport const assertThatArray = <T>(array: T[]) => {\n return {\n isEmpty: () => assertEqual(array.length, 0),\n isNotEmpty: () => assertNotEqual(array.length, 0),\n hasSize: (length: number) => assertEqual(array.length, length),\n containsElements: (...other: T[]) => {\n assertTrue(other.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyInAnyOrder: (...other: T[]) => {\n assertEqual(array.length, other.length);\n assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyInAnyOrderElementsOf: (other: T[]) => {\n assertEqual(array.length, other.length);\n assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyElementsOf: (other: T[]) => {\n assertEqual(array.length, other.length);\n for (let i = 0; i < array.length; i++) {\n assertTrue(deepEquals(array[i], other[i]));\n }\n },\n containsExactly: (elem: T) => {\n assertEqual(array.length, 1);\n assertTrue(deepEquals(array[0], elem));\n },\n contains: (elem: T) => {\n assertTrue(array.some((a) => deepEquals(a, elem)));\n },\n containsOnlyOnceElementsOf: (other: T[]) => {\n assertTrue(\n other\n .map((o) => array.filter((a) => deepEquals(a, o)).length)\n .filter((a) => a === 1).length === other.length,\n );\n },\n containsAnyOf: (...other: T[]) => {\n assertTrue(array.some((a) => other.some((o) => deepEquals(a, o))));\n },\n allMatch: (matches: (item: T) => boolean) => {\n assertTrue(array.every(matches));\n },\n anyMatches: (matches: (item: T) => boolean) => {\n assertTrue(array.some(matches));\n },\n allMatchAsync: async (\n matches: (item: T) => Promise<boolean>,\n ): Promise<void> => {\n for (const item of array) {\n assertTrue(await matches(item));\n }\n },\n };\n};\n","import { isErrorConstructor, type ErrorConstructor } from '../errors';\nimport { AssertionError, assertMatches, assertTrue } from './assertions';\n\ntype ErrorCheck<ErrorType> = (error: ErrorType) => boolean;\n\nexport type ThenThrows<ErrorType extends Error> =\n | (() => void)\n | ((errorConstructor: ErrorConstructor<ErrorType>) => void)\n | ((errorCheck: ErrorCheck<ErrorType>) => void)\n | ((\n errorConstructor: ErrorConstructor<ErrorType>,\n errorCheck?: ErrorCheck<ErrorType>,\n ) => void);\n\nexport type DeciderSpecfication<Command, Event> = (\n givenEvents: Event | Event[],\n) => {\n when: (command: Command) => {\n then: (expectedEvents: Event | Event[]) => void;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => void;\n };\n};\n\nexport const DeciderSpecification = {\n for: <Command, Event, State>(decider: {\n decide: (command: Command, state: State) => Event | Event[];\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n }): DeciderSpecfication<Command, Event> => {\n {\n return (givenEvents: Event | Event[]) => {\n return {\n when: (command: Command) => {\n const handle = () => {\n const existingEvents = Array.isArray(givenEvents)\n ? givenEvents\n : [givenEvents];\n\n const currentState = existingEvents.reduce<State>(\n decider.evolve,\n decider.initialState(),\n );\n\n return decider.decide(command, currentState);\n };\n\n return {\n then: (expectedEvents: Event | Event[]): void => {\n const resultEvents = handle();\n\n const resultEventsArray = Array.isArray(resultEvents)\n ? resultEvents\n : [resultEvents];\n\n const expectedEventsArray = Array.isArray(expectedEvents)\n ? expectedEvents\n : [expectedEvents];\n\n assertMatches(resultEventsArray, expectedEventsArray);\n },\n thenThrows: <ErrorType extends Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): void => {\n try {\n handle();\n throw new AssertionError('Handler did not fail as expected');\n } catch (error) {\n if (error instanceof AssertionError) throw error;\n\n if (args.length === 0) return;\n\n if (!isErrorConstructor(args[0])) {\n assertTrue(\n args[0](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n return;\n }\n\n assertTrue(\n error instanceof args[0],\n `Caught error is not an instance of the expected type: ${error?.toString()}`,\n );\n\n if (args[1]) {\n assertTrue(\n args[1](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n }\n }\n },\n };\n },\n };\n };\n }\n },\n};\n","import type {\n AggregateStreamOptions,\n AggregateStreamResult,\n AppendToStreamOptions,\n AppendToStreamResult,\n DefaultStreamVersionType,\n EventStore,\n ReadStreamOptions,\n ReadStreamResult,\n} from '../eventStore';\nimport { type Event } from '../typing';\n\nexport type TestEventStream<EventType extends Event = Event> = [\n string,\n EventType[],\n];\n\nexport const WrapEventStore = <StreamVersion = DefaultStreamVersionType>(\n eventStore: EventStore<StreamVersion>,\n): EventStore<StreamVersion> & {\n appendedEvents: Map<string, TestEventStream>;\n setup<EventType extends Event>(\n streamName: string,\n events: EventType[],\n ): Promise<AppendToStreamResult<StreamVersion>>;\n} => {\n const appendedEvents = new Map<string, TestEventStream>();\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType, StreamVersion>,\n ): Promise<AggregateStreamResult<State, StreamVersion> | null> {\n return eventStore.aggregateStream(streamName, options);\n },\n\n readStream<EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions<StreamVersion>,\n ): Promise<ReadStreamResult<EventType, StreamVersion>> {\n return eventStore.readStream(streamName, options);\n },\n\n appendToStream: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<StreamVersion>,\n ): Promise<AppendToStreamResult<StreamVersion>> => {\n const result = await eventStore.appendToStream(\n streamName,\n events,\n options,\n );\n\n const currentStream = appendedEvents.get(streamName) ?? [streamName, []];\n\n appendedEvents.set(streamName, [\n streamName,\n [...currentStream[1], ...events],\n ]);\n\n return result;\n },\n\n appendedEvents,\n\n setup: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n ): Promise<AppendToStreamResult<StreamVersion>> => {\n return eventStore.appendToStream(streamName, events);\n },\n };\n};\n","import {\n type NodePostgresClient,\n type NodePostgresTransaction,\n type SQL,\n type SQLExecutor,\n} from '@event-driven-io/dumbo';\nimport {\n projection,\n type CanHandle,\n type Event,\n type EventMetaDataOf,\n type ProjectionHandler,\n type ReadEvent,\n type ReadEventMetadata,\n type TypedProjectionDefinition,\n} from '@event-driven-io/emmett';\n\nexport type PostgreSQLProjectionHandlerContext = {\n connectionString: string;\n client: NodePostgresClient;\n execute: SQLExecutor;\n transaction: NodePostgresTransaction;\n};\n\nexport type PostgreSQLProjectionHandler<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n> = ProjectionHandler<\n EventType,\n EventMetaDataType,\n PostgreSQLProjectionHandlerContext\n>;\n\nexport type PostgreSQLProjectionDefinition<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n> = TypedProjectionDefinition<\n EventType,\n EventMetaDataType,\n PostgreSQLProjectionHandlerContext\n>;\n\nexport type ProjectionHandlerOptions<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n> = {\n events: ReadEvent<EventType, EventMetaDataType>[];\n projections: PostgreSQLProjectionDefinition<EventType>[];\n connection: {\n connectionString: string;\n transaction: NodePostgresTransaction;\n };\n};\n\nexport const handleProjections = async <\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n>(\n options: ProjectionHandlerOptions<EventType, EventMetaDataType>,\n): Promise<void> => {\n const {\n projections: allProjections,\n events,\n connection: { transaction, connectionString },\n } = options;\n\n const eventTypes = events.map((e) => e.type);\n\n const projections = allProjections.filter((p) =>\n p.canHandle.some((type) => eventTypes.includes(type)),\n );\n\n const client = (await transaction.connection.open()) as NodePostgresClient;\n\n for (const projection of projections) {\n await projection.handle(events, {\n connectionString,\n client,\n transaction,\n execute: transaction.execute,\n });\n }\n};\n\nexport const postgreSQLProjection = <\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n>(\n definition: PostgreSQLProjectionDefinition<EventType>,\n): PostgreSQLProjectionDefinition =>\n projection<\n EventType,\n EventMetaDataType,\n PostgreSQLProjectionHandlerContext,\n PostgreSQLProjectionDefinition<EventType>\n >(definition) as PostgreSQLProjectionDefinition;\n\nexport const postgreSQLRawBatchSQLProjection = <EventType extends Event>(\n handle: (\n events: EventType[],\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<SQL[]> | SQL[],\n ...canHandle: CanHandle<EventType>\n): PostgreSQLProjectionDefinition =>\n postgreSQLProjection<EventType>({\n canHandle,\n handle: async (events, context) => {\n const sqls: SQL[] = await handle(events, context);\n\n await context.execute.batchCommand(sqls);\n },\n });\n\nexport const postgreSQLRawSQLProjection = <EventType extends Event>(\n handle: (\n event: EventType,\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<SQL> | SQL,\n ...canHandle: CanHandle<EventType>\n): PostgreSQLProjectionDefinition =>\n postgreSQLRawBatchSQLProjection<EventType>(\n async (events, context) => {\n const sqls: SQL[] = [];\n\n for (const event of events) {\n sqls.push(await handle(event, context));\n }\n return sqls;\n },\n ...canHandle,\n );\n\nexport * from './pongo';\nexport * from './postgresProjectionSpec';\n","import { type Dumbo } from '@event-driven-io/dumbo';\nimport {\n assertDeepEqual,\n assertEqual,\n assertIsNotNull,\n assertThatArray,\n} from '@event-driven-io/emmett';\nimport {\n pongoClient,\n type PongoCollection,\n type PongoDocument,\n type PongoFilter,\n type WithId,\n} from '@event-driven-io/pongo';\nimport { type PostgreSQLProjectionAssert } from '..';\n\nexport type PongoAssertOptions = {\n inCollection: string;\n inDatabase?: string;\n};\n\nconst withCollection = (\n handle: (collection: PongoCollection<PongoDocument>) => Promise<void>,\n options: {\n pool: Dumbo;\n connectionString: string;\n } & PongoAssertOptions,\n) => {\n const { pool, connectionString, inDatabase, inCollection } = options;\n\n return pool.withConnection(async (connection) => {\n const pongo = pongoClient(connectionString, {\n connectionOptions: { connection },\n });\n try {\n const collection = pongo.db(inDatabase).collection(inCollection);\n\n return handle(collection);\n } finally {\n await pongo.close();\n }\n });\n};\n\nconst withoutIdAndVersion = <Doc extends PongoDocument | WithId<PongoDocument>>(\n doc: Doc,\n) => {\n const { _id, _version, ...without } = doc;\n\n return without;\n};\n\nconst assertDocumentsEqual = <\n Doc extends PongoDocument | WithId<PongoDocument>,\n>(\n actual: PongoDocument,\n expected: Doc,\n) => {\n if ('_id' in expected)\n assertEqual(\n expected._id,\n actual._id,\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Document ids are not matching! Expected: ${expected._id}, actual: ${actual._id}`,\n );\n\n return assertDeepEqual(\n withoutIdAndVersion(actual),\n withoutIdAndVersion(expected),\n );\n};\n\ntype FilterOrId<Doc extends PongoDocument | WithId<PongoDocument>> =\n | { withId: string }\n | {\n matchingFilter: PongoFilter<Doc>;\n };\n\nexport const documentExists =\n <Doc extends PongoDocument | WithId<PongoDocument>>(\n document: Doc,\n options: PongoAssertOptions & FilterOrId<Doc>,\n ): PostgreSQLProjectionAssert =>\n (assertOptions) =>\n withCollection(\n async (collection) => {\n const result = await collection.findOne(\n 'withId' in options\n ? { _id: options.withId }\n : options.matchingFilter,\n );\n\n assertIsNotNull(result);\n\n assertDocumentsEqual(result, document);\n },\n { ...options, ...assertOptions },\n );\n\nexport const documentsAreTheSame =\n <Doc extends PongoDocument | WithId<PongoDocument>>(\n documents: Doc[],\n options: PongoAssertOptions & FilterOrId<Doc>,\n ): PostgreSQLProjectionAssert =>\n (assertOptions) =>\n withCollection(\n async (collection) => {\n const result = await collection.find(\n 'withId' in options\n ? { _id: options.withId }\n : options.matchingFilter,\n );\n\n assertEqual(\n documents.length,\n result.length,\n 'Different Documents Count than expected',\n );\n\n for (let i = 0; i < documents.length; i++) {\n assertThatArray(result).contains(documents[i]!);\n }\n },\n { ...options, ...assertOptions },\n );\n\nexport const documentsMatchingHaveCount =\n <Doc extends PongoDocument | WithId<PongoDocument>>(\n expectedCount: number,\n options: PongoAssertOptions & FilterOrId<Doc>,\n ): PostgreSQLProjectionAssert =>\n (assertOptions) =>\n withCollection(\n async (collection) => {\n const result = await collection.find(\n 'withId' in options\n ? { _id: options.withId }\n : options.matchingFilter,\n );\n\n assertEqual(\n expectedCount,\n result.length,\n 'Different Documents Count than expected',\n );\n },\n { ...options, ...assertOptions },\n );\n\nexport const documentMatchingExists =\n <Doc extends PongoDocument | WithId<PongoDocument>>(\n options: PongoAssertOptions & FilterOrId<Doc>,\n ): PostgreSQLProjectionAssert =>\n (assertOptions) =>\n withCollection(\n async (collection) => {\n const result = await collection.find(\n 'withId' in options\n ? { _id: options.withId }\n : options.matchingFilter,\n );\n\n assertThatArray(result).isNotEmpty();\n },\n { ...options, ...assertOptions },\n );\n\nexport const documentDoesNotExist =\n <Doc extends PongoDocument | WithId<PongoDocument>>(\n options: PongoAssertOptions & FilterOrId<Doc>,\n ): PostgreSQLProjectionAssert =>\n (assertOptions) =>\n withCollection(\n async (collection) => {\n const result = await collection.findOne(\n 'withId' in options\n ? { _id: options.withId }\n : options.matchingFilter,\n );\n\n assertIsNotNull(result);\n },\n { ...options, ...assertOptions },\n );\n\nexport const expectPongoDocuments = {\n fromCollection: <Doc extends PongoDocument | WithId<PongoDocument>>(\n collectionName: string,\n ) => {\n return {\n withId: (id: string) => {\n return {\n toBeEqual: (document: Doc) =>\n documentExists(document, {\n withId: id,\n inCollection: collectionName,\n }),\n toExist: () =>\n documentMatchingExists({\n withId: id,\n inCollection: collectionName,\n }),\n notToExist: () =>\n documentDoesNotExist({\n withId: id,\n inCollection: collectionName,\n }),\n };\n },\n matching: <Doc extends PongoDocument | WithId<PongoDocument>>(\n filter: PongoFilter<Doc>,\n ) => {\n return {\n toBeTheSame: (documents: Doc[]) =>\n documentsAreTheSame<Doc>(documents, {\n matchingFilter: filter,\n inCollection: collectionName,\n }),\n toHaveCount: (expectedCount: number) =>\n documentsMatchingHaveCount(expectedCount, {\n matchingFilter: filter,\n inCollection: collectionName,\n }),\n toExist: () =>\n documentMatchingExists({\n matchingFilter: filter,\n inCollection: collectionName,\n }),\n notToExist: () =>\n documentDoesNotExist({\n matchingFilter: filter,\n inCollection: collectionName,\n }),\n };\n },\n };\n },\n};\n","import {\n type CanHandle,\n type Event,\n type EventMetaDataOf,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n} from '@event-driven-io/emmett';\nimport {\n pongoClient,\n type PongoClient,\n type PongoDocument,\n} from '@event-driven-io/pongo';\nimport {\n postgreSQLProjection,\n type PostgreSQLProjectionDefinition,\n type PostgreSQLProjectionHandlerContext,\n} from '..';\n\nexport type PongoProjectionHandlerContext =\n PostgreSQLProjectionHandlerContext & {\n pongo: PongoClient;\n };\n\nexport type PongoWithNotNullDocumentEvolve<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> =\n | ((\n document: Document,\n event: ReadEvent<EventType, EventMetaDataType>,\n ) => Document | null)\n | ((\n document: Document,\n event: ReadEvent<EventType>,\n ) => Promise<Document | null>);\n\nexport type PongoWithNullableDocumentEvolve<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> =\n | ((\n document: Document | null,\n event: ReadEvent<EventType, EventMetaDataType>,\n ) => Document | null)\n | ((\n document: Document | null,\n event: ReadEvent<EventType>,\n ) => Promise<Document | null>);\n\nexport type PongoDocumentEvolve<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> =\n | PongoWithNotNullDocumentEvolve<Document, EventType, EventMetaDataType>\n | PongoWithNullableDocumentEvolve<Document, EventType, EventMetaDataType>;\n\nexport type PongoProjectionOptions<\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> = {\n handle: (\n events: ReadEvent<EventType, EventMetaDataType>[],\n context: PongoProjectionHandlerContext,\n ) => Promise<void>;\n canHandle: CanHandle<EventType>;\n};\n\nexport const pongoProjection = <\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n>({\n handle,\n canHandle,\n}: PongoProjectionOptions<\n EventType,\n EventMetaDataType\n>): PostgreSQLProjectionDefinition =>\n postgreSQLProjection<EventType, EventMetaDataType>({\n canHandle,\n handle: async (events, context) => {\n const { connectionString, client } = context;\n const pongo = pongoClient(connectionString, {\n connectionOptions: { client },\n });\n await handle(events as ReadEvent<EventType, EventMetaDataType>[], {\n ...context,\n pongo,\n });\n },\n });\n\nexport type PongoMultiStreamProjectionOptions<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> = {\n canHandle: CanHandle<EventType>;\n\n collectionName: string;\n getDocumentId: (event: ReadEvent<EventType>) => string;\n} & (\n | {\n evolve: PongoWithNullableDocumentEvolve<\n Document,\n EventType,\n EventMetaDataType\n >;\n }\n | {\n evolve: PongoWithNotNullDocumentEvolve<\n Document,\n EventType,\n EventMetaDataType\n >;\n initialState: () => Document;\n }\n);\n\nexport const pongoMultiStreamProjection = <\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n>(\n options: PongoMultiStreamProjectionOptions<\n Document,\n EventType,\n EventMetaDataType\n >,\n): PostgreSQLProjectionDefinition => {\n const { collectionName, getDocumentId, canHandle } = options;\n\n return pongoProjection({\n handle: async (events, { pongo }) => {\n const collection = pongo.db().collection<Document>(collectionName);\n\n for (const event of events) {\n await collection.handle(getDocumentId(event), async (document) => {\n return 'initialState' in options\n ? await options.evolve(\n document ?? options.initialState(),\n event as ReadEvent<EventType, EventMetaDataType>,\n )\n : await options.evolve(\n document,\n event as ReadEvent<EventType, EventMetaDataType>,\n );\n });\n }\n },\n canHandle,\n });\n};\n\nexport type PongoSingleStreamProjectionOptions<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> = {\n canHandle: CanHandle<EventType>;\n\n collectionName: string;\n} & (\n | {\n evolve: PongoWithNullableDocumentEvolve<\n Document,\n EventType,\n EventMetaDataType\n >;\n }\n | {\n evolve: PongoWithNotNullDocumentEvolve<\n Document,\n EventType,\n EventMetaDataType\n >;\n initialState: () => Document;\n }\n);\n\nexport const pongoSingleStreamProjection = <\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n>(\n options: PongoSingleStreamProjectionOptions<\n Document,\n EventType,\n EventMetaDataType\n >,\n): PostgreSQLProjectionDefinition => {\n return pongoMultiStreamProjection<Document, EventType, EventMetaDataType>({\n ...options,\n getDocumentId: (event) => event.metadata.streamName,\n });\n};\n","import {\n dumbo,\n type Dumbo,\n type DumboOptions,\n type QueryResultRow,\n type SQL,\n} from '@event-driven-io/dumbo';\nimport {\n assertFails,\n AssertionError,\n assertThatArray,\n assertTrue,\n isErrorConstructor,\n type Event,\n type EventMetaDataOf,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n type ThenThrows,\n} from '@event-driven-io/emmett';\nimport { v4 as uuid } from 'uuid';\nimport { handleProjections, type PostgreSQLProjectionDefinition } from '.';\n\nexport type PostgreSQLProjectionSpecEvent<\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> = EventType & {\n metadata?: Partial<EventMetaDataType>;\n};\n\nexport type PostgreSQLProjectionSpecWhenOptions = { numberOfTimes: number };\n\nexport type PostgreSQLProjectionSpec<EventType extends Event> = (\n givenEvents: PostgreSQLProjectionSpecEvent<EventType>[],\n) => {\n when: (\n events: PostgreSQLProjectionSpecEvent<EventType>[],\n options?: PostgreSQLProjectionSpecWhenOptions,\n ) => {\n then: (\n assert: PostgreSQLProjectionAssert,\n message?: string,\n ) => Promise<void>;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => Promise<void>;\n };\n};\n\nexport type PostgreSQLProjectionAssert = (options: {\n pool: Dumbo;\n connectionString: string;\n}) => Promise<void | boolean>;\n\nexport type PostgreSQLProjectionSpecOptions = {\n projection: PostgreSQLProjectionDefinition;\n} & DumboOptions;\n\nexport const PostgreSQLProjectionSpec = {\n for: <EventType extends Event>(\n options: PostgreSQLProjectionSpecOptions,\n ): PostgreSQLProjectionSpec<EventType> => {\n {\n const { projection, ...dumoOptions } = options;\n const { connectionString } = dumoOptions;\n\n return (givenEvents: PostgreSQLProjectionSpecEvent<EventType>[]) => {\n return {\n when: (\n events: PostgreSQLProjectionSpecEvent<EventType>[],\n options?: PostgreSQLProjectionSpecWhenOptions,\n ) => {\n const allEvents: ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >[] = [];\n\n const run = async (pool: Dumbo) => {\n let globalPosition = 0n;\n const numberOfTimes = options?.numberOfTimes ?? 1;\n\n for (const event of [\n ...givenEvents,\n ...Array.from({ length: numberOfTimes }).flatMap(() => events),\n ]) {\n allEvents.push({\n ...event,\n metadata: {\n ...{\n globalPosition: ++globalPosition,\n streamPosition: globalPosition,\n streamName: `test-${uuid()}`,\n eventId: uuid(),\n },\n ...(event.metadata ?? {}),\n },\n });\n }\n\n await pool.withTransaction((transaction) =>\n handleProjections({\n events: allEvents,\n projections: [projection],\n connection: {\n connectionString,\n transaction,\n },\n }),\n );\n };\n\n return {\n then: async (\n assert: PostgreSQLProjectionAssert,\n message?: string,\n ): Promise<void> => {\n const pool = dumbo(dumoOptions);\n try {\n await run(pool);\n\n const succeeded = await assert({ pool, connectionString });\n\n if (succeeded !== undefined && succeeded === false)\n assertFails(\n message ??\n \"Projection specification didn't match the criteria\",\n );\n } finally {\n await pool.close();\n }\n },\n thenThrows: async <ErrorType extends Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): Promise<void> => {\n const pool = dumbo(dumoOptions);\n try {\n await run(pool);\n throw new AssertionError('Handler did not fail as expected');\n } catch (error) {\n if (error instanceof AssertionError) throw error;\n\n if (args.length === 0) return;\n\n if (!isErrorConstructor(args[0])) {\n assertTrue(\n args[0](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n return;\n }\n\n assertTrue(\n error instanceof args[0],\n `Caught error is not an instance of the expected type: ${error?.toString()}`,\n );\n\n if (args[1]) {\n assertTrue(\n args[1](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n }\n } finally {\n await pool.close();\n }\n },\n };\n },\n };\n };\n }\n },\n};\n\nexport const eventInStream = <\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n>(\n streamName: string,\n event: PostgreSQLProjectionSpecEvent<EventType, EventMetaDataType>,\n): PostgreSQLProjectionSpecEvent<EventType, EventMetaDataType> => {\n return {\n ...event,\n metadata: {\n ...(event.metadata ?? {}),\n streamName: event.metadata?.streamName ?? streamName,\n } as Partial<EventMetaDataType>,\n };\n};\n\nexport const eventsInStream = <\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n>(\n streamName: string,\n events: PostgreSQLProjectionSpecEvent<EventType, EventMetaDataType>[],\n): PostgreSQLProjectionSpecEvent<EventType, EventMetaDataType>[] => {\n return events.map((e) => eventInStream(streamName, e));\n};\n\nexport const newEventsInStream = eventsInStream;\n\nexport const assertSQLQueryResultMatches =\n <T extends QueryResultRow>(sql: SQL, rows: T[]): PostgreSQLProjectionAssert =>\n async ({ pool: { execute } }) => {\n const result = await execute.query<T>(sql);\n\n assertThatArray(rows).containsExactlyInAnyOrder(...result.rows);\n };\n\nexport const expectSQL = {\n query: (sql: SQL) => ({\n resultRows: {\n toBeTheSame: <T extends QueryResultRow>(rows: T[]) =>\n assertSQLQueryResultMatches(sql, rows),\n },\n }),\n};\n","import { type NodePostgresPool, type SQL } from '@event-driven-io/dumbo';\nimport { appendEventsSQL } from './appendToStream';\nimport {\n addDefaultPartition,\n addEventsPartitions,\n addModuleForAllTenantsSQL,\n addModuleSQL,\n addTablePartitions,\n addTenantForAllModulesSQL,\n addTenantSQL,\n eventsTableSQL,\n sanitizeNameSQL,\n streamsTableSQL,\n subscriptionsTableSQL,\n} from './tables';\n\nexport * from './appendToStream';\nexport * from './readStream';\nexport * from './tables';\nexport * from './typing';\n\nexport const schemaSQL: SQL[] = [\n streamsTableSQL,\n eventsTableSQL,\n subscriptionsTableSQL,\n sanitizeNameSQL,\n addTablePartitions,\n addEventsPartitions,\n addModuleSQL,\n addTenantSQL,\n addModuleForAllTenantsSQL,\n addTenantForAllModulesSQL,\n appendEventsSQL,\n addDefaultPartition,\n];\n\nexport const createEventStoreSchema = async (\n pool: NodePostgresPool,\n): Promise<void> => {\n await pool.withTransaction(({ execute }) => execute.batchCommand(schemaSQL));\n};\n","import {\n rawSql,\n single,\n sql,\n type NodePostgresPool,\n type NodePostgresTransaction,\n type SQLExecutor,\n} from '@event-driven-io/dumbo';\nimport {\n JSONParser,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AppendToStreamOptions,\n type Event,\n type ExpectedStreamVersion,\n type ReadEvent,\n} from '@event-driven-io/emmett';\nimport { v4 as uuid } from 'uuid';\nimport { defaultTag, eventsTable, streamsTable } from './typing';\n\nexport const appendEventsSQL = rawSql(\n `CREATE OR REPLACE FUNCTION emt_append_event(\n v_event_ids text[],\n v_events_data jsonb[],\n v_events_metadata jsonb[],\n v_event_schema_versions text[],\n v_event_types text[],\n v_stream_id text,\n v_stream_type text,\n v_expected_stream_position bigint DEFAULT NULL,\n v_partition text DEFAULT emt_sanitize_name('default_partition')\n ) RETURNS TABLE (\n success boolean,\n next_stream_position bigint,\n last_global_position bigint,\n transaction_id xid8\n ) LANGUAGE plpgsql\n AS $$\n DECLARE\n v_next_stream_position bigint;\n v_position bigint;\n v_updated_rows int;\n v_transaction_id xid8;\n v_last_global_position bigint;\n BEGIN\n IF v_expected_stream_position IS NULL THEN\n SELECT COALESCE(max(stream_position), 0) INTO v_expected_stream_position\n FROM ${streamsTable.name}\n WHERE stream_id = v_stream_id AND partition = v_partition;\n END IF;\n\n v_next_stream_position := v_expected_stream_position + array_upper(v_events_data, 1);\n v_transaction_id := pg_current_xact_id();\n\n WITH ev AS (\n SELECT row_number() OVER () + v_expected_stream_position AS stream_position, \n event_data, \n event_metadata, \n schema_version, \n event_id, \n event_type\n FROM (\n SELECT *\n FROM \n unnest(v_event_ids, v_events_data, v_events_metadata, v_event_schema_versions, v_event_types) \n AS event(event_id, event_data, event_metadata, schema_version, event_type)\n ) AS event\n ),\n all_events_insert AS (\n INSERT INTO ${eventsTable.name}\n (stream_id, stream_position, partition, event_data, event_metadata, event_schema_version, event_type, event_id, transaction_id)\n SELECT \n v_stream_id, ev.stream_position, v_partition, ev.event_data, ev.event_metadata, ev.schema_version, ev.event_type, ev.event_id, v_transaction_id\n FROM ev\n RETURNING global_position\n )\n SELECT \n max(global_position) INTO v_last_global_position \n FROM \n all_events_insert;\n\n\n IF v_expected_stream_position = 0 THEN\n INSERT INTO ${streamsTable.name}\n (stream_id, stream_position, partition, stream_type, stream_metadata, is_archived)\n VALUES\n (v_stream_id, v_next_stream_position, v_partition, v_stream_type, '{}', FALSE);\n ELSE\n UPDATE ${streamsTable.name} as s \n SET stream_position = v_next_stream_position\n WHERE stream_id = v_stream_id AND stream_position = v_expected_stream_position AND partition = v_partition AND is_archived = FALSE;\n\n get diagnostics v_updated_rows = row_count;\n\n IF v_updated_rows = 0 THEN\n RETURN QUERY SELECT FALSE, NULL::bigint, NULL::bigint, NULL::xid8;\n RETURN;\n END IF;\n END IF;\n\n RETURN QUERY SELECT TRUE, v_next_stream_position, v_last_global_position, v_transaction_id;\n END;\n $$;\n `,\n);\n\ntype AppendEventResult =\n | {\n success: true;\n nextStreamPosition: bigint;\n lastGlobalPosition: bigint;\n transactionId: string;\n }\n | { success: false };\n\nexport type AppendToStreamPreCommitHook = (\n events: ReadEvent[],\n context: {\n transaction: NodePostgresTransaction;\n },\n) => Promise<void>;\n\nexport const appendToStream = (\n pool: NodePostgresPool,\n streamName: string,\n streamType: string,\n events: Event[],\n options?: AppendToStreamOptions & {\n partition?: string;\n preCommitHook?: AppendToStreamPreCommitHook;\n },\n): Promise<AppendEventResult> =>\n pool.withTransaction<AppendEventResult>(async (transaction) => {\n const { execute } = transaction;\n\n if (events.length === 0)\n return { success: false, result: { success: false } };\n\n let appendResult: AppendEventSqlResult;\n\n try {\n const expectedStreamVersion = toExpectedVersion(\n options?.expectedStreamVersion,\n );\n\n const eventsToAppend: ReadEvent[] = events.map((e, i) => ({\n ...e,\n metadata: {\n streamName,\n eventId: uuid(),\n streamPosition: BigInt(i),\n ...e.metadata,\n },\n }));\n\n // TODO: return global positions from append raw and other generated data\n appendResult = await appendEventsRaw(\n execute,\n streamName,\n streamType,\n eventsToAppend,\n {\n expectedStreamVersion,\n },\n );\n\n if (options?.preCommitHook)\n await options.preCommitHook(eventsToAppend, { transaction });\n } catch (error) {\n if (!isOptimisticConcurrencyError(error)) throw error;\n\n appendResult = {\n success: false,\n last_global_position: null,\n next_stream_position: null,\n transaction_id: null,\n };\n }\n\n const {\n success,\n next_stream_position,\n last_global_position,\n transaction_id,\n } = appendResult;\n\n return {\n success,\n result:\n success &&\n next_stream_position &&\n last_global_position &&\n transaction_id\n ? {\n success: true,\n nextStreamPosition: BigInt(next_stream_position),\n lastGlobalPosition: BigInt(last_global_position),\n transactionId: transaction_id,\n }\n : { success: false },\n };\n });\n\nconst toExpectedVersion = (\n expected: ExpectedStreamVersion | undefined,\n): bigint | null => {\n if (expected === undefined) return null;\n\n if (expected === NO_CONCURRENCY_CHECK) return null;\n\n // TODO: this needs to be fixed\n if (expected == STREAM_DOES_NOT_EXIST) return null;\n\n // TODO: this needs to be fixed\n if (expected == STREAM_EXISTS) return null;\n\n return expected as bigint;\n};\n\nconst isOptimisticConcurrencyError = (error: unknown): boolean =>\n error instanceof Error && 'code' in error && error.code === '23505';\n\ntype AppendEventSqlResult = {\n success: boolean;\n next_stream_position: string | null;\n last_global_position: string | null;\n transaction_id: string | null | undefined;\n};\n\nconst appendEventsRaw = (\n execute: SQLExecutor,\n streamId: string,\n streamType: string,\n events: ReadEvent[],\n options?: {\n expectedStreamVersion: bigint | null;\n partition?: string;\n },\n): Promise<AppendEventSqlResult> =>\n single(\n execute.command<AppendEventSqlResult>(\n sql(\n `SELECT * FROM emt_append_event(\n ARRAY[%s]::text[],\n ARRAY[%s]::jsonb[],\n ARRAY[%s]::jsonb[],\n ARRAY[%s]::text[],\n ARRAY[%s]::text[],\n %L::text,\n %L::text,\n %s::bigint,\n %L::text\n )`,\n events.map((e) => sql('%L', e.metadata.eventId)).join(','),\n events.map((e) => sql('%L', JSONParser.stringify(e.data))).join(','),\n events\n .map((e) => sql('%L', JSONParser.stringify(e.metadata ?? {})))\n .join(','),\n events.map(() => `'1'`).join(','),\n events.map((e) => sql('%L', e.type)).join(','),\n streamId,\n streamType,\n options?.expectedStreamVersion ?? 'NULL',\n options?.partition ?? defaultTag,\n ),\n ),\n );\n","export const emmettPrefix = 'emt';\n\nexport const globalTag = 'global';\nexport const defaultTag = 'emt:default';\n\nexport const globalNames = {\n module: `${emmettPrefix}:module:${globalTag}`,\n tenant: `${emmettPrefix}:tenant:${globalTag}`,\n};\n\nconst columns = {\n partition: {\n name: 'partition',\n },\n isArchived: { name: 'is_archived' },\n};\n\nexport const streamsTable = {\n name: `${emmettPrefix}_streams`,\n columns: {\n partition: columns.partition,\n isArchived: columns.isArchived,\n },\n};\n\nexport const eventsTable = {\n name: `${emmettPrefix}_events`,\n columns: {\n partition: columns.partition,\n isArchived: columns.isArchived,\n },\n};\n","import { rawSql } from '@event-driven-io/dumbo';\nimport { defaultTag, eventsTable, globalTag, streamsTable } from './typing';\n\nexport const streamsTableSQL = rawSql(\n `CREATE TABLE IF NOT EXISTS ${streamsTable.name}(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${globalTag}__${globalTag}',\n stream_type TEXT NOT NULL,\n stream_metadata JSONB NOT NULL,\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n PRIMARY KEY (stream_id, stream_position, partition, is_archived),\n UNIQUE (stream_id, partition, is_archived)\n ) PARTITION BY LIST (partition);`,\n);\n\nexport const eventsTableSQL = rawSql(\n `\n CREATE SEQUENCE IF NOT EXISTS emt_global_event_position;\n\n CREATE TABLE IF NOT EXISTS ${eventsTable.name}(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${globalTag}',\n event_data JSONB NOT NULL,\n event_metadata JSONB NOT NULL,\n event_schema_version TEXT NOT NULL,\n event_type TEXT NOT NULL,\n event_id TEXT NOT NULL,\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n global_position BIGINT DEFAULT nextval('emt_global_event_position'),\n transaction_id XID8 NOT NULL,\n created TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (stream_id, stream_position, partition, is_archived)\n ) PARTITION BY LIST (partition);`,\n);\n\nexport const subscriptionsTableSQL = rawSql(\n `\n CREATE TABLE IF NOT EXISTS emt_subscriptions(\n subscription_id TEXT NOT NULL PRIMARY KEY,\n version INT NOT NULL DEFAULT 1,\n module TEXT NULL,\n tenant TEXT NULL,\n last_processed_position BIGINT NOT NULL,\n last_processed_transaction_id BIGINT NOT NULL\n );\n`,\n);\n\nexport const sanitizeNameSQL = rawSql(\n `CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $$\n BEGIN\n RETURN REGEXP_REPLACE(input_name, '[^a-zA-Z0-9_]', '_', 'g');\n END;\n $$ LANGUAGE plpgsql;`,\n);\n\nexport const addTablePartitions = rawSql(\n `\n CREATE OR REPLACE FUNCTION emt_add_table_partition(tableName TEXT, partition_name TEXT) RETURNS void AS $$\n DECLARE\n v_main_partiton_name TEXT;\n v_active_partiton_name TEXT;\n v_archived_partiton_name TEXT;\n BEGIN \n v_main_partiton_name := emt_sanitize_name(tableName || '_' || partition_name);\n v_active_partiton_name := emt_sanitize_name(v_main_partiton_name || '_active');\n v_archived_partiton_name := emt_sanitize_name(v_main_partiton_name || '_archived');\n\n -- create default events partition\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L) PARTITION BY LIST (is_archived);',\n v_main_partiton_name, tableName, partition_name\n );\n\n -- create default streams partition\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L) PARTITION BY LIST (is_archived);',\n v_main_partiton_name, tableName, partition_name\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (FALSE);',\n v_active_partiton_name, v_main_partiton_name\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (TRUE);',\n v_archived_partiton_name, v_main_partiton_name\n );\n END;\n $$ LANGUAGE plpgsql;`,\n);\n\nexport const addEventsPartitions = rawSql(\n `\n CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $$\n BEGIN \n PERFORM emt_add_table_partition('${eventsTable.name}', partition_name);\n PERFORM emt_add_table_partition('${streamsTable.name}', partition_name);\n END;\n $$ LANGUAGE plpgsql;`,\n);\n\nexport const addModuleSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_module(new_module TEXT) RETURNS void AS $$\n BEGIN\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}'), '${eventsTable.name}', new_module, '${globalTag}'\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}' || '_active'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}' || '_archived'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}'), '${streamsTable.name}', new_module, '${globalTag}'\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}' || '_active'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}' || '_archived'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addTenantSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_tenant(new_module TEXT, new_tenant TEXT) RETURNS void AS $$\n BEGIN\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant), '${eventsTable.name}', new_module, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant)\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant), '${streamsTable.name}', new_module, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant)\n );\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addModuleForAllTenantsSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_module_for_all_tenants(new_module TEXT) RETURNS void AS $$\n DECLARE\n tenant_record RECORD;\n BEGIN\n PERFORM add_module(new_module);\n \n FOR tenant_record IN SELECT DISTINCT tenant FROM ${eventsTable.name}\n LOOP\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant), '${eventsTable.name}', new_module, tenant_record.tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant), '${streamsTable.name}', new_module, tenant_record.tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n END LOOP;\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addTenantForAllModulesSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_tenant_for_all_modules(new_tenant TEXT) RETURNS void AS $$\n DECLARE\n module_record RECORD;\n BEGIN\n FOR module_record IN SELECT DISTINCT partitionname FROM pg_partman.part_config WHERE parent_table = '${eventsTable.name}'\n LOOP\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant), '${eventsTable.name}', module_record.partitionname, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant), '${streamsTable.name}', module_record.partitionname, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n END LOOP;\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addDefaultPartition = rawSql(\n `SELECT emt_add_partition('${defaultTag}');`,\n);\n","import { mapRows, sql, type SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n event,\n type DefaultStreamVersionType,\n type Event,\n type EventDataOf,\n type EventMetaDataOf,\n type EventTypeOf,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport { defaultTag, eventsTable } from './typing';\n\ntype ReadStreamSqlResult<EventType extends Event> = {\n stream_position: string;\n event_data: EventDataOf<EventType>;\n event_metadata: EventMetaDataOf<EventType>;\n event_schema_version: string;\n event_type: EventTypeOf<EventType>;\n event_id: string;\n global_position: string;\n transaction_id: string;\n created: string;\n};\n\nexport const readStream = async <EventType extends Event>(\n execute: SQLExecutor,\n streamId: string,\n options?: ReadStreamOptions & { partition?: string },\n): Promise<\n ReadStreamResult<\n EventType,\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n >\n> => {\n const fromCondition: string =\n options && 'from' in options\n ? `AND stream_position >= ${options.from}`\n : '';\n\n const to = Number(\n options && 'to' in options\n ? options.to\n : options && 'maxCount' in options && options.maxCount\n ? options.from + options.maxCount\n : NaN,\n );\n\n const toCondition = !isNaN(to) ? `AND stream_position <= ${to}` : '';\n\n const events: ReadEvent<EventType, ReadEventMetadataWithGlobalPosition>[] =\n await mapRows(\n execute.query<ReadStreamSqlResult<EventType>>(\n sql(\n `SELECT stream_id, stream_position, global_position, event_data, event_metadata, event_schema_version, event_type, event_id\n FROM ${eventsTable.name}\n WHERE stream_id = %L AND partition = %L AND is_archived = FALSE ${fromCondition} ${toCondition}`,\n streamId,\n options?.partition ?? defaultTag,\n ),\n ),\n (row) => {\n const rawEvent = event<EventType>(\n row.event_type,\n row.event_data,\n row.event_metadata,\n ) as EventType;\n\n return {\n ...rawEvent,\n metadata: {\n ...rawEvent.metadata,\n eventId: row.event_id,\n streamName: streamId,\n streamPosition: BigInt(row.stream_position),\n globalPosition: BigInt(row.global_position),\n },\n };\n },\n );\n\n return events.length > 0\n ? {\n currentStreamVersion:\n events[events.length - 1]!.metadata.streamPosition,\n events,\n }\n : null;\n};\n"],"mappings":"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","names":["dumbo","ValidationErrors","isNumber","val","isString","isErrorConstructor","expect","EmmettError","_EmmettError","options","errorCode","isNumber","message","isString","ConcurrencyError","_ConcurrencyError","current","expected","randomUUID","retry","TransformStream","STREAM_EXISTS","STREAM_DOES_NOT_EXIST","NO_CONCURRENCY_CHECK","ExpectedVersionConflictError","_ExpectedVersionConflictError","ConcurrencyError","current","expected","event","type","data","metadata","projection","definition","ParseError","text","JSONParser","value","options","_","v","parsed","deepEquals","left","right","isEquatable","val","index","keys1","keys2","key","AssertionError","message","assertFails","message","AssertionError","assertDeepEqual","actual","expected","message","deepEquals","AssertionError","JSONParser","assertTrue","condition","message","AssertionError","assertOk","obj","assertEqual","expected","actual","JSONParser","assertNotEqual","other","assertIsNotNull","result","assertThatArray","array","assertEqual","assertNotEqual","length","other","assertTrue","ts","o","deepEquals","i","elem","a","matches","item","pongoClient","withCollection","handle","options","pool","connectionString","inDatabase","inCollection","connection","pongo","pongoClient","collection","withoutIdAndVersion","doc","_id","_version","without","assertDocumentsEqual","actual","expected","l","an","documentExists","document","assertOptions","result","mn","documentsAreTheSame","documents","i","yn","documentsMatchingHaveCount","expectedCount","documentMatchingExists","documentDoesNotExist","expectPongoDocuments","collectionName","id","filter","pongoClient","pongoProjection","handle","canHandle","postgreSQLProjection","events","context","connectionString","client","pongo","pongoClient","pongoMultiStreamProjection","options","collectionName","getDocumentId","collection","event","document","pongoSingleStreamProjection","dumbo","uuid","PostgreSQLProjectionSpec","options","projection","dumoOptions","connectionString","givenEvents","events","allEvents","run","pool","globalPosition","numberOfTimes","event","uuid","transaction","handleProjections","assert","message","dumbo","succeeded","nn","args","p","error","C","s","eventInStream","streamName","eventsInStream","e","newEventsInStream","assertSQLQueryResultMatches","sql","rows","execute","result","yn","expectSQL","handleProjections","options","allProjections","events","transaction","connectionString","eventTypes","e","projections","p","type","client","projection","postgreSQLProjection","definition","at","postgreSQLRawBatchSQLProjection","handle","canHandle","context","sqls","postgreSQLRawSQLProjection","event","rawSql","single","sql","uuid","emmettPrefix","globalTag","defaultTag","globalNames","columns","streamsTable","eventsTable","appendEventsSQL","rawSql","streamsTable","eventsTable","appendToStream","pool","streamName","streamType","events","options","transaction","execute","appendResult","expectedStreamVersion","toExpectedVersion","eventsToAppend","e","i","uuid","appendEventsRaw","error","isOptimisticConcurrencyError","success","next_stream_position","last_global_position","transaction_id","expected","f","O","U","streamId","single","sql","u","defaultTag","rawSql","streamsTableSQL","rawSql","streamsTable","globalTag","eventsTableSQL","eventsTable","subscriptionsTableSQL","sanitizeNameSQL","addTablePartitions","addEventsPartitions","addModuleSQL","addTenantSQL","addModuleForAllTenantsSQL","addTenantForAllModulesSQL","addDefaultPartition","defaultTag","mapRows","sql","readStream","execute","streamId","options","fromCondition","to","toCondition","events","mapRows","sql","eventsTable","defaultTag","row","rawEvent","Ne","schemaSQL","streamsTableSQL","eventsTableSQL","subscriptionsTableSQL","sanitizeNameSQL","addTablePartitions","addEventsPartitions","addModuleSQL","addTenantSQL","addModuleForAllTenantsSQL","addTenantForAllModulesSQL","appendEventsSQL","addDefaultPartition","createEventStoreSchema","pool","execute","defaultPostgreSQLOptions","getPostgreSQLEventStore","connectionString","options","poolOptions","pool","dumbo","migrateSchema","autoGenerateSchema","ensureSchemaExists","createEventStoreSchema","inlineProjections","type","projection","preCommitHook","events","transaction","handleProjections","schemaSQL","streamName","evolve","initialState","read","expectedStreamVersion","state","result","currentStreamVersion","assertExpectedVersionMatchesCurrent","event","readStream","firstPart","rest","streamType","appendResult","appendToStream","V","f","callback","connection","storeOptions","eventStore","matchesExpectedVersion","current","expected","O","U"]}
|
|
1
|
+
{"version":3,"sources":["../src/eventStore/postgreSQLEventStore.ts","../../emmett/src/validation/index.ts","../../emmett/src/errors/index.ts","../../emmett/src/validation/dates.ts","../../emmett/src/config/plugins/index.ts","../../emmett/src/eventStore/eventStore.ts","../../emmett/src/eventStore/expectedVersion.ts","../../emmett/src/eventStore/inMemoryEventStore.ts","../../emmett/src/commandHandling/handleCommand.ts","../../emmett/src/commandHandling/handleCommandWithDecider.ts","../../emmett/src/typing/command.ts","../../emmett/src/typing/event.ts","../../emmett/src/typing/workflow.ts","../../emmett/src/messageBus/index.ts","../../emmett/src/projections/index.ts","../../emmett/src/serialization/json/JSONParser.ts","../../emmett/src/streaming/binaryArrays.ts","../../emmett/src/streaming/collect.ts","../../emmett/src/streaming/decoders/binary.ts","../../emmett/src/streaming/decoders/string.ts","../../emmett/src/streaming/decoders/json.ts","../../emmett/src/streaming/decoders/object.ts","../../emmett/src/streaming/decoders/composite.ts","../../emmett/src/streaming/restream.ts","../../emmett/src/utils/deepEquals.ts","../../emmett/src/utils/iterators.ts","../../emmett/src/utils/merge.ts","../../emmett/src/testing/assertions.ts","../../emmett/src/testing/deciderSpecification.ts","../../emmett/src/testing/wrapEventStore.ts","../src/eventStore/projections/index.ts","../src/eventStore/projections/pongo/pongoProjectionSpec.ts","../src/eventStore/projections/pongo/projections.ts","../src/eventStore/projections/postgresProjectionSpec.ts","../src/eventStore/schema/index.ts","../src/eventStore/schema/appendToStream.ts","../src/eventStore/schema/typing.ts","../src/eventStore/schema/tables.ts","../src/eventStore/schema/readStream.ts"],"sourcesContent":["import {\n dumbo,\n type MigrationStyle,\n type NodePostgresClientConnection,\n type NodePostgresConnector,\n type NodePostgresPool,\n type NodePostgresPoolClientConnection,\n} from '@event-driven-io/dumbo';\nimport {\n ExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type DefaultStreamVersionType,\n type Event,\n type EventStore,\n type EventStoreSession,\n type EventStoreSessionFactory,\n type ExpectedStreamVersion,\n type ProjectionRegistration,\n type ReadEventMetadataWithGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport pg from 'pg';\nimport {\n handleProjections,\n type PostgreSQLProjectionHandlerContext,\n} from './projections';\nimport {\n appendToStream,\n createEventStoreSchema,\n readStream,\n schemaSQL,\n type AppendToStreamPreCommitHook,\n} from './schema';\n\nexport interface PostgresEventStore\n extends EventStore<\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n >,\n EventStoreSessionFactory<PostgresEventStore, DefaultStreamVersionType> {\n close(): Promise<void>;\n schema: {\n sql(): string;\n print(): void;\n migrate(): Promise<void>;\n };\n}\n\ntype PostgresEventStorePooledOptions =\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: true;\n pool: pg.Pool;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pool: pg.Pool;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: true;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n };\n\ntype PostgresEventStoreNotPooledOptions =\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: false;\n client: pg.Client;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n client: pg.Client;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n pooled: false;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n connection:\n | NodePostgresPoolClientConnection\n | NodePostgresClientConnection;\n pooled?: false;\n }\n | {\n connector?: NodePostgresConnector;\n connectionString?: string;\n database?: string;\n dumbo: NodePostgresPool;\n pooled?: false;\n };\n\nexport type PostgresEventStoreConnectionOptions =\n | PostgresEventStorePooledOptions\n | PostgresEventStoreNotPooledOptions;\n\nexport type PostgresEventStoreOptions = {\n projections?: ProjectionRegistration<\n 'inline',\n PostgreSQLProjectionHandlerContext\n >[];\n schema?: { autoMigration?: MigrationStyle };\n connectionOptions?: PostgresEventStoreConnectionOptions;\n};\n\nexport const defaultPostgreSQLOptions: PostgresEventStoreOptions = {\n projections: [],\n schema: { autoMigration: 'CreateOrUpdate' },\n};\n\nexport const getPostgreSQLEventStore = (\n connectionString: string,\n options: PostgresEventStoreOptions = defaultPostgreSQLOptions,\n): PostgresEventStore => {\n const poolOptions = {\n connectionString,\n ...(options.connectionOptions ? options.connectionOptions : {}),\n };\n const pool = 'dumbo' in poolOptions ? poolOptions.dumbo : dumbo(poolOptions);\n let migrateSchema: Promise<void>;\n\n const autoGenerateSchema =\n options.schema?.autoMigration === undefined ||\n options.schema?.autoMigration !== 'None';\n\n const ensureSchemaExists = () => {\n if (!autoGenerateSchema) return Promise.resolve();\n\n if (!migrateSchema) {\n migrateSchema = createEventStoreSchema(pool);\n }\n return migrateSchema;\n };\n\n const inlineProjections = (options.projections ?? [])\n .filter(({ type }) => type === 'inline')\n .map(({ projection }) => projection);\n\n const preCommitHook: AppendToStreamPreCommitHook | undefined =\n inlineProjections.length > 0\n ? (events, { transaction }) =>\n handleProjections({\n projections: inlineProjections,\n connection: {\n connectionString,\n transaction,\n },\n events,\n })\n : undefined;\n\n return {\n schema: {\n sql: () => schemaSQL.join(''),\n print: () => console.log(schemaSQL.join('')),\n migrate: async () => {\n await (migrateSchema = createEventStoreSchema(pool));\n },\n },\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n const { evolve, initialState, read } = options;\n\n const expectedStreamVersion = read?.expectedStreamVersion;\n\n let state = initialState();\n\n const result = await this.readStream<EventType>(streamName, options.read);\n\n if (result === null) return null;\n\n const currentStreamVersion = result.currentStreamVersion;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n );\n\n for (const event of result.events) {\n if (!event) continue;\n\n state = evolve(state, event);\n }\n\n return {\n currentStreamVersion: currentStreamVersion,\n state,\n };\n },\n\n readStream: async <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<\n ReadStreamResult<\n EventType,\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n >\n > => {\n await ensureSchemaExists();\n return readStream<EventType>(pool.execute, streamName, options);\n },\n\n appendToStream: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> => {\n await ensureSchemaExists();\n // TODO: This has to be smarter when we introduce urn-based resolution\n const [firstPart, ...rest] = streamName.split('-');\n\n const streamType =\n firstPart && rest.length > 0 ? firstPart : 'emt:unknown';\n\n const appendResult = await appendToStream(\n pool,\n streamName,\n streamType,\n events,\n {\n ...options,\n preCommitHook,\n },\n );\n\n if (!appendResult.success)\n throw new ExpectedVersionConflictError<bigint>(\n -1n, //TODO: Return actual version in case of error\n options?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n );\n\n return { nextExpectedStreamVersion: appendResult.nextStreamPosition };\n },\n close: () => pool.close(),\n\n async withSession<T = unknown>(\n callback: (\n session: EventStoreSession<\n PostgresEventStore,\n DefaultStreamVersionType\n >,\n ) => Promise<T>,\n ): Promise<T> {\n return await pool.withConnection(async (connection) => {\n const storeOptions: PostgresEventStoreOptions = {\n ...options,\n connectionOptions: {\n connection,\n },\n };\n\n const eventStore = getPostgreSQLEventStore(\n connectionString,\n storeOptions,\n );\n\n return callback({\n eventStore,\n close: () => Promise.resolve(),\n });\n });\n },\n };\n};\n\nconst matchesExpectedVersion = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nconst assertExpectedVersionMatchesCurrent = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n","import { ValidationError } from '../errors';\n\nexport const enum ValidationErrors {\n NOT_A_NONEMPTY_STRING = 'NOT_A_NONEMPTY_STRING',\n NOT_A_POSITIVE_NUMBER = 'NOT_A_POSITIVE_NUMBER',\n NOT_AN_UNSIGNED_BIGINT = 'NOT_AN_UNSIGNED_BIGINT',\n}\n\nexport const isNumber = (val: unknown): val is number =>\n typeof val === 'number' && val === val;\n\nexport const isString = (val: unknown): val is string =>\n typeof val === 'string';\n\nexport const assertNotEmptyString = (value: unknown): string => {\n if (!isString(value) || value.length === 0) {\n throw new ValidationError(ValidationErrors.NOT_A_NONEMPTY_STRING);\n }\n return value;\n};\n\nexport const assertPositiveNumber = (value: unknown): number => {\n if (!isNumber(value) || value <= 0) {\n throw new ValidationError(ValidationErrors.NOT_A_POSITIVE_NUMBER);\n }\n return value;\n};\n\nexport const assertUnsignedBigInt = (value: string): bigint => {\n const number = BigInt(value);\n if (number < 0) {\n throw new ValidationError(ValidationErrors.NOT_AN_UNSIGNED_BIGINT);\n }\n return number;\n};\n\nexport * from './dates';\n","import { isNumber, isString } from '../validation';\n\nexport type ErrorConstructor<ErrorType extends Error> = new (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ...args: any[]\n) => ErrorType;\n\nexport const isErrorConstructor = <ErrorType extends Error>(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n expect: Function,\n): expect is ErrorConstructor<ErrorType> => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return (\n typeof expect === 'function' &&\n expect.prototype &&\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n expect.prototype.constructor === expect\n );\n};\n\nexport class EmmettError extends Error {\n public errorCode: number;\n\n constructor(\n options?: { errorCode: number; message?: string } | string | number,\n ) {\n const errorCode =\n options && typeof options === 'object' && 'errorCode' in options\n ? options.errorCode\n : isNumber(options)\n ? options\n : 500;\n const message =\n options && typeof options === 'object' && 'message' in options\n ? options.message\n : isString(options)\n ? options\n : `Error with status code '${errorCode}' ocurred during Emmett processing`;\n\n super(message);\n this.errorCode = errorCode;\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, EmmettError.prototype);\n }\n}\n\nexport class ConcurrencyError extends EmmettError {\n constructor(\n public current: string | undefined,\n public expected: string,\n message?: string,\n ) {\n super({\n errorCode: 412,\n message:\n message ??\n `Expected version ${expected.toString()} does not match current ${current?.toString()}`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyError.prototype);\n }\n}\n\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 400,\n message: message ?? `Validation Error ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class IllegalStateError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 403,\n message: message ?? `Illegal State ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, IllegalStateError.prototype);\n }\n}\n\nexport class NotFoundError extends EmmettError {\n constructor(options?: { id: string; type: string; message?: string }) {\n super({\n errorCode: 404,\n message:\n options?.message ??\n (options?.id\n ? options.type\n ? `${options.type} with ${options.id} was not found during Emmett processing`\n : `State with ${options.id} was not found during Emmett processing`\n : options?.type\n ? `${options.type} was not found during Emmett processing`\n : 'State was not found during Emmett processing'),\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n","import { ValidationError } from '../errors';\n\nexport const formatDateToUtcYYYYMMDD = (date: Date) => {\n // Use the 'en-CA' locale which formats as 'yyyy-mm-dd'\n const formatter = new Intl.DateTimeFormat('en-CA', {\n timeZone: 'UTC',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n });\n\n // Format the date\n return formatter.format(date);\n};\n\n// Function to validate 'yyyy-mm-dd' format\nexport const isValidYYYYMMDD = (dateString: string) => {\n const regex = /^\\d{4}-\\d{2}-\\d{2}$/;\n return regex.test(dateString);\n};\n\nexport const parseDateFromUtcYYYYMMDD = (dateString: string) => {\n const date = new Date(dateString + 'T00:00:00Z');\n\n if (!isValidYYYYMMDD(dateString)) {\n throw new ValidationError('Invalid date format, must be yyyy-mm-dd');\n }\n\n if (isNaN(date.getTime())) {\n throw new ValidationError('Invalid date format');\n }\n\n return date;\n};\n","import { Command as CliCommand } from 'commander';\n\nexport type EmmettPluginConfig =\n | {\n name: string;\n register: EmmettPluginRegistration[];\n }\n | string;\n\nexport type EmmettPluginType = 'cli';\n\nexport type EmmettCliPluginRegistration = { pluginType: 'cli'; path?: string };\n\nexport type EmmettPluginRegistration = EmmettCliPluginRegistration;\n\nexport type EmmettCliPlugin = {\n pluginType: 'cli';\n name: string;\n registerCommands: (program: CliCommand) => Promise<void> | void;\n};\n\nexport type EmmettPlugin = EmmettCliPlugin;\n\nexport const isPluginConfig = (\n plugin: Partial<EmmettPluginConfig> | string | undefined,\n): plugin is EmmettPluginConfig =>\n plugin !== undefined &&\n (typeof plugin === 'string' ||\n ('name' in plugin &&\n plugin.name !== undefined &&\n typeof plugin.name === 'string'));\n","import type { Event, ReadEvent, ReadEventMetadata } from '../typing';\nimport type { ExpectedStreamVersion } from './expectedVersion';\n\n// #region event-store\nexport interface EventStore<\n StreamVersion = DefaultStreamVersionType,\n ReadEventMetadataType extends ReadEventMetadata = ReadEventMetadata,\n> {\n aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n StreamVersion,\n ReadEventMetadataType\n >,\n ): Promise<AggregateStreamResult<State, StreamVersion> | null>;\n\n readStream<EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions<StreamVersion>,\n ): Promise<ReadStreamResult<EventType, StreamVersion, ReadEventMetadataType>>;\n\n appendToStream<EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<StreamVersion>,\n ): Promise<AppendToStreamResult<StreamVersion>>;\n}\n\nexport type EventStoreSession<\n EventStoreType extends EventStore<StreamVersion>,\n StreamVersion = DefaultStreamVersionType,\n> = {\n eventStore: EventStoreType;\n close: () => Promise<void>;\n};\n\nexport interface EventStoreSessionFactory<\n EventStoreType extends EventStore<StreamVersion>,\n StreamVersion = DefaultStreamVersionType,\n> {\n withSession<T = unknown>(\n callback: (\n session: EventStoreSession<EventStoreType, StreamVersion>,\n ) => Promise<T>,\n ): Promise<T>;\n}\n\nexport type DefaultStreamVersionType = bigint;\n// #endregion event-store\n\nexport const canCreateEventStoreSession = <\n Store extends EventStore<StreamVersion>,\n StreamVersion = DefaultStreamVersionType,\n>(\n eventStore: Store | EventStoreSessionFactory<Store, StreamVersion>,\n): eventStore is EventStoreSessionFactory<Store, StreamVersion> =>\n 'withSession' in eventStore;\n\nexport const nulloSessionFactory = <\n EventStoreType extends EventStore<StreamVersion>,\n StreamVersion = DefaultStreamVersionType,\n>(\n eventStore: EventStoreType,\n): EventStoreSessionFactory<EventStoreType, StreamVersion> => ({\n withSession: (callback) => {\n const nulloSession: EventStoreSession<EventStoreType, StreamVersion> = {\n eventStore,\n close: () => Promise.resolve(),\n };\n\n return callback(nulloSession);\n },\n});\n\n////////////////////////////////////////////////////////////////////\n/// ReadStream types\n////////////////////////////////////////////////////////////////////\n\nexport type ReadStreamOptions<StreamVersion = DefaultStreamVersionType> = (\n | {\n from: StreamVersion;\n }\n | { to: StreamVersion }\n | { from: StreamVersion; maxCount?: bigint }\n | {\n expectedStreamVersion: ExpectedStreamVersion<StreamVersion>;\n }\n) & {\n expectedStreamVersion?: ExpectedStreamVersion<StreamVersion>;\n};\n\nexport type ReadStreamResult<\n EventType extends Event,\n StreamVersion = DefaultStreamVersionType,\n ReadEventMetadataType extends ReadEventMetadata = ReadEventMetadata,\n> = {\n currentStreamVersion: StreamVersion;\n events: ReadEvent<EventType, ReadEventMetadataType>[];\n} | null;\n\n////////////////////////////////////////////////////////////////////\n/// AggregateStream types\n////////////////////////////////////////////////////////////////////\n\ntype Evolve<\n State,\n EventType extends Event,\n ReadEventMetadataType extends ReadEventMetadata = ReadEventMetadata,\n> =\n | ((currentState: State, event: EventType) => State)\n | ((\n currentState: State,\n event: ReadEvent<EventType, ReadEventMetadataType>,\n ) => State)\n | ((currentState: State, event: ReadEvent<EventType>) => State);\n\nexport type AggregateStreamOptions<\n State,\n EventType extends Event,\n StreamVersion = DefaultStreamVersionType,\n ReadEventMetadataType extends ReadEventMetadata = ReadEventMetadata,\n> = {\n evolve: Evolve<State, EventType, ReadEventMetadataType>;\n initialState: () => State;\n read?: ReadStreamOptions<StreamVersion>;\n};\n\nexport type AggregateStreamResult<\n State,\n StreamVersion = DefaultStreamVersionType,\n> = {\n currentStreamVersion: StreamVersion;\n state: State;\n};\n\n////////////////////////////////////////////////////////////////////\n/// AppendToStream types\n////////////////////////////////////////////////////////////////////\n\nexport type AppendToStreamOptions<StreamVersion = DefaultStreamVersionType> = {\n expectedStreamVersion?: ExpectedStreamVersion<StreamVersion>;\n};\n\nexport type AppendToStreamResult<StreamVersion = DefaultStreamVersionType> = {\n nextExpectedStreamVersion: StreamVersion;\n};\n","import { ConcurrencyError } from '../errors';\nimport type { Flavour } from '../typing';\nimport type { DefaultStreamVersionType } from './eventStore';\n\nexport type ExpectedStreamVersion<VersionType = DefaultStreamVersionType> =\n | ExpectedStreamVersionWithValue<VersionType>\n | ExpectedStreamVersionGeneral;\n\nexport type ExpectedStreamVersionWithValue<\n VersionType = DefaultStreamVersionType,\n> = Flavour<VersionType, 'StreamVersion'>;\n\nexport type ExpectedStreamVersionGeneral = Flavour<\n 'STREAM_EXISTS' | 'STREAM_DOES_NOT_EXIST' | 'NO_CONCURRENCY_CHECK',\n 'StreamVersion'\n>;\n\nexport const STREAM_EXISTS = 'STREAM_EXISTS' as ExpectedStreamVersionGeneral;\nexport const STREAM_DOES_NOT_EXIST =\n 'STREAM_DOES_NOT_EXIST' as ExpectedStreamVersionGeneral;\nexport const NO_CONCURRENCY_CHECK =\n 'NO_CONCURRENCY_CHECK' as ExpectedStreamVersionGeneral;\n\nexport const matchesExpectedVersion = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion>,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nexport const assertExpectedVersionMatchesCurrent = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion> | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n\nexport class ExpectedVersionConflictError<\n VersionType = DefaultStreamVersionType,\n> extends ConcurrencyError {\n constructor(\n current: VersionType | undefined,\n expected: ExpectedStreamVersion<VersionType>,\n ) {\n super(current?.toString(), expected?.toString());\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);\n }\n}\n","import { v4 as randomUUID } from 'uuid';\nimport type {\n Event,\n ReadEvent,\n ReadEventMetadataWithGlobalPosition,\n} from '../typing';\nimport {\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type DefaultStreamVersionType,\n type EventStore,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\n\nexport type EventHandler<E extends Event = Event> = (\n eventEnvelope: ReadEvent<E>,\n) => void;\n\nexport const getInMemoryEventStore = (): EventStore<\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n> => {\n const streams = new Map<string, ReadEvent[]>();\n\n const getAllEventsCount = () => {\n return Array.from<ReadEvent[]>(streams.values())\n .map((s) => s.length)\n .reduce((p, c) => p + c, 0);\n };\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n const { evolve, initialState, read } = options;\n\n const result = await this.readStream<EventType>(streamName, read);\n\n if (!result) return null;\n\n const events = result?.events ?? [];\n\n return {\n currentStreamVersion: BigInt(events.length),\n state: events.reduce(evolve, initialState()),\n };\n },\n\n readStream: <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<\n ReadStreamResult<\n EventType,\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n >\n > => {\n const events = streams.get(streamName);\n const currentStreamVersion = events ? BigInt(events.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n );\n\n const from = Number(options && 'from' in options ? options.from : 0);\n const to = Number(\n options && 'to' in options\n ? options.to\n : options && 'maxCount' in options && options.maxCount\n ? options.from + options.maxCount\n : (events?.length ?? 1),\n );\n\n const resultEvents =\n events && events.length > 0\n ? events\n .map(\n (e) =>\n e as ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >,\n )\n .slice(from, to)\n : [];\n\n const result: ReadStreamResult<\n EventType,\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n > =\n events && events.length > 0\n ? {\n currentStreamVersion: currentStreamVersion!,\n events: resultEvents,\n }\n : null;\n\n return Promise.resolve(result);\n },\n\n appendToStream: <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> => {\n const currentEvents = streams.get(streamName) ?? [];\n const currentStreamVersion =\n currentEvents.length > 0 ? BigInt(currentEvents.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n );\n\n const eventEnvelopes: ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >[] = events.map((event, index) => {\n return {\n ...event,\n metadata: {\n ...(event.metadata ?? {}),\n streamName,\n eventId: randomUUID(),\n streamPosition: BigInt(currentEvents.length + index + 1),\n globalPosition: BigInt(getAllEventsCount() + index + 1),\n },\n };\n });\n\n const positionOfLastEventInTheStream = BigInt(\n eventEnvelopes.slice(-1)[0]!.metadata.streamPosition,\n );\n\n streams.set(streamName, [...currentEvents, ...eventEnvelopes]);\n\n const result: AppendToStreamResult = {\n nextExpectedStreamVersion: positionOfLastEventInTheStream,\n };\n\n return Promise.resolve(result);\n },\n };\n};\n","import {\n canCreateEventStoreSession,\n NO_CONCURRENCY_CHECK,\n nulloSessionFactory,\n STREAM_DOES_NOT_EXIST,\n type AppendToStreamResult,\n type DefaultStreamVersionType,\n type EventStore,\n type EventStoreSession,\n type ExpectedStreamVersion,\n} from '../eventStore';\nimport type { Event } from '../typing';\n\n// #region command-handler\nexport type CommandHandlerResult<\n State,\n StreamEvent extends Event,\n StreamVersion = DefaultStreamVersionType,\n> = AppendToStreamResult<StreamVersion> & {\n newState: State;\n newEvents: StreamEvent[];\n};\n\nexport const CommandHandler =\n <State, StreamEvent extends Event, StreamVersion = DefaultStreamVersionType>(\n evolve: (state: State, event: StreamEvent) => State,\n initialState: () => State,\n mapToStreamId: (id: string) => string = (id) => id,\n ) =>\n async <Store extends EventStore<StreamVersion>>(\n store: Store,\n id: string,\n handle: (state: State) => StreamEvent | StreamEvent[],\n options?: Parameters<Store['appendToStream']>[2] & {\n expectedStreamVersion?: ExpectedStreamVersion<StreamVersion>;\n },\n ): Promise<CommandHandlerResult<State, StreamEvent, StreamVersion>> => {\n const result = await withSession<\n Store,\n StreamVersion,\n CommandHandlerResult<State, StreamEvent, StreamVersion>\n >(store, async ({ eventStore }) => {\n const streamName = mapToStreamId(id);\n\n // 1. Aggregate the stream\n const aggregationResult = await eventStore.aggregateStream<\n State,\n StreamEvent\n >(streamName, {\n evolve,\n initialState,\n read: {\n // expected stream version is passed to fail fast\n // if stream is in the wrong state\n expectedStreamVersion:\n options?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n },\n });\n\n // 2. Use the aggregate state or the initial one (when e.g. stream does not exist)\n const state = aggregationResult?.state ?? initialState();\n const currentStreamVersion = aggregationResult?.currentStreamVersion;\n\n // 3. Run business logic\n const result = handle(state);\n\n const newEvents = Array.isArray(result) ? result : [result];\n\n // Either use:\n // - provided expected stream version,\n // - current stream version got from stream aggregation,\n // - or expect stream not to exists otherwise.\n const expectedStreamVersion: ExpectedStreamVersion<StreamVersion> =\n options?.expectedStreamVersion ??\n currentStreamVersion ??\n STREAM_DOES_NOT_EXIST;\n\n // 4. Append result to the stream\n const appendResult = await eventStore.appendToStream(\n streamName,\n newEvents,\n {\n ...options,\n expectedStreamVersion,\n },\n );\n\n // 5. Return result with updated state\n return {\n ...appendResult,\n newEvents,\n newState: newEvents.reduce(evolve, state),\n };\n });\n\n return result;\n };\n// #endregion command-handler\n\nconst withSession = <\n EventStoreType extends EventStore<StreamVersion>,\n StreamVersion = DefaultStreamVersionType,\n T = unknown,\n>(\n eventStore: EventStoreType,\n callback: (\n session: EventStoreSession<EventStoreType, StreamVersion>,\n ) => Promise<T>,\n) => {\n const sessionFactory = canCreateEventStoreSession<\n EventStoreType,\n StreamVersion\n >(eventStore)\n ? eventStore\n : nulloSessionFactory<EventStoreType, StreamVersion>(eventStore);\n\n return sessionFactory.withSession(callback);\n};\n","import type {\n DefaultStreamVersionType,\n EventStore,\n ExpectedStreamVersion,\n} from '../eventStore';\nimport type { Command, Event } from '../typing';\nimport type { Decider } from '../typing/decider';\nimport { CommandHandler } from './handleCommand';\n\n// #region command-handler\nexport const DeciderCommandHandler =\n <\n State,\n CommandType extends Command,\n StreamEvent extends Event,\n StreamVersion = DefaultStreamVersionType,\n >(\n { decide, evolve, initialState }: Decider<State, CommandType, StreamEvent>,\n mapToStreamId: (id: string) => string = (id) => id,\n ) =>\n async (\n eventStore: EventStore<StreamVersion>,\n id: string,\n command: CommandType,\n options?: {\n expectedStreamVersion?: ExpectedStreamVersion<StreamVersion>;\n },\n ) =>\n CommandHandler<State, StreamEvent, StreamVersion>(\n evolve,\n initialState,\n mapToStreamId,\n )(eventStore, id, (state) => decide(command, state), options);\n// #endregion command-handler\n","import type { DefaultRecord, Flavour } from './';\nexport type Command<\n CommandType extends string = string,\n CommandData extends DefaultRecord = DefaultRecord,\n CommandMetaData extends DefaultRecord = DefaultCommandMetadata,\n> = Flavour<\n Readonly<{\n type: CommandType;\n data: Readonly<CommandData>;\n metadata?: CommandMetaData | undefined;\n }>,\n 'Command'\n>;\n\nexport type CommandTypeOf<T extends Command> = T['type'];\nexport type CommandDataOf<T extends Command> = T['data'];\nexport type CommandMetaDataOf<T extends Command> = T['metadata'];\n\nexport type CreateCommandType<\n CommandType extends string,\n CommandData extends DefaultRecord,\n CommandMetaData extends DefaultRecord | undefined,\n> = Readonly<{\n type: CommandType;\n data: CommandData;\n metadata?: CommandMetaData;\n}>;\n\nexport const command = <CommandType extends Command>(\n type: CommandTypeOf<CommandType>,\n data: CommandDataOf<CommandType>,\n metadata?: CommandMetaDataOf<CommandType>,\n): CreateCommandType<\n CommandTypeOf<CommandType>,\n CommandDataOf<CommandType>,\n CommandMetaDataOf<CommandType>\n> => {\n return {\n type,\n data,\n metadata,\n };\n};\n\nexport type DefaultCommandMetadata = { now: Date };\n","import type { DefaultRecord, Flavour } from './';\n\nexport type Event<\n EventType extends string = string,\n EventData extends DefaultRecord = DefaultRecord,\n EventMetaData extends DefaultRecord = DefaultRecord,\n> = Flavour<\n Readonly<{\n type: EventType;\n data: EventData;\n metadata?: EventMetaData;\n }>,\n 'Event'\n>;\n\nexport type EventTypeOf<T extends Event> = T['type'];\nexport type EventDataOf<T extends Event> = T['data'];\nexport type EventMetaDataOf<T extends Event> = T['metadata'];\n\nexport type CanHandle<T extends Event> = EventTypeOf<T>[];\n\nexport type CreateEventType<\n EventType extends string,\n EventData extends DefaultRecord,\n EventMetaData extends DefaultRecord | undefined,\n> = Readonly<{\n type: EventType;\n data: EventData;\n metadata?: EventMetaData;\n}>;\n\nexport const event = <EventType extends Event>(\n type: EventTypeOf<EventType>,\n data: EventDataOf<EventType>,\n metadata?: EventMetaDataOf<EventType>,\n): CreateEventType<\n EventTypeOf<EventType>,\n EventDataOf<EventType>,\n EventMetaDataOf<EventType>\n> => {\n return {\n type,\n data,\n metadata,\n };\n};\n\nexport type ReadEvent<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n> = CreateEventType<\n EventTypeOf<EventType>,\n EventDataOf<EventType>,\n EventMetaDataType\n> &\n EventType & { metadata: EventMetaDataType };\n\nexport type ReadEventMetadata = Readonly<{\n eventId: string;\n streamPosition: bigint;\n streamName: string;\n}>;\n\nexport type ReadEventMetadataWithGlobalPosition = ReadEventMetadata & {\n globalPosition: bigint;\n};\n","import type { Command } from './command';\nimport type { Event } from './event';\n\n/// Inspired by https://blog.bittacklr.be/the-workflow-pattern.html\n\nexport type Workflow<\n Input extends Event | Command,\n State,\n Output extends Event | Command,\n> = {\n decide: (command: Input, state: State) => WorkflowOutput<Output>[];\n evolve: (currentState: State, event: WorkflowEvent<Output>) => State;\n initialState: () => State;\n};\n\nexport type WorkflowEvent<Output extends Command | Event> = Extract<\n Output,\n { __brand?: 'Event' }\n>;\n\nexport type WorkflowCommand<Output extends Command | Event> = Extract<\n Output,\n { __brand?: 'Command' }\n>;\n\nexport type WorkflowOutput<TOutput extends Command | Event> =\n | { kind: 'Reply'; message: TOutput }\n | { kind: 'Send'; message: WorkflowCommand<TOutput> }\n | { kind: 'Publish'; message: WorkflowEvent<TOutput> }\n | {\n kind: 'Schedule';\n message: TOutput;\n when: { afterInMs: number } | { at: Date };\n }\n | { kind: 'Complete' }\n | { kind: 'Accept' }\n | { kind: 'Ignore'; reason: string }\n | { kind: 'Error'; reason: string };\n\nexport const reply = <TOutput extends Command | Event>(\n message: TOutput,\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Reply',\n message,\n };\n};\n\nexport const send = <TOutput extends Command | Event>(\n message: WorkflowCommand<TOutput>,\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Send',\n message,\n };\n};\n\nexport const publish = <TOutput extends Command | Event>(\n message: WorkflowEvent<TOutput>,\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Publish',\n message,\n };\n};\n\nexport const schedule = <TOutput extends Command | Event>(\n message: TOutput,\n when: { afterInMs: number } | { at: Date },\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Schedule',\n message,\n when,\n };\n};\n\nexport const complete = <\n TOutput extends Command | Event,\n>(): WorkflowOutput<TOutput> => {\n return {\n kind: 'Complete',\n };\n};\n\nexport const ignore = <TOutput extends Command | Event>(\n reason: string,\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Ignore',\n reason,\n };\n};\n\nexport const error = <TOutput extends Command | Event>(\n reason: string,\n): WorkflowOutput<TOutput> => {\n return {\n kind: 'Error',\n reason,\n };\n};\n\nexport const accept = <\n TOutput extends Command | Event,\n>(): WorkflowOutput<TOutput> => {\n return { kind: 'Accept' };\n};\n","import { EmmettError } from '../errors';\nimport {\n type Command,\n type CommandTypeOf,\n type Event,\n type EventTypeOf,\n} from '../typing';\n\nexport interface CommandSender {\n send<CommandType extends Command = Command>(\n command: CommandType,\n ): Promise<void>;\n}\n\nexport interface EventsPublisher {\n publish<EventType extends Event = Event>(event: EventType): Promise<void>;\n}\n\nexport type ScheduleOptions = { afterInMs: number } | { at: Date };\n\nexport interface MessageScheduler<CommandOrEvent extends Command | Event> {\n schedule<MessageType extends CommandOrEvent>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void;\n}\n\nexport interface CommandBus extends CommandSender, MessageScheduler<Command> {}\n\nexport interface EventBus extends EventsPublisher, MessageScheduler<Event> {}\n\nexport interface MessageBus extends CommandBus, EventBus {\n schedule<MessageType extends Command | Event>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void;\n}\n\ntype CommandHandler<CommandType extends Command = Command> = (\n command: CommandType,\n) => Promise<void> | void;\n\nexport interface CommandProcessor {\n handle<CommandType extends Command>(\n commandHandler: CommandHandler<CommandType>,\n ...commandTypes: CommandTypeOf<CommandType>[]\n ): void;\n}\n\ntype EventHandler<EventType extends Event = Event> = (\n event: EventType,\n) => Promise<void> | void;\n\nexport interface EventProcessor {\n subscribe<EventType extends Event>(\n eventHandler: EventHandler<EventType>,\n ...eventTypes: EventTypeOf<EventType>[]\n ): void;\n}\n\nexport type ScheduledMessage = {\n message: Event | Command;\n options?: ScheduleOptions;\n};\n\nexport interface ScheduledMessageProcessor {\n dequeue(): ScheduledMessage[];\n}\n\nexport type MessageHandler = CommandHandler | EventHandler;\n\nexport type MessageProcessor = EventProcessor | CommandProcessor;\n\nexport const getInMemoryMessageBus = (): MessageBus &\n EventProcessor &\n CommandProcessor &\n ScheduledMessageProcessor => {\n const allHandlers = new Map<string, MessageHandler[]>();\n let pendingMessages: ScheduledMessage[] = [];\n\n return {\n send: async <CommandType extends Command = Command>(\n command: CommandType,\n ): Promise<void> => {\n const handlers = allHandlers.get(command.type);\n\n if (handlers === undefined || handlers.length === 0)\n throw new EmmettError(\n `No handler registered for command ${command.type}!`,\n );\n\n const commandHandler = handlers[0] as CommandHandler<CommandType>;\n\n await commandHandler(command);\n },\n\n publish: async <EventType extends Event = Event>(\n event: EventType,\n ): Promise<void> => {\n const handlers = allHandlers.get(event.type) ?? [];\n\n for (const handler of handlers) {\n const eventHandler = handler as EventHandler<EventType>;\n\n await eventHandler(event);\n }\n },\n\n schedule: <MessageType extends Command | Event>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void => {\n pendingMessages = [...pendingMessages, { message, options: when }];\n },\n\n handle: <CommandType extends Command>(\n commandHandler: CommandHandler<CommandType>,\n ...commandTypes: CommandTypeOf<CommandType>[]\n ): void => {\n const alreadyRegistered = [...allHandlers.keys()].filter((registered) =>\n commandTypes.includes(registered),\n );\n\n if (alreadyRegistered.length > 0)\n throw new EmmettError(\n `Cannot register handler for commands ${alreadyRegistered.join(', ')} as they're already registered!`,\n );\n for (const commandType of commandTypes) {\n allHandlers.set(commandType, [commandHandler as MessageHandler]);\n }\n },\n\n subscribe<EventType extends Event>(\n eventHandler: EventHandler<EventType>,\n ...eventTypes: EventTypeOf<EventType>[]\n ): void {\n for (const eventType of eventTypes) {\n if (!allHandlers.has(eventType)) allHandlers.set(eventType, []);\n\n allHandlers.set(eventType, [\n ...(allHandlers.get(eventType) ?? []),\n eventHandler as MessageHandler,\n ]);\n }\n },\n\n dequeue: (): ScheduledMessage[] => {\n const pending = pendingMessages;\n pendingMessages = [];\n return pending;\n },\n };\n};\n","import type {\n CanHandle,\n DefaultRecord,\n Event,\n EventMetaDataOf,\n ReadEvent,\n ReadEventMetadata,\n} from '../typing';\n\nexport type ProjectionHandlingType = 'inline' | 'async';\n\nexport type ProjectionHandler<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = (\n events: ReadEvent<EventType, EventMetaDataType>[],\n context: ProjectionHandlerContext,\n) => Promise<void> | void;\n\nexport interface ProjectionDefinition<\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> {\n name?: string;\n canHandle: CanHandle<Event>;\n handle: ProjectionHandler<Event, ReadEventMetadata, ProjectionHandlerContext>;\n}\n\nexport interface TypedProjectionDefinition<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> {\n name?: string;\n canHandle: CanHandle<EventType>;\n handle: ProjectionHandler<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n >;\n}\n\nexport type ProjectionRegistration<\n HandlingType extends ProjectionHandlingType,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n type: HandlingType;\n projection: ProjectionDefinition<ProjectionHandlerContext>;\n};\n\nexport const projection = <\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n ProjectionDefintionType extends TypedProjectionDefinition<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n > = ProjectionDefinition<ProjectionHandlerContext>,\n>(\n definition: ProjectionDefintionType,\n): ProjectionDefintionType => definition;\n\nexport const inlineProjections = <\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n ProjectionDefintionType extends\n ProjectionDefinition<ProjectionHandlerContext> = ProjectionDefinition<ProjectionHandlerContext>,\n>(\n definitions: ProjectionDefintionType[],\n): ProjectionRegistration<'inline', ProjectionHandlerContext>[] =>\n definitions.map((projection) => ({ type: 'inline', projection }));\n\nexport const asyncProjections = <\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n ProjectionDefintionType extends\n ProjectionDefinition<ProjectionHandlerContext> = ProjectionDefinition<ProjectionHandlerContext>,\n>(\n definitions: ProjectionDefintionType[],\n): ProjectionRegistration<'async', ProjectionHandlerContext>[] =>\n definitions.map((projection) => ({ type: 'async', projection }));\n\nexport const projections = {\n inline: inlineProjections,\n async: asyncProjections,\n};\n","export class ParseError extends Error {\n constructor(text: string) {\n super(`Cannot parse! ${text}`);\n }\n}\n\nexport type Mapper<From, To = From> =\n | ((value: unknown) => To)\n | ((value: Partial<From>) => To)\n | ((value: From) => To)\n | ((value: Partial<To>) => To)\n | ((value: To) => To)\n | ((value: Partial<To | From>) => To)\n | ((value: To | From) => To);\n\nexport type MapperArgs<From, To = From> = Partial<From> &\n From &\n Partial<To> &\n To;\n\nexport type ParseOptions<From, To = From> = {\n reviver?: (key: string, value: unknown) => unknown;\n map?: Mapper<From, To>;\n typeCheck?: <To>(value: unknown) => value is To;\n};\n\nexport type StringifyOptions<From, To = From> = {\n map?: Mapper<From, To>;\n};\n\nexport const JSONParser = {\n stringify: <From, To = From>(\n value: From,\n options?: StringifyOptions<From, To>,\n ) => {\n return JSON.stringify(\n options?.map ? options.map(value as MapperArgs<From, To>) : value,\n //TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n (_, v) => (typeof v === 'bigint' ? v.toString() : v),\n );\n },\n parse: <From, To = From>(\n text: string,\n options?: ParseOptions<From, To>,\n ): To | undefined => {\n const parsed: unknown = JSON.parse(text, options?.reviver);\n\n if (options?.typeCheck && !options?.typeCheck<To>(parsed))\n throw new ParseError(text);\n\n return options?.map\n ? options.map(parsed as MapperArgs<From, To>)\n : (parsed as To | undefined);\n },\n};\n","export const concatUint8Arrays = (chunks: Uint8Array[]): Uint8Array => {\n const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n return result;\n};\n","import type { ReadableStream } from 'web-streams-polyfill';\n\nexport const collectStream = async <T>(\n reader: ReadableStream<T>,\n): Promise<T[]> => {\n const results: T[] = [];\n\n for await (const value of reader) {\n results.push(value as T);\n }\n return results;\n};\n","import type { Decoder } from '.';\nimport { concatUint8Arrays } from '../binaryArrays';\n\nexport class BinaryJsonDecoder<Decoded>\n implements Decoder<Uint8Array, Decoded>\n{\n private buffer: Uint8Array[] = [];\n\n addToBuffer(data: Uint8Array): void {\n this.buffer.push(data);\n }\n\n clearBuffer(): void {\n this.buffer = [];\n }\n\n hasCompleteMessage(): boolean {\n const combined = concatUint8Arrays(this.buffer);\n const text = new TextDecoder().decode(combined);\n return text.includes('\\n');\n }\n\n decode(): Decoded | null {\n if (!this.hasCompleteMessage()) {\n return null;\n }\n\n const combined = concatUint8Arrays(this.buffer);\n const text = new TextDecoder().decode(combined);\n const delimiterIndex = text.indexOf('\\n');\n\n if (delimiterIndex === -1) {\n return null;\n }\n\n const jsonString = text.slice(0, delimiterIndex);\n const remaining = new Uint8Array(combined.buffer, delimiterIndex + 1);\n this.buffer = remaining.byteLength > 0 ? [remaining] : [];\n\n return JSON.parse(jsonString) as Decoded;\n }\n}\n","import type { Decoder } from '.';\n\nexport class StringDecoder<Decoded> implements Decoder<string, Decoded> {\n protected buffer: string[] = [];\n\n constructor(private transform: (input: string) => Decoded) {\n this.transform = transform;\n }\n\n addToBuffer(data: string): void {\n this.buffer.push(data);\n }\n\n clearBuffer(): void {\n this.buffer = [];\n }\n\n hasCompleteMessage(): boolean {\n return this.buffer.some((chunk) => chunk.includes('\\n'));\n }\n\n decode(): Decoded | null {\n const completeString = this.buffer.join('');\n\n if (!this.hasCompleteMessage()) {\n if (completeString.trim().length > 0) {\n throw new Error('Unterminated string in JSON at position');\n }\n return null;\n }\n\n const delimiterIndex = completeString.indexOf('\\n');\n const message = completeString.slice(0, delimiterIndex).trim();\n this.buffer = [completeString.slice(delimiterIndex + 1)];\n\n return this.transform(message);\n }\n}\n","import { StringDecoder } from './string';\n\nexport class JsonDecoder<Decoded> extends StringDecoder<Decoded> {\n constructor() {\n super((jsonString) => JSON.parse(jsonString) as Decoded);\n }\n}\n","import type { Decoder } from '.';\n\nexport class ObjectDecoder<Decoded> implements Decoder<Decoded, Decoded> {\n private buffer: Decoded | null = null;\n\n addToBuffer(data: Decoded): void {\n this.buffer = data;\n }\n\n clearBuffer(): void {\n this.buffer = null;\n }\n\n hasCompleteMessage(): boolean {\n return this.buffer !== null;\n }\n\n decode(): Decoded | null {\n if (!this.hasCompleteMessage() || !this.buffer) {\n return null;\n }\n\n const data = this.buffer;\n this.clearBuffer();\n return data as Decoded;\n }\n}\n","import type { Decoder } from '.';\nimport { BinaryJsonDecoder } from './binary';\nimport { JsonDecoder } from './json';\nimport { ObjectDecoder } from './object';\n\nexport class CompositeDecoder<Decoded> implements Decoder<unknown, Decoded> {\n constructor(\n private decoders: [(data: unknown) => boolean, Decoder<unknown, Decoded>][],\n ) {}\n\n private decoderFor(data: unknown): Decoder<unknown, unknown> | null {\n const decoder = this.decoders.find((d) => d[0](data));\n\n if (!decoder) return null;\n\n return decoder[1];\n }\n\n addToBuffer(data: unknown): void {\n this.decoderFor(data)?.addToBuffer(data);\n }\n\n clearBuffer(): void {\n for (const decoder of this.decoders.map((d) => d[1])) {\n decoder.clearBuffer();\n }\n }\n\n hasCompleteMessage(): boolean {\n return this.decoders.some((d) => d[1].hasCompleteMessage());\n }\n\n decode(): Decoded | null {\n const decoder = this.decoders\n .map((d) => d[1])\n .find((d) => d.hasCompleteMessage());\n\n return decoder?.decode() ?? null;\n }\n}\n\nexport class DefaultDecoder<Decoded> extends CompositeDecoder<Decoded> {\n constructor() {\n super([\n [(data) => typeof data === 'string', new JsonDecoder<Decoded>()],\n [(data) => data instanceof Uint8Array, new BinaryJsonDecoder<Decoded>()],\n [(data) => typeof data === 'object', new ObjectDecoder<Decoded>()],\n ]);\n }\n}\n","import retry from 'async-retry';\nimport {\n ReadableStream,\n ReadableStreamDefaultReader,\n TransformStream,\n TransformStreamDefaultController,\n} from 'web-streams-polyfill';\nimport type { Decoder } from './decoders';\nimport { DefaultDecoder } from './decoders/composite';\n\nexport const restream = <\n Source = unknown,\n Transformed = Source,\n StreamType = object,\n>(\n createSourceStream: () => ReadableStream<StreamType>,\n transform: (input: Source) => Transformed = (source) =>\n source as unknown as Transformed,\n retryOptions: retry.Options = { forever: true, minTimeout: 25 },\n decoder: Decoder<StreamType, Source> = new DefaultDecoder<Source>(),\n): ReadableStream<Transformed> =>\n new TransformStream<Source, Transformed>({\n start(controller) {\n retry(\n () => onRestream(createSourceStream, controller, transform, decoder),\n retryOptions,\n ).catch((error) => {\n controller.error(error);\n });\n },\n }).readable;\n\nconst onRestream = async <StreamType, Source, Transformed = Source>(\n createSourceStream: () => ReadableStream<StreamType>,\n controller: TransformStreamDefaultController<Transformed>,\n transform: (input: Source) => Transformed,\n decoder: Decoder<StreamType, Source>,\n): Promise<void> => {\n const sourceStream = createSourceStream();\n const reader = sourceStream.getReader();\n try {\n let done: boolean;\n\n do {\n done = await restreamChunk(reader, controller, transform, decoder);\n } while (!done);\n } finally {\n reader.releaseLock();\n }\n};\n\nconst restreamChunk = async <StreamType, Source, Transformed = Source>(\n reader: ReadableStreamDefaultReader<StreamType>,\n controller: TransformStreamDefaultController<Transformed>,\n transform: (input: Source) => Transformed,\n decoder: Decoder<StreamType, Source>,\n): Promise<boolean> => {\n const { done: isDone, value } = await reader.read();\n\n if (value) decoder.addToBuffer(value);\n\n if (!isDone && !decoder.hasCompleteMessage()) return false;\n\n decodeAndTransform(decoder, transform, controller);\n\n if (isDone) {\n controller.terminate();\n }\n\n return isDone;\n};\n\nconst decodeAndTransform = <StreamType, Source, Transformed = Source>(\n decoder: Decoder<StreamType, Source>,\n transform: (input: Source) => Transformed,\n controller: TransformStreamDefaultController<Transformed>,\n) => {\n try {\n const decoded = decoder.decode();\n if (!decoded) return;\n\n const transformed = transform(decoded);\n controller.enqueue(transformed);\n } catch (error) {\n controller.error(new Error(`Decoding error: ${error?.toString()}`));\n }\n};\n","export const deepEquals = <T>(left: T, right: T): boolean => {\n if (isEquatable(left)) {\n return left.equals(right);\n }\n\n if (Array.isArray(left)) {\n return (\n Array.isArray(right) &&\n left.length === right.length &&\n left.every((val, index) => deepEquals(val, right[index]))\n );\n }\n\n if (\n typeof left !== 'object' ||\n typeof right !== 'object' ||\n left === null ||\n right === null\n ) {\n return left === right;\n }\n\n if (Array.isArray(right)) return false;\n\n const keys1 = Object.keys(left);\n const keys2 = Object.keys(right);\n\n if (\n keys1.length !== keys2.length ||\n !keys1.every((key) => keys2.includes(key))\n )\n return false;\n\n for (const key in left) {\n if (left[key] instanceof Function && right[key] instanceof Function)\n continue;\n\n const isEqual = deepEquals(left[key], right[key]);\n if (!isEqual) {\n return false;\n }\n }\n\n return true;\n};\n\nexport type Equatable<T> = { equals: (right: T) => boolean } & T;\n\nexport const isEquatable = <T>(left: T): left is Equatable<T> => {\n return (\n left &&\n typeof left === 'object' &&\n 'equals' in left &&\n typeof left['equals'] === 'function'\n );\n};\n","export const sum = (\n iterator: Iterator<number, number, number> | Iterator<number>,\n) => {\n let value,\n done: boolean | undefined,\n sum = 0;\n do {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n ({ value, done } = iterator.next());\n sum += value || 0;\n } while (!done);\n return sum;\n};\n","export const merge = <T>(\n array: T[],\n item: T,\n where: (current: T) => boolean,\n onExisting: (current: T) => T,\n onNotFound: () => T | undefined = () => undefined,\n) => {\n let wasFound = false;\n\n const result = array\n // merge the existing item if matches condition\n .map((p: T) => {\n if (!where(p)) return p;\n\n wasFound = true;\n return onExisting(p);\n })\n // filter out item if undefined was returned\n // for cases of removal\n .filter((p) => p !== undefined)\n // make TypeScript happy\n .map((p) => {\n if (!p) throw Error('That should not happen');\n\n return p;\n });\n\n // if item was not found and onNotFound action is defined\n // try to generate new item\n if (!wasFound) {\n const result = onNotFound();\n\n if (result !== undefined) return [...array, item];\n }\n\n return result;\n};\n","import { JSONParser } from '../serialization';\nimport type { DefaultRecord } from '../typing';\nimport { deepEquals } from '../utils';\n\nexport class AssertionError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\nexport const isSubset = (superObj: unknown, subObj: unknown): boolean => {\n const sup = superObj as DefaultRecord;\n const sub = subObj as DefaultRecord;\n\n assertOk(sup);\n assertOk(sub);\n\n return Object.keys(sub).every((ele: string) => {\n if (typeof sub[ele] == 'object') {\n return isSubset(sup[ele], sub[ele]);\n }\n return sub[ele] === sup[ele];\n });\n};\n\nexport const assertFails = (message?: string) => {\n throw new AssertionError(message ?? 'That should not ever happened, right?');\n};\n\nexport const assertThrowsAsync = async <TError extends Error>(\n fun: () => Promise<void>,\n errorCheck?: (error: Error) => boolean,\n): Promise<TError> => {\n try {\n await fun();\n throw new AssertionError(\"Function didn't throw expected error\");\n } catch (error) {\n const typedError = error as TError;\n if (errorCheck) assertTrue(errorCheck(typedError));\n return typedError;\n }\n};\n\nexport const assertThrows = <TError extends Error>(\n fun: () => void,\n errorCheck?: (error: Error) => boolean,\n): TError => {\n try {\n fun();\n throw new AssertionError(\"Function didn't throw expected error\");\n } catch (error) {\n const typedError = error as TError;\n if (errorCheck) assertTrue(errorCheck(typedError));\n return typedError;\n }\n};\nexport const assertMatches = (\n actual: unknown,\n expected: unknown,\n message?: string,\n) => {\n if (!isSubset(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONParser.stringify(expected)}\\nis not subset of\\n${JSONParser.stringify(actual)}`,\n );\n};\n\nexport const assertDeepEqual = <T = unknown>(\n actual: T,\n expected: T,\n message?: string,\n) => {\n if (!deepEquals(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONParser.stringify(expected)}\\nis not equal to\\n${JSONParser.stringify(actual)}`,\n );\n};\n\nexport const assertNotDeepEqual = <T = unknown>(\n actual: T,\n expected: T,\n message?: string,\n) => {\n if (deepEquals(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONParser.stringify(expected)}\\nis equals to\\n${JSONParser.stringify(actual)}`,\n );\n};\n\nexport const assertThat = <T>(item: T) => {\n return {\n isEqualTo: (other: T) => assertTrue(deepEquals(item, other)),\n };\n};\n\nexport function assertFalse(\n condition: boolean,\n message?: string,\n): asserts condition is false {\n if (condition) throw new AssertionError(message ?? `Condition is false`);\n}\n\nexport function assertTrue(\n condition: boolean,\n message?: string,\n): asserts condition is true {\n if (!condition) throw new AssertionError(message ?? `Condition is false`);\n}\n\nexport function assertOk<T>(\n obj: T | null | undefined,\n message?: string,\n): asserts obj is T {\n if (!obj) throw new AssertionError(message ?? `Condition is not truthy`);\n}\n\nexport function assertEqual<T>(\n expected: T | null | undefined,\n actual: T | null | undefined,\n message?: string,\n): void {\n if (expected !== actual)\n throw new AssertionError(\n `${message ?? 'Objects are not equal'}:\\nExpected: ${JSONParser.stringify(expected)}\\nActual:${JSONParser.stringify(actual)}`,\n );\n}\n\nexport function assertNotEqual<T>(\n obj: T | null | undefined,\n other: T | null | undefined,\n message?: string,\n): void {\n if (obj === other)\n throw new AssertionError(\n message ?? `Objects are equal: ${JSONParser.stringify(obj)}`,\n );\n}\n\nexport function assertIsNotNull<T extends object | bigint>(\n result: T | null,\n): asserts result is T {\n assertNotEqual(result, null);\n assertOk(result);\n}\n\nexport function assertIsNull<T extends object>(\n result: T | null,\n): asserts result is null {\n assertEqual(result, null);\n}\n\ntype Call = {\n arguments: unknown[];\n result: unknown;\n target: unknown;\n this: unknown;\n};\n\nexport type ArgumentMatcher = (arg: unknown) => boolean;\n\nexport const argValue =\n <T>(value: T): ArgumentMatcher =>\n (arg) =>\n deepEquals(arg, value);\n\nexport const argMatches =\n <T>(matches: (arg: T) => boolean): ArgumentMatcher =>\n (arg) =>\n matches(arg as T);\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport type MockedFunction = Function & { mock?: { calls: Call[] } };\n\nexport function verifyThat(fn: MockedFunction) {\n return {\n calledTimes: (times: number) => {\n assertEqual(fn.mock?.calls?.length, times);\n },\n notCalled: () => {\n assertEqual(fn?.mock?.calls?.length, 0);\n },\n called: () => {\n assertTrue(\n fn.mock?.calls.length !== undefined && fn.mock.calls.length > 0,\n );\n },\n calledWith: (...args: unknown[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls.some((call) => deepEquals(call.arguments, args)),\n );\n },\n calledOnceWith: (...args: unknown[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length === 1 &&\n fn.mock.calls.some((call) => deepEquals(call.arguments, args)),\n );\n },\n calledWithArgumentMatching: (...matches: ArgumentMatcher[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined && fn.mock.calls.length >= 1,\n );\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls.some(\n (call) =>\n call.arguments &&\n call.arguments.length >= matches.length &&\n matches.every((match, index) => match(call.arguments[index])),\n ),\n );\n },\n notCalledWithArgumentMatching: (...matches: ArgumentMatcher[]) => {\n assertFalse(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls[0]!.arguments &&\n fn.mock.calls[0]!.arguments.length >= matches.length &&\n matches.every((match, index) =>\n match(fn.mock!.calls[0]!.arguments[index]),\n ),\n );\n },\n };\n}\n\nexport const assertThatArray = <T>(array: T[]) => {\n return {\n isEmpty: () => assertEqual(array.length, 0),\n isNotEmpty: () => assertNotEqual(array.length, 0),\n hasSize: (length: number) => assertEqual(array.length, length),\n containsElements: (...other: T[]) => {\n assertTrue(other.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyInAnyOrder: (...other: T[]) => {\n assertEqual(array.length, other.length);\n assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyInAnyOrderElementsOf: (other: T[]) => {\n assertEqual(array.length, other.length);\n assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyElementsOf: (other: T[]) => {\n assertEqual(array.length, other.length);\n for (let i = 0; i < array.length; i++) {\n assertTrue(deepEquals(array[i], other[i]));\n }\n },\n containsExactly: (elem: T) => {\n assertEqual(array.length, 1);\n assertTrue(deepEquals(array[0], elem));\n },\n contains: (elem: T) => {\n assertTrue(array.some((a) => deepEquals(a, elem)));\n },\n containsOnlyOnceElementsOf: (other: T[]) => {\n assertTrue(\n other\n .map((o) => array.filter((a) => deepEquals(a, o)).length)\n .filter((a) => a === 1).length === other.length,\n );\n },\n containsAnyOf: (...other: T[]) => {\n assertTrue(array.some((a) => other.some((o) => deepEquals(a, o))));\n },\n allMatch: (matches: (item: T) => boolean) => {\n assertTrue(array.every(matches));\n },\n anyMatches: (matches: (item: T) => boolean) => {\n assertTrue(array.some(matches));\n },\n allMatchAsync: async (\n matches: (item: T) => Promise<boolean>,\n ): Promise<void> => {\n for (const item of array) {\n assertTrue(await matches(item));\n }\n },\n };\n};\n","import { isErrorConstructor, type ErrorConstructor } from '../errors';\nimport { AssertionError, assertMatches, assertTrue } from './assertions';\n\ntype ErrorCheck<ErrorType> = (error: ErrorType) => boolean;\n\nexport type ThenThrows<ErrorType extends Error> =\n | (() => void)\n | ((errorConstructor: ErrorConstructor<ErrorType>) => void)\n | ((errorCheck: ErrorCheck<ErrorType>) => void)\n | ((\n errorConstructor: ErrorConstructor<ErrorType>,\n errorCheck?: ErrorCheck<ErrorType>,\n ) => void);\n\nexport type DeciderSpecfication<Command, Event> = (\n givenEvents: Event | Event[],\n) => {\n when: (command: Command) => {\n then: (expectedEvents: Event | Event[]) => void;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => void;\n };\n};\n\nexport const DeciderSpecification = {\n for: <Command, Event, State>(decider: {\n decide: (command: Command, state: State) => Event | Event[];\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n }): DeciderSpecfication<Command, Event> => {\n {\n return (givenEvents: Event | Event[]) => {\n return {\n when: (command: Command) => {\n const handle = () => {\n const existingEvents = Array.isArray(givenEvents)\n ? givenEvents\n : [givenEvents];\n\n const currentState = existingEvents.reduce<State>(\n decider.evolve,\n decider.initialState(),\n );\n\n return decider.decide(command, currentState);\n };\n\n return {\n then: (expectedEvents: Event | Event[]): void => {\n const resultEvents = handle();\n\n const resultEventsArray = Array.isArray(resultEvents)\n ? resultEvents\n : [resultEvents];\n\n const expectedEventsArray = Array.isArray(expectedEvents)\n ? expectedEvents\n : [expectedEvents];\n\n assertMatches(resultEventsArray, expectedEventsArray);\n },\n thenThrows: <ErrorType extends Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): void => {\n try {\n handle();\n throw new AssertionError('Handler did not fail as expected');\n } catch (error) {\n if (error instanceof AssertionError) throw error;\n\n if (args.length === 0) return;\n\n if (!isErrorConstructor(args[0])) {\n assertTrue(\n args[0](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n return;\n }\n\n assertTrue(\n error instanceof args[0],\n `Caught error is not an instance of the expected type: ${error?.toString()}`,\n );\n\n if (args[1]) {\n assertTrue(\n args[1](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n }\n }\n },\n };\n },\n };\n };\n }\n },\n};\n","import type {\n AggregateStreamOptions,\n AggregateStreamResult,\n AppendToStreamOptions,\n AppendToStreamResult,\n DefaultStreamVersionType,\n EventStore,\n ReadStreamOptions,\n ReadStreamResult,\n} from '../eventStore';\nimport { type Event } from '../typing';\n\nexport type TestEventStream<EventType extends Event = Event> = [\n string,\n EventType[],\n];\n\nexport const WrapEventStore = <StreamVersion = DefaultStreamVersionType>(\n eventStore: EventStore<StreamVersion>,\n): EventStore<StreamVersion> & {\n appendedEvents: Map<string, TestEventStream>;\n setup<EventType extends Event>(\n streamName: string,\n events: EventType[],\n ): Promise<AppendToStreamResult<StreamVersion>>;\n} => {\n const appendedEvents = new Map<string, TestEventStream>();\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType, StreamVersion>,\n ): Promise<AggregateStreamResult<State, StreamVersion> | null> {\n return eventStore.aggregateStream(streamName, options);\n },\n\n readStream<EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions<StreamVersion>,\n ): Promise<ReadStreamResult<EventType, StreamVersion>> {\n return eventStore.readStream(streamName, options);\n },\n\n appendToStream: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<StreamVersion>,\n ): Promise<AppendToStreamResult<StreamVersion>> => {\n const result = await eventStore.appendToStream(\n streamName,\n events,\n options,\n );\n\n const currentStream = appendedEvents.get(streamName) ?? [streamName, []];\n\n appendedEvents.set(streamName, [\n streamName,\n [...currentStream[1], ...events],\n ]);\n\n return result;\n },\n\n appendedEvents,\n\n setup: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n ): Promise<AppendToStreamResult<StreamVersion>> => {\n return eventStore.appendToStream(streamName, events);\n },\n };\n};\n","import {\n type NodePostgresClient,\n type NodePostgresTransaction,\n type SQL,\n type SQLExecutor,\n} from '@event-driven-io/dumbo';\nimport {\n projection,\n type CanHandle,\n type Event,\n type EventMetaDataOf,\n type ProjectionHandler,\n type ReadEvent,\n type ReadEventMetadata,\n type TypedProjectionDefinition,\n} from '@event-driven-io/emmett';\n\nexport type PostgreSQLProjectionHandlerContext = {\n connectionString: string;\n client: NodePostgresClient;\n execute: SQLExecutor;\n transaction: NodePostgresTransaction;\n};\n\nexport type PostgreSQLProjectionHandler<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n> = ProjectionHandler<\n EventType,\n EventMetaDataType,\n PostgreSQLProjectionHandlerContext\n>;\n\nexport type PostgreSQLProjectionDefinition<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n> = TypedProjectionDefinition<\n EventType,\n EventMetaDataType,\n PostgreSQLProjectionHandlerContext\n>;\n\nexport type ProjectionHandlerOptions<\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n> = {\n events: ReadEvent<EventType, EventMetaDataType>[];\n projections: PostgreSQLProjectionDefinition<EventType>[];\n connection: {\n connectionString: string;\n transaction: NodePostgresTransaction;\n };\n};\n\nexport const handleProjections = async <\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n>(\n options: ProjectionHandlerOptions<EventType, EventMetaDataType>,\n): Promise<void> => {\n const {\n projections: allProjections,\n events,\n connection: { transaction, connectionString },\n } = options;\n\n const eventTypes = events.map((e) => e.type);\n\n const projections = allProjections.filter((p) =>\n p.canHandle.some((type) => eventTypes.includes(type)),\n );\n\n const client = (await transaction.connection.open()) as NodePostgresClient;\n\n for (const projection of projections) {\n await projection.handle(events, {\n connectionString,\n client,\n transaction,\n execute: transaction.execute,\n });\n }\n};\n\nexport const postgreSQLProjection = <\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadata = EventMetaDataOf<EventType> & ReadEventMetadata,\n>(\n definition: PostgreSQLProjectionDefinition<EventType>,\n): PostgreSQLProjectionDefinition =>\n projection<\n EventType,\n EventMetaDataType,\n PostgreSQLProjectionHandlerContext,\n PostgreSQLProjectionDefinition<EventType>\n >(definition) as PostgreSQLProjectionDefinition;\n\nexport const postgreSQLRawBatchSQLProjection = <EventType extends Event>(\n handle: (\n events: EventType[],\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<SQL[]> | SQL[],\n ...canHandle: CanHandle<EventType>\n): PostgreSQLProjectionDefinition =>\n postgreSQLProjection<EventType>({\n canHandle,\n handle: async (events, context) => {\n const sqls: SQL[] = await handle(events, context);\n\n await context.execute.batchCommand(sqls);\n },\n });\n\nexport const postgreSQLRawSQLProjection = <EventType extends Event>(\n handle: (\n event: EventType,\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<SQL> | SQL,\n ...canHandle: CanHandle<EventType>\n): PostgreSQLProjectionDefinition =>\n postgreSQLRawBatchSQLProjection<EventType>(\n async (events, context) => {\n const sqls: SQL[] = [];\n\n for (const event of events) {\n sqls.push(await handle(event, context));\n }\n return sqls;\n },\n ...canHandle,\n );\n\nexport * from './pongo';\nexport * from './postgresProjectionSpec';\n","import { type Dumbo } from '@event-driven-io/dumbo';\nimport {\n assertDeepEqual,\n assertEqual,\n assertIsNotNull,\n assertThatArray,\n} from '@event-driven-io/emmett';\nimport {\n pongoClient,\n type PongoCollection,\n type PongoDocument,\n type PongoFilter,\n type WithId,\n} from '@event-driven-io/pongo';\nimport { type PostgreSQLProjectionAssert } from '..';\n\nexport type PongoAssertOptions = {\n inCollection: string;\n inDatabase?: string;\n};\n\nconst withCollection = (\n handle: (collection: PongoCollection<PongoDocument>) => Promise<void>,\n options: {\n pool: Dumbo;\n connectionString: string;\n } & PongoAssertOptions,\n) => {\n const { pool, connectionString, inDatabase, inCollection } = options;\n\n return pool.withConnection(async (connection) => {\n const pongo = pongoClient(connectionString, {\n connectionOptions: { connection },\n });\n try {\n const collection = pongo.db(inDatabase).collection(inCollection);\n\n return handle(collection);\n } finally {\n await pongo.close();\n }\n });\n};\n\nconst withoutIdAndVersion = <Doc extends PongoDocument | WithId<PongoDocument>>(\n doc: Doc,\n) => {\n const { _id, _version, ...without } = doc;\n\n return without;\n};\n\nconst assertDocumentsEqual = <\n Doc extends PongoDocument | WithId<PongoDocument>,\n>(\n actual: PongoDocument,\n expected: Doc,\n) => {\n if ('_id' in expected)\n assertEqual(\n expected._id,\n actual._id,\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Document ids are not matching! Expected: ${expected._id}, actual: ${actual._id}`,\n );\n\n return assertDeepEqual(\n withoutIdAndVersion(actual),\n withoutIdAndVersion(expected),\n );\n};\n\ntype FilterOrId<Doc extends PongoDocument | WithId<PongoDocument>> =\n | { withId: string }\n | {\n matchingFilter: PongoFilter<Doc>;\n };\n\nexport const documentExists =\n <Doc extends PongoDocument | WithId<PongoDocument>>(\n document: Doc,\n options: PongoAssertOptions & FilterOrId<Doc>,\n ): PostgreSQLProjectionAssert =>\n (assertOptions) =>\n withCollection(\n async (collection) => {\n const result = await collection.findOne(\n 'withId' in options\n ? { _id: options.withId }\n : options.matchingFilter,\n );\n\n assertIsNotNull(result);\n\n assertDocumentsEqual(result, document);\n },\n { ...options, ...assertOptions },\n );\n\nexport const documentsAreTheSame =\n <Doc extends PongoDocument | WithId<PongoDocument>>(\n documents: Doc[],\n options: PongoAssertOptions & FilterOrId<Doc>,\n ): PostgreSQLProjectionAssert =>\n (assertOptions) =>\n withCollection(\n async (collection) => {\n const result = await collection.find(\n 'withId' in options\n ? { _id: options.withId }\n : options.matchingFilter,\n );\n\n assertEqual(\n documents.length,\n result.length,\n 'Different Documents Count than expected',\n );\n\n for (let i = 0; i < documents.length; i++) {\n assertThatArray(result as Doc[]).contains(documents[i]!);\n }\n },\n { ...options, ...assertOptions },\n );\n\nexport const documentsMatchingHaveCount =\n <Doc extends PongoDocument | WithId<PongoDocument>>(\n expectedCount: number,\n options: PongoAssertOptions & FilterOrId<Doc>,\n ): PostgreSQLProjectionAssert =>\n (assertOptions) =>\n withCollection(\n async (collection) => {\n const result = await collection.find(\n 'withId' in options\n ? { _id: options.withId }\n : options.matchingFilter,\n );\n\n assertEqual(\n expectedCount,\n result.length,\n 'Different Documents Count than expected',\n );\n },\n { ...options, ...assertOptions },\n );\n\nexport const documentMatchingExists =\n <Doc extends PongoDocument | WithId<PongoDocument>>(\n options: PongoAssertOptions & FilterOrId<Doc>,\n ): PostgreSQLProjectionAssert =>\n (assertOptions) =>\n withCollection(\n async (collection) => {\n const result = await collection.find(\n 'withId' in options\n ? { _id: options.withId }\n : options.matchingFilter,\n );\n\n assertThatArray(result).isNotEmpty();\n },\n { ...options, ...assertOptions },\n );\n\nexport const documentDoesNotExist =\n <Doc extends PongoDocument | WithId<PongoDocument>>(\n options: PongoAssertOptions & FilterOrId<Doc>,\n ): PostgreSQLProjectionAssert =>\n (assertOptions) =>\n withCollection(\n async (collection) => {\n const result = await collection.findOne(\n 'withId' in options\n ? { _id: options.withId }\n : options.matchingFilter,\n );\n\n assertIsNotNull(result);\n },\n { ...options, ...assertOptions },\n );\n\nexport const expectPongoDocuments = {\n fromCollection: <Doc extends PongoDocument | WithId<PongoDocument>>(\n collectionName: string,\n ) => {\n return {\n withId: (id: string) => {\n return {\n toBeEqual: (document: Doc) =>\n documentExists(document, {\n withId: id,\n inCollection: collectionName,\n }),\n toExist: () =>\n documentMatchingExists({\n withId: id,\n inCollection: collectionName,\n }),\n notToExist: () =>\n documentDoesNotExist({\n withId: id,\n inCollection: collectionName,\n }),\n };\n },\n matching: <Doc extends PongoDocument | WithId<PongoDocument>>(\n filter: PongoFilter<Doc>,\n ) => {\n return {\n toBeTheSame: (documents: Doc[]) =>\n documentsAreTheSame<Doc>(documents, {\n matchingFilter: filter,\n inCollection: collectionName,\n }),\n toHaveCount: (expectedCount: number) =>\n documentsMatchingHaveCount(expectedCount, {\n matchingFilter: filter,\n inCollection: collectionName,\n }),\n toExist: () =>\n documentMatchingExists({\n matchingFilter: filter,\n inCollection: collectionName,\n }),\n notToExist: () =>\n documentDoesNotExist({\n matchingFilter: filter,\n inCollection: collectionName,\n }),\n };\n },\n };\n },\n};\n","import {\n type CanHandle,\n type Event,\n type EventMetaDataOf,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n} from '@event-driven-io/emmett';\nimport {\n pongoClient,\n type PongoClient,\n type PongoDocument,\n} from '@event-driven-io/pongo';\nimport {\n postgreSQLProjection,\n type PostgreSQLProjectionDefinition,\n type PostgreSQLProjectionHandlerContext,\n} from '..';\n\nexport type PongoProjectionHandlerContext =\n PostgreSQLProjectionHandlerContext & {\n pongo: PongoClient;\n };\n\nexport type PongoWithNotNullDocumentEvolve<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> =\n | ((\n document: Document,\n event: ReadEvent<EventType, EventMetaDataType>,\n ) => Document | null)\n | ((\n document: Document,\n event: ReadEvent<EventType>,\n ) => Promise<Document | null>);\n\nexport type PongoWithNullableDocumentEvolve<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> =\n | ((\n document: Document | null,\n event: ReadEvent<EventType, EventMetaDataType>,\n ) => Document | null)\n | ((\n document: Document | null,\n event: ReadEvent<EventType>,\n ) => Promise<Document | null>);\n\nexport type PongoDocumentEvolve<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> =\n | PongoWithNotNullDocumentEvolve<Document, EventType, EventMetaDataType>\n | PongoWithNullableDocumentEvolve<Document, EventType, EventMetaDataType>;\n\nexport type PongoProjectionOptions<\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> = {\n handle: (\n events: ReadEvent<EventType, EventMetaDataType>[],\n context: PongoProjectionHandlerContext,\n ) => Promise<void>;\n canHandle: CanHandle<EventType>;\n};\n\nexport const pongoProjection = <\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n>({\n handle,\n canHandle,\n}: PongoProjectionOptions<\n EventType,\n EventMetaDataType\n>): PostgreSQLProjectionDefinition =>\n postgreSQLProjection<EventType, EventMetaDataType>({\n canHandle,\n handle: async (events, context) => {\n const { connectionString, client } = context;\n const pongo = pongoClient(connectionString, {\n connectionOptions: { client },\n });\n await handle(events as ReadEvent<EventType, EventMetaDataType>[], {\n ...context,\n pongo,\n });\n },\n });\n\nexport type PongoMultiStreamProjectionOptions<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> = {\n canHandle: CanHandle<EventType>;\n\n collectionName: string;\n getDocumentId: (event: ReadEvent<EventType>) => string;\n} & (\n | {\n evolve: PongoWithNullableDocumentEvolve<\n Document,\n EventType,\n EventMetaDataType\n >;\n }\n | {\n evolve: PongoWithNotNullDocumentEvolve<\n Document,\n EventType,\n EventMetaDataType\n >;\n initialState: () => Document;\n }\n);\n\nexport const pongoMultiStreamProjection = <\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n>(\n options: PongoMultiStreamProjectionOptions<\n Document,\n EventType,\n EventMetaDataType\n >,\n): PostgreSQLProjectionDefinition => {\n const { collectionName, getDocumentId, canHandle } = options;\n\n return pongoProjection({\n handle: async (events, { pongo }) => {\n const collection = pongo.db().collection<Document>(collectionName);\n\n for (const event of events) {\n await collection.handle(getDocumentId(event), async (document) => {\n return 'initialState' in options\n ? await options.evolve(\n document ?? options.initialState(),\n event as ReadEvent<EventType, EventMetaDataType>,\n )\n : await options.evolve(\n document,\n event as ReadEvent<EventType, EventMetaDataType>,\n );\n });\n }\n },\n canHandle,\n });\n};\n\nexport type PongoSingleStreamProjectionOptions<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> = {\n canHandle: CanHandle<EventType>;\n\n collectionName: string;\n} & (\n | {\n evolve: PongoWithNullableDocumentEvolve<\n Document,\n EventType,\n EventMetaDataType\n >;\n }\n | {\n evolve: PongoWithNotNullDocumentEvolve<\n Document,\n EventType,\n EventMetaDataType\n >;\n initialState: () => Document;\n }\n);\n\nexport const pongoSingleStreamProjection = <\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n>(\n options: PongoSingleStreamProjectionOptions<\n Document,\n EventType,\n EventMetaDataType\n >,\n): PostgreSQLProjectionDefinition => {\n return pongoMultiStreamProjection<Document, EventType, EventMetaDataType>({\n ...options,\n getDocumentId: (event) => event.metadata.streamName,\n });\n};\n","import {\n dumbo,\n type Dumbo,\n type DumboOptions,\n type QueryResultRow,\n type SQL,\n} from '@event-driven-io/dumbo';\nimport {\n assertFails,\n AssertionError,\n assertThatArray,\n assertTrue,\n isErrorConstructor,\n type Event,\n type EventMetaDataOf,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n type ThenThrows,\n} from '@event-driven-io/emmett';\nimport { v4 as uuid } from 'uuid';\nimport { handleProjections, type PostgreSQLProjectionDefinition } from '.';\n\nexport type PostgreSQLProjectionSpecEvent<\n EventType extends Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n> = EventType & {\n metadata?: Partial<EventMetaDataType>;\n};\n\nexport type PostgreSQLProjectionSpecWhenOptions = { numberOfTimes: number };\n\nexport type PostgreSQLProjectionSpec<EventType extends Event> = (\n givenEvents: PostgreSQLProjectionSpecEvent<EventType>[],\n) => {\n when: (\n events: PostgreSQLProjectionSpecEvent<EventType>[],\n options?: PostgreSQLProjectionSpecWhenOptions,\n ) => {\n then: (\n assert: PostgreSQLProjectionAssert,\n message?: string,\n ) => Promise<void>;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => Promise<void>;\n };\n};\n\nexport type PostgreSQLProjectionAssert = (options: {\n pool: Dumbo;\n connectionString: string;\n}) => Promise<void | boolean>;\n\nexport type PostgreSQLProjectionSpecOptions = {\n projection: PostgreSQLProjectionDefinition;\n} & DumboOptions;\n\nexport const PostgreSQLProjectionSpec = {\n for: <EventType extends Event>(\n options: PostgreSQLProjectionSpecOptions,\n ): PostgreSQLProjectionSpec<EventType> => {\n {\n const { projection, ...dumoOptions } = options;\n const { connectionString } = dumoOptions;\n\n return (givenEvents: PostgreSQLProjectionSpecEvent<EventType>[]) => {\n return {\n when: (\n events: PostgreSQLProjectionSpecEvent<EventType>[],\n options?: PostgreSQLProjectionSpecWhenOptions,\n ) => {\n const allEvents: ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >[] = [];\n\n const run = async (pool: Dumbo) => {\n let globalPosition = 0n;\n const numberOfTimes = options?.numberOfTimes ?? 1;\n\n for (const event of [\n ...givenEvents,\n ...Array.from({ length: numberOfTimes }).flatMap(() => events),\n ]) {\n allEvents.push({\n ...event,\n metadata: {\n ...{\n globalPosition: ++globalPosition,\n streamPosition: globalPosition,\n streamName: `test-${uuid()}`,\n eventId: uuid(),\n },\n ...(event.metadata ?? {}),\n },\n });\n }\n\n await pool.withTransaction((transaction) =>\n handleProjections({\n events: allEvents,\n projections: [projection],\n connection: {\n connectionString,\n transaction,\n },\n }),\n );\n };\n\n return {\n then: async (\n assert: PostgreSQLProjectionAssert,\n message?: string,\n ): Promise<void> => {\n const pool = dumbo(dumoOptions);\n try {\n await run(pool);\n\n const succeeded = await assert({ pool, connectionString });\n\n if (succeeded !== undefined && succeeded === false)\n assertFails(\n message ??\n \"Projection specification didn't match the criteria\",\n );\n } finally {\n await pool.close();\n }\n },\n thenThrows: async <ErrorType extends Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): Promise<void> => {\n const pool = dumbo(dumoOptions);\n try {\n await run(pool);\n throw new AssertionError('Handler did not fail as expected');\n } catch (error) {\n if (error instanceof AssertionError) throw error;\n\n if (args.length === 0) return;\n\n if (!isErrorConstructor(args[0])) {\n assertTrue(\n args[0](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n return;\n }\n\n assertTrue(\n error instanceof args[0],\n `Caught error is not an instance of the expected type: ${error?.toString()}`,\n );\n\n if (args[1]) {\n assertTrue(\n args[1](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n }\n } finally {\n await pool.close();\n }\n },\n };\n },\n };\n };\n }\n },\n};\n\nexport const eventInStream = <\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n>(\n streamName: string,\n event: PostgreSQLProjectionSpecEvent<EventType, EventMetaDataType>,\n): PostgreSQLProjectionSpecEvent<EventType, EventMetaDataType> => {\n return {\n ...event,\n metadata: {\n ...(event.metadata ?? {}),\n streamName: event.metadata?.streamName ?? streamName,\n } as Partial<EventMetaDataType>,\n };\n};\n\nexport const eventsInStream = <\n EventType extends Event = Event,\n EventMetaDataType extends EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition = EventMetaDataOf<EventType> &\n ReadEventMetadataWithGlobalPosition,\n>(\n streamName: string,\n events: PostgreSQLProjectionSpecEvent<EventType, EventMetaDataType>[],\n): PostgreSQLProjectionSpecEvent<EventType, EventMetaDataType>[] => {\n return events.map((e) => eventInStream(streamName, e));\n};\n\nexport const newEventsInStream = eventsInStream;\n\nexport const assertSQLQueryResultMatches =\n <T extends QueryResultRow>(sql: SQL, rows: T[]): PostgreSQLProjectionAssert =>\n async ({ pool: { execute } }) => {\n const result = await execute.query<T>(sql);\n\n assertThatArray(rows).containsExactlyInAnyOrder(...result.rows);\n };\n\nexport const expectSQL = {\n query: (sql: SQL) => ({\n resultRows: {\n toBeTheSame: <T extends QueryResultRow>(rows: T[]) =>\n assertSQLQueryResultMatches(sql, rows),\n },\n }),\n};\n","import { type NodePostgresPool, type SQL } from '@event-driven-io/dumbo';\nimport { appendEventsSQL } from './appendToStream';\nimport {\n addDefaultPartition,\n addEventsPartitions,\n addModuleForAllTenantsSQL,\n addModuleSQL,\n addTablePartitions,\n addTenantForAllModulesSQL,\n addTenantSQL,\n eventsTableSQL,\n sanitizeNameSQL,\n streamsTableSQL,\n subscriptionsTableSQL,\n} from './tables';\n\nexport * from './appendToStream';\nexport * from './readStream';\nexport * from './tables';\nexport * from './typing';\n\nexport const schemaSQL: SQL[] = [\n streamsTableSQL,\n eventsTableSQL,\n subscriptionsTableSQL,\n sanitizeNameSQL,\n addTablePartitions,\n addEventsPartitions,\n addModuleSQL,\n addTenantSQL,\n addModuleForAllTenantsSQL,\n addTenantForAllModulesSQL,\n appendEventsSQL,\n addDefaultPartition,\n];\n\nexport const createEventStoreSchema = async (\n pool: NodePostgresPool,\n): Promise<void> => {\n await pool.withTransaction(({ execute }) => execute.batchCommand(schemaSQL));\n};\n","import {\n rawSql,\n single,\n sql,\n type NodePostgresPool,\n type NodePostgresTransaction,\n type SQLExecutor,\n} from '@event-driven-io/dumbo';\nimport {\n JSONParser,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AppendToStreamOptions,\n type Event,\n type ExpectedStreamVersion,\n type ReadEvent,\n} from '@event-driven-io/emmett';\nimport { v4 as uuid } from 'uuid';\nimport { defaultTag, eventsTable, streamsTable } from './typing';\n\nexport const appendEventsSQL = rawSql(\n `CREATE OR REPLACE FUNCTION emt_append_event(\n v_event_ids text[],\n v_events_data jsonb[],\n v_events_metadata jsonb[],\n v_event_schema_versions text[],\n v_event_types text[],\n v_stream_id text,\n v_stream_type text,\n v_expected_stream_position bigint DEFAULT NULL,\n v_partition text DEFAULT emt_sanitize_name('default_partition')\n ) RETURNS TABLE (\n success boolean,\n next_stream_position bigint,\n last_global_position bigint,\n transaction_id xid8\n ) LANGUAGE plpgsql\n AS $$\n DECLARE\n v_next_stream_position bigint;\n v_position bigint;\n v_updated_rows int;\n v_transaction_id xid8;\n v_last_global_position bigint;\n BEGIN\n IF v_expected_stream_position IS NULL THEN\n SELECT COALESCE(max(stream_position), 0) INTO v_expected_stream_position\n FROM ${streamsTable.name}\n WHERE stream_id = v_stream_id AND partition = v_partition;\n END IF;\n\n v_next_stream_position := v_expected_stream_position + array_upper(v_events_data, 1);\n v_transaction_id := pg_current_xact_id();\n\n WITH ev AS (\n SELECT row_number() OVER () + v_expected_stream_position AS stream_position, \n event_data, \n event_metadata, \n schema_version, \n event_id, \n event_type\n FROM (\n SELECT *\n FROM \n unnest(v_event_ids, v_events_data, v_events_metadata, v_event_schema_versions, v_event_types) \n AS event(event_id, event_data, event_metadata, schema_version, event_type)\n ) AS event\n ),\n all_events_insert AS (\n INSERT INTO ${eventsTable.name}\n (stream_id, stream_position, partition, event_data, event_metadata, event_schema_version, event_type, event_id, transaction_id)\n SELECT \n v_stream_id, ev.stream_position, v_partition, ev.event_data, ev.event_metadata, ev.schema_version, ev.event_type, ev.event_id, v_transaction_id\n FROM ev\n RETURNING global_position\n )\n SELECT \n max(global_position) INTO v_last_global_position \n FROM \n all_events_insert;\n\n\n IF v_expected_stream_position = 0 THEN\n INSERT INTO ${streamsTable.name}\n (stream_id, stream_position, partition, stream_type, stream_metadata, is_archived)\n VALUES\n (v_stream_id, v_next_stream_position, v_partition, v_stream_type, '{}', FALSE);\n ELSE\n UPDATE ${streamsTable.name} as s \n SET stream_position = v_next_stream_position\n WHERE stream_id = v_stream_id AND stream_position = v_expected_stream_position AND partition = v_partition AND is_archived = FALSE;\n\n get diagnostics v_updated_rows = row_count;\n\n IF v_updated_rows = 0 THEN\n RETURN QUERY SELECT FALSE, NULL::bigint, NULL::bigint, NULL::xid8;\n RETURN;\n END IF;\n END IF;\n\n RETURN QUERY SELECT TRUE, v_next_stream_position, v_last_global_position, v_transaction_id;\n END;\n $$;\n `,\n);\n\ntype AppendEventResult =\n | {\n success: true;\n nextStreamPosition: bigint;\n lastGlobalPosition: bigint;\n transactionId: string;\n }\n | { success: false };\n\nexport type AppendToStreamPreCommitHook = (\n events: ReadEvent[],\n context: {\n transaction: NodePostgresTransaction;\n },\n) => Promise<void>;\n\nexport const appendToStream = (\n pool: NodePostgresPool,\n streamName: string,\n streamType: string,\n events: Event[],\n options?: AppendToStreamOptions & {\n partition?: string;\n preCommitHook?: AppendToStreamPreCommitHook;\n },\n): Promise<AppendEventResult> =>\n pool.withTransaction<AppendEventResult>(async (transaction) => {\n const { execute } = transaction;\n\n if (events.length === 0)\n return { success: false, result: { success: false } };\n\n let appendResult: AppendEventSqlResult;\n\n try {\n const expectedStreamVersion = toExpectedVersion(\n options?.expectedStreamVersion,\n );\n\n const eventsToAppend: ReadEvent[] = events.map((e, i) => ({\n ...e,\n metadata: {\n streamName,\n eventId: uuid(),\n streamPosition: BigInt(i),\n ...e.metadata,\n },\n }));\n\n // TODO: return global positions from append raw and other generated data\n appendResult = await appendEventsRaw(\n execute,\n streamName,\n streamType,\n eventsToAppend,\n {\n expectedStreamVersion,\n },\n );\n\n if (options?.preCommitHook)\n await options.preCommitHook(eventsToAppend, { transaction });\n } catch (error) {\n if (!isOptimisticConcurrencyError(error)) throw error;\n\n appendResult = {\n success: false,\n last_global_position: null,\n next_stream_position: null,\n transaction_id: null,\n };\n }\n\n const {\n success,\n next_stream_position,\n last_global_position,\n transaction_id,\n } = appendResult;\n\n return {\n success,\n result:\n success &&\n next_stream_position &&\n last_global_position &&\n transaction_id\n ? {\n success: true,\n nextStreamPosition: BigInt(next_stream_position),\n lastGlobalPosition: BigInt(last_global_position),\n transactionId: transaction_id,\n }\n : { success: false },\n };\n });\n\nconst toExpectedVersion = (\n expected: ExpectedStreamVersion | undefined,\n): bigint | null => {\n if (expected === undefined) return null;\n\n if (expected === NO_CONCURRENCY_CHECK) return null;\n\n // TODO: this needs to be fixed\n if (expected == STREAM_DOES_NOT_EXIST) return null;\n\n // TODO: this needs to be fixed\n if (expected == STREAM_EXISTS) return null;\n\n return expected as bigint;\n};\n\nconst isOptimisticConcurrencyError = (error: unknown): boolean =>\n error instanceof Error && 'code' in error && error.code === '23505';\n\ntype AppendEventSqlResult = {\n success: boolean;\n next_stream_position: string | null;\n last_global_position: string | null;\n transaction_id: string | null | undefined;\n};\n\nconst appendEventsRaw = (\n execute: SQLExecutor,\n streamId: string,\n streamType: string,\n events: ReadEvent[],\n options?: {\n expectedStreamVersion: bigint | null;\n partition?: string;\n },\n): Promise<AppendEventSqlResult> =>\n single(\n execute.command<AppendEventSqlResult>(\n sql(\n `SELECT * FROM emt_append_event(\n ARRAY[%s]::text[],\n ARRAY[%s]::jsonb[],\n ARRAY[%s]::jsonb[],\n ARRAY[%s]::text[],\n ARRAY[%s]::text[],\n %L::text,\n %L::text,\n %s::bigint,\n %L::text\n )`,\n events.map((e) => sql('%L', e.metadata.eventId)).join(','),\n events.map((e) => sql('%L', JSONParser.stringify(e.data))).join(','),\n events\n .map((e) => sql('%L', JSONParser.stringify(e.metadata ?? {})))\n .join(','),\n events.map(() => `'1'`).join(','),\n events.map((e) => sql('%L', e.type)).join(','),\n streamId,\n streamType,\n options?.expectedStreamVersion ?? 'NULL',\n options?.partition ?? defaultTag,\n ),\n ),\n );\n","export const emmettPrefix = 'emt';\n\nexport const globalTag = 'global';\nexport const defaultTag = 'emt:default';\n\nexport const globalNames = {\n module: `${emmettPrefix}:module:${globalTag}`,\n tenant: `${emmettPrefix}:tenant:${globalTag}`,\n};\n\nconst columns = {\n partition: {\n name: 'partition',\n },\n isArchived: { name: 'is_archived' },\n};\n\nexport const streamsTable = {\n name: `${emmettPrefix}_streams`,\n columns: {\n partition: columns.partition,\n isArchived: columns.isArchived,\n },\n};\n\nexport const eventsTable = {\n name: `${emmettPrefix}_events`,\n columns: {\n partition: columns.partition,\n isArchived: columns.isArchived,\n },\n};\n","import { rawSql } from '@event-driven-io/dumbo';\nimport { defaultTag, eventsTable, globalTag, streamsTable } from './typing';\n\nexport const streamsTableSQL = rawSql(\n `CREATE TABLE IF NOT EXISTS ${streamsTable.name}(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${globalTag}__${globalTag}',\n stream_type TEXT NOT NULL,\n stream_metadata JSONB NOT NULL,\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n PRIMARY KEY (stream_id, stream_position, partition, is_archived),\n UNIQUE (stream_id, partition, is_archived)\n ) PARTITION BY LIST (partition);`,\n);\n\nexport const eventsTableSQL = rawSql(\n `\n CREATE SEQUENCE IF NOT EXISTS emt_global_event_position;\n\n CREATE TABLE IF NOT EXISTS ${eventsTable.name}(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${globalTag}',\n event_data JSONB NOT NULL,\n event_metadata JSONB NOT NULL,\n event_schema_version TEXT NOT NULL,\n event_type TEXT NOT NULL,\n event_id TEXT NOT NULL,\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n global_position BIGINT DEFAULT nextval('emt_global_event_position'),\n transaction_id XID8 NOT NULL,\n created TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (stream_id, stream_position, partition, is_archived)\n ) PARTITION BY LIST (partition);`,\n);\n\nexport const subscriptionsTableSQL = rawSql(\n `\n CREATE TABLE IF NOT EXISTS emt_subscriptions(\n subscription_id TEXT NOT NULL PRIMARY KEY,\n version INT NOT NULL DEFAULT 1,\n module TEXT NULL,\n tenant TEXT NULL,\n last_processed_position BIGINT NOT NULL,\n last_processed_transaction_id BIGINT NOT NULL\n );\n`,\n);\n\nexport const sanitizeNameSQL = rawSql(\n `CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $$\n BEGIN\n RETURN REGEXP_REPLACE(input_name, '[^a-zA-Z0-9_]', '_', 'g');\n END;\n $$ LANGUAGE plpgsql;`,\n);\n\nexport const addTablePartitions = rawSql(\n `\n CREATE OR REPLACE FUNCTION emt_add_table_partition(tableName TEXT, partition_name TEXT) RETURNS void AS $$\n DECLARE\n v_main_partiton_name TEXT;\n v_active_partiton_name TEXT;\n v_archived_partiton_name TEXT;\n BEGIN \n v_main_partiton_name := emt_sanitize_name(tableName || '_' || partition_name);\n v_active_partiton_name := emt_sanitize_name(v_main_partiton_name || '_active');\n v_archived_partiton_name := emt_sanitize_name(v_main_partiton_name || '_archived');\n\n -- create default events partition\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L) PARTITION BY LIST (is_archived);',\n v_main_partiton_name, tableName, partition_name\n );\n\n -- create default streams partition\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L) PARTITION BY LIST (is_archived);',\n v_main_partiton_name, tableName, partition_name\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (FALSE);',\n v_active_partiton_name, v_main_partiton_name\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (TRUE);',\n v_archived_partiton_name, v_main_partiton_name\n );\n END;\n $$ LANGUAGE plpgsql;`,\n);\n\nexport const addEventsPartitions = rawSql(\n `\n CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $$\n BEGIN \n PERFORM emt_add_table_partition('${eventsTable.name}', partition_name);\n PERFORM emt_add_table_partition('${streamsTable.name}', partition_name);\n END;\n $$ LANGUAGE plpgsql;`,\n);\n\nexport const addModuleSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_module(new_module TEXT) RETURNS void AS $$\n BEGIN\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}'), '${eventsTable.name}', new_module, '${globalTag}'\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}' || '_active'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}' || '_archived'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}'), '${streamsTable.name}', new_module, '${globalTag}'\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}' || '_active'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}' || '_archived'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || '${globalTag}')\n );\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addTenantSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_tenant(new_module TEXT, new_tenant TEXT) RETURNS void AS $$\n BEGIN\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant), '${eventsTable.name}', new_module, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || new_tenant)\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant), '${streamsTable.name}', new_module, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || new_tenant)\n );\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addModuleForAllTenantsSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_module_for_all_tenants(new_module TEXT) RETURNS void AS $$\n DECLARE\n tenant_record RECORD;\n BEGIN\n PERFORM add_module(new_module);\n \n FOR tenant_record IN SELECT DISTINCT tenant FROM ${eventsTable.name}\n LOOP\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant), '${eventsTable.name}', new_module, tenant_record.tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${eventsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant), '${streamsTable.name}', new_module, tenant_record.tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${streamsTable.name}_' || new_module || '__' || tenant_record.tenant)\n );\n END LOOP;\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addTenantForAllModulesSQL = rawSql(\n `\n CREATE OR REPLACE FUNCTION add_tenant_for_all_modules(new_tenant TEXT) RETURNS void AS $$\n DECLARE\n module_record RECORD;\n BEGIN\n FOR module_record IN SELECT DISTINCT partitionname FROM pg_partman.part_config WHERE parent_table = '${eventsTable.name}'\n LOOP\n -- For ${eventsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant), '${eventsTable.name}', module_record.partitionname, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${eventsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n \n -- For ${streamsTable.name} table\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',\n emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant), '${streamsTable.name}', module_record.partitionname, new_tenant\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I\n FOR VALUES IN (FALSE);',\n emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I\n FOR VALUES IN (TRUE);',\n emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${streamsTable.name}_' || module_record.partitionname || '__' || new_tenant)\n );\n END LOOP;\n END;\n $$ LANGUAGE plpgsql;\n `,\n);\n\nexport const addDefaultPartition = rawSql(\n `SELECT emt_add_partition('${defaultTag}');`,\n);\n","import { mapRows, sql, type SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n event,\n type DefaultStreamVersionType,\n type Event,\n type EventDataOf,\n type EventMetaDataOf,\n type EventTypeOf,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport { defaultTag, eventsTable } from './typing';\n\ntype ReadStreamSqlResult<EventType extends Event> = {\n stream_position: string;\n event_data: EventDataOf<EventType>;\n event_metadata: EventMetaDataOf<EventType>;\n event_schema_version: string;\n event_type: EventTypeOf<EventType>;\n event_id: string;\n global_position: string;\n transaction_id: string;\n created: string;\n};\n\nexport const readStream = async <EventType extends Event>(\n execute: SQLExecutor,\n streamId: string,\n options?: ReadStreamOptions & { partition?: string },\n): Promise<\n ReadStreamResult<\n EventType,\n DefaultStreamVersionType,\n ReadEventMetadataWithGlobalPosition\n >\n> => {\n const fromCondition: string =\n options && 'from' in options\n ? `AND stream_position >= ${options.from}`\n : '';\n\n const to = Number(\n options && 'to' in options\n ? options.to\n : options && 'maxCount' in options && options.maxCount\n ? options.from + options.maxCount\n : NaN,\n );\n\n const toCondition = !isNaN(to) ? `AND stream_position <= ${to}` : '';\n\n const events: ReadEvent<EventType, ReadEventMetadataWithGlobalPosition>[] =\n await mapRows(\n execute.query<ReadStreamSqlResult<EventType>>(\n sql(\n `SELECT stream_id, stream_position, global_position, event_data, event_metadata, event_schema_version, event_type, event_id\n FROM ${eventsTable.name}\n WHERE stream_id = %L AND partition = %L AND is_archived = FALSE ${fromCondition} ${toCondition}`,\n streamId,\n options?.partition ?? defaultTag,\n ),\n ),\n (row) => {\n const rawEvent = event<EventType>(\n row.event_type,\n row.event_data,\n row.event_metadata,\n ) as EventType;\n\n return {\n ...rawEvent,\n metadata: {\n ...rawEvent.metadata,\n eventId: row.event_id,\n streamName: streamId,\n streamPosition: BigInt(row.stream_position),\n globalPosition: BigInt(row.global_position),\n },\n };\n },\n );\n\n return events.length > 0\n ? {\n currentStreamVersion:\n events[events.length - 1]!.metadata.streamPosition,\n events,\n }\n : null;\n};\n"],"mappings":"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","names":["dumbo","ValidationErrors","isNumber","val","isString","isErrorConstructor","expect","EmmettError","_EmmettError","options","errorCode","isNumber","message","isString","ConcurrencyError","_ConcurrencyError","current","expected","randomUUID","retry","TransformStream","STREAM_EXISTS","STREAM_DOES_NOT_EXIST","NO_CONCURRENCY_CHECK","ExpectedVersionConflictError","_ExpectedVersionConflictError","ConcurrencyError","current","expected","event","type","data","metadata","projection","definition","ParseError","text","JSONParser","value","options","_","v","parsed","deepEquals","left","right","isEquatable","val","index","keys1","keys2","key","AssertionError","message","assertFails","message","AssertionError","assertDeepEqual","actual","expected","message","deepEquals","AssertionError","JSONParser","assertTrue","condition","message","AssertionError","assertOk","obj","assertEqual","expected","actual","JSONParser","assertNotEqual","other","assertIsNotNull","result","assertThatArray","array","assertEqual","assertNotEqual","length","other","assertTrue","ts","o","deepEquals","i","elem","a","matches","item","pongoClient","withCollection","handle","options","pool","connectionString","inDatabase","inCollection","connection","pongo","pongoClient","collection","withoutIdAndVersion","doc","_id","_version","without","assertDocumentsEqual","actual","expected","l","an","documentExists","document","assertOptions","result","mn","documentsAreTheSame","documents","i","yn","documentsMatchingHaveCount","expectedCount","documentMatchingExists","documentDoesNotExist","expectPongoDocuments","collectionName","id","filter","pongoClient","pongoProjection","handle","canHandle","postgreSQLProjection","events","context","connectionString","client","pongo","pongoClient","pongoMultiStreamProjection","options","collectionName","getDocumentId","collection","event","document","pongoSingleStreamProjection","dumbo","uuid","PostgreSQLProjectionSpec","options","projection","dumoOptions","connectionString","givenEvents","events","allEvents","run","pool","globalPosition","numberOfTimes","event","uuid","transaction","handleProjections","assert","message","dumbo","succeeded","nn","args","p","error","C","s","eventInStream","streamName","eventsInStream","e","newEventsInStream","assertSQLQueryResultMatches","sql","rows","execute","result","yn","expectSQL","handleProjections","options","allProjections","events","transaction","connectionString","eventTypes","e","projections","p","type","client","projection","postgreSQLProjection","definition","at","postgreSQLRawBatchSQLProjection","handle","canHandle","context","sqls","postgreSQLRawSQLProjection","event","rawSql","single","sql","uuid","emmettPrefix","globalTag","defaultTag","globalNames","columns","streamsTable","eventsTable","appendEventsSQL","rawSql","streamsTable","eventsTable","appendToStream","pool","streamName","streamType","events","options","transaction","execute","appendResult","expectedStreamVersion","toExpectedVersion","eventsToAppend","e","i","uuid","appendEventsRaw","error","isOptimisticConcurrencyError","success","next_stream_position","last_global_position","transaction_id","expected","f","O","U","streamId","single","sql","u","defaultTag","rawSql","streamsTableSQL","rawSql","streamsTable","globalTag","eventsTableSQL","eventsTable","subscriptionsTableSQL","sanitizeNameSQL","addTablePartitions","addEventsPartitions","addModuleSQL","addTenantSQL","addModuleForAllTenantsSQL","addTenantForAllModulesSQL","addDefaultPartition","defaultTag","mapRows","sql","readStream","execute","streamId","options","fromCondition","to","toCondition","events","mapRows","sql","eventsTable","defaultTag","row","rawEvent","Ne","schemaSQL","streamsTableSQL","eventsTableSQL","subscriptionsTableSQL","sanitizeNameSQL","addTablePartitions","addEventsPartitions","addModuleSQL","addTenantSQL","addModuleForAllTenantsSQL","addTenantForAllModulesSQL","appendEventsSQL","addDefaultPartition","createEventStoreSchema","pool","execute","defaultPostgreSQLOptions","getPostgreSQLEventStore","connectionString","options","poolOptions","pool","dumbo","migrateSchema","autoGenerateSchema","ensureSchemaExists","createEventStoreSchema","inlineProjections","type","projection","preCommitHook","events","transaction","handleProjections","schemaSQL","streamName","evolve","initialState","read","expectedStreamVersion","state","result","currentStreamVersion","assertExpectedVersionMatchesCurrent","event","readStream","firstPart","rest","streamType","appendResult","appendToStream","V","f","callback","connection","storeOptions","eventStore","matchesExpectedVersion","current","expected","O","U"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@event-driven-io/emmett-postgresql",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Emmett - PostgreSQL - Event Sourcing development made simple",
|
|
6
6
|
"scripts": {
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
],
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@testcontainers/postgresql": "^10.12.0",
|
|
73
|
-
"@event-driven-io/emmett-testcontainers": "0.19.
|
|
73
|
+
"@event-driven-io/emmett-testcontainers": "0.19.1"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"@event-driven-io/emmett": "0.19.
|
|
77
|
-
"@event-driven-io/pongo": "0.15.
|
|
76
|
+
"@event-driven-io/emmett": "0.19.1",
|
|
77
|
+
"@event-driven-io/pongo": "0.15.3"
|
|
78
78
|
}
|
|
79
79
|
}
|