@event-driven-io/emmett-postgresql 0.43.0-beta.14 → 0.43.0-beta.15

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["SQL","SQL","SQL","SQL","SQL","bigInt","EmmettError","SQL","JSONSerializer","SQL","pgDriver","pgDriver","AssertionError","SQL","NO_CONCURRENCY_CHECK","STREAM_DOES_NOT_EXIST","STREAM_EXISTS","DumboError","UniqueConstraintError","SQL","SQL","SQL","SQL","SQL","SQL","SQL","SQL","SQL","ExpectedVersionConflictError","NO_CONCURRENCY_CHECK","EmmettError","defaultProcessorVersion","defaultProcessorPartition","unknownTag","EmmettError","unknownTag"],"sources":["../src/eventStore/schema/typing.ts","../src/eventStore/schema/readLastMessageGlobalPosition.ts","../src/eventStore/schema/readMessagesBatch.ts","../src/eventStore/consumers/messageBatchProcessing/index.ts","../src/eventStore/schema/createFunctionIfDoesNotExist.ts","../src/eventStore/schema/projections/projectionsLocks.ts","../src/eventStore/projections/locks/tryAcquireProjectionLock.ts","../src/eventStore/projections/locks/postgreSQLProjectionLock.ts","../src/eventStore/schema/processors/processorsLocks.ts","../src/eventStore/projections/locks/tryAcquireProcessorLock.ts","../src/eventStore/projections/locks/postgreSQLProcessorLock.ts","../src/eventStore/schema/projections/registerProjection.ts","../src/eventStore/projections/management/projectionManagement.ts","../src/eventStore/projections/pongo/pongoProjections.ts","../src/eventStore/projections/pongo/pongoProjectionSpec.ts","../src/eventStore/projections/postgresProjectionSpec.ts","../src/eventStore/projections/postgreSQLProjection.ts","../src/eventStore/schema/appendToStream.ts","../src/eventStore/schema/migrations/0_38_7/0_38_7.migration.ts","../src/eventStore/schema/migrations/0_38_7/0_38_7.snapshot.ts","../src/eventStore/schema/migrations/0_42_0/0_42_0.migration.ts","../src/eventStore/schema/migrations/0_42_0/0_42_0.snapshot.ts","../src/eventStore/schema/storeProcessorCheckpoint.ts","../src/eventStore/schema/migrations/0_43_0/index.ts","../src/eventStore/schema/tables.ts","../src/eventStore/schema/readProcessorCheckpoint.ts","../src/eventStore/schema/readStream.ts","../src/eventStore/schema/streamExists.ts","../src/eventStore/schema/index.ts","../src/eventStore/schema/truncateTables.ts","../src/eventStore/postgreSQLEventStore.ts","../src/eventStore/consumers/postgreSQLProcessor.ts","../src/eventStore/consumers/postgreSQLEventStoreConsumer.ts","../src/eventStore/consumers/rebuildPostgreSQLProjections.ts"],"sourcesContent":["export const emmettPrefix = 'emt';\n\nexport const globalTag = 'global';\nexport const defaultTag = `${emmettPrefix}:default`;\nexport const unknownTag = `${emmettPrefix}:unknown`;\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 messagesTable = {\n name: `${emmettPrefix}_messages`,\n columns: {\n partition: columns.partition,\n isArchived: columns.isArchived,\n },\n};\n\nexport const processorsTable = {\n name: `${emmettPrefix}_processors`,\n};\n\nexport const projectionsTable = {\n name: `${emmettPrefix}_projections`,\n};\n","import { singleOrNull, SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport { defaultTag, messagesTable } from './typing';\n\ntype ReadLastMessageGlobalPositionSqlResult = {\n global_position: string;\n};\n\nexport type ReadLastMessageGlobalPositionResult = {\n currentGlobalPosition: bigint | null;\n};\n\nexport const readLastMessageGlobalPosition = async (\n execute: SQLExecutor,\n options?: { partition?: string },\n): Promise<ReadLastMessageGlobalPositionResult> => {\n const result = await singleOrNull(\n execute.query<ReadLastMessageGlobalPositionSqlResult>(\n SQL`SELECT global_position\n FROM ${SQL.identifier(messagesTable.name)}\n WHERE partition = ${options?.partition ?? defaultTag} AND is_archived = FALSE AND transaction_id < pg_snapshot_xmin(pg_current_snapshot())\n ORDER BY transaction_id DESC, global_position DESC\n LIMIT 1`,\n ),\n );\n\n return {\n currentGlobalPosition:\n result !== null ? BigInt(result.global_position) : null,\n };\n};\n","import { mapRows, SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n bigIntProcessorCheckpoint,\n type CombinedMessageMetadata,\n type Message,\n type MessageDataOf,\n type MessageMetaDataOf,\n type MessageTypeOf,\n type RecordedMessage,\n type RecordedMessageMetadata,\n type RecordedMessageMetadataWithGlobalPosition,\n} from '@event-driven-io/emmett';\nimport { defaultTag, messagesTable } from './typing';\n\ntype ReadMessagesBatchSqlResult<MessageType extends Message> = {\n stream_position: string;\n stream_id: string;\n message_data: MessageDataOf<MessageType>;\n message_metadata: MessageMetaDataOf<MessageType>;\n message_schema_version: string;\n message_type: MessageTypeOf<MessageType>;\n message_id: string;\n global_position: string;\n transaction_id: string;\n created: string;\n};\n\nexport type ReadMessagesBatchOptions =\n | {\n after: bigint;\n batchSize: number;\n }\n | {\n from: bigint;\n batchSize: number;\n }\n | { to: bigint; batchSize: number }\n | { from: bigint; to: bigint };\n\nexport type ReadMessagesBatchResult<\n MessageType extends Message,\n MessageMetadataType extends RecordedMessageMetadata = RecordedMessageMetadata,\n> = {\n currentGlobalPosition: bigint;\n messages: RecordedMessage<MessageType, MessageMetadataType>[];\n areMessagesLeft: boolean;\n};\n\nexport const readMessagesBatch = async <\n MessageType extends Message,\n RecordedMessageMetadataType extends\n RecordedMessageMetadataWithGlobalPosition =\n RecordedMessageMetadataWithGlobalPosition,\n>(\n execute: SQLExecutor,\n options: ReadMessagesBatchOptions & { partition?: string },\n): Promise<\n ReadMessagesBatchResult<MessageType, RecordedMessageMetadataType>\n> => {\n const from = 'from' in options ? options.from : undefined;\n const after = 'after' in options ? options.after : undefined;\n const batchSize =\n 'batchSize' in options ? options.batchSize : options.to - options.from;\n\n const fromCondition: SQL =\n from !== undefined\n ? SQL`AND global_position >= ${from}`\n : after !== undefined\n ? SQL`AND global_position > ${after}`\n : SQL.EMPTY;\n\n const toCondition: SQL =\n 'to' in options ? SQL`AND global_position <= ${options.to}` : SQL.EMPTY;\n\n const limitCondition: SQL =\n 'batchSize' in options ? SQL`LIMIT ${options.batchSize}` : SQL.EMPTY;\n\n const messages: RecordedMessage<MessageType, RecordedMessageMetadataType>[] =\n await mapRows(\n execute.query<ReadMessagesBatchSqlResult<MessageType>>(\n SQL`\n SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id\n FROM ${SQL.identifier(messagesTable.name)}\n WHERE partition = ${options?.partition ?? defaultTag} AND is_archived = FALSE AND transaction_id < pg_snapshot_xmin(pg_current_snapshot()) ${fromCondition} ${toCondition}\n ORDER BY transaction_id, global_position\n ${limitCondition}`,\n ),\n (row) => {\n const rawEvent = {\n type: row.message_type,\n data: row.message_data,\n metadata: row.message_metadata,\n } as unknown as MessageType;\n\n const metadata: RecordedMessageMetadataWithGlobalPosition = {\n ...('metadata' in rawEvent ? (rawEvent.metadata ?? {}) : {}),\n messageId: row.message_id,\n streamName: row.stream_id,\n streamPosition: BigInt(row.stream_position),\n globalPosition: BigInt(row.global_position),\n checkpoint: bigIntProcessorCheckpoint(BigInt(row.global_position)),\n };\n\n return {\n ...rawEvent,\n kind: 'Event',\n metadata: metadata as CombinedMessageMetadata<\n MessageType,\n RecordedMessageMetadataType\n >,\n };\n },\n );\n\n return messages.length > 0\n ? {\n currentGlobalPosition:\n messages[messages.length - 1]!.metadata.globalPosition,\n messages: messages,\n areMessagesLeft: messages.length === batchSize,\n }\n : {\n currentGlobalPosition:\n 'from' in options\n ? options.from\n : 'after' in options\n ? options.after\n : 0n,\n messages: [],\n areMessagesLeft: false,\n };\n};\n","import type { SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n parseBigIntProcessorCheckpoint,\n type AsyncAwaiter,\n type BatchRecordedMessageHandlerWithoutContext,\n type EmmettError,\n type Message,\n type ProcessorCheckpoint,\n type ReadEventMetadataWithGlobalPosition,\n} from '@event-driven-io/emmett';\nimport { readLastMessageGlobalPosition } from '../../schema/readLastMessageGlobalPosition';\nimport {\n readMessagesBatch,\n type ReadMessagesBatchOptions,\n} from '../../schema/readMessagesBatch';\n\nexport const DefaultPostgreSQLEventStoreProcessorBatchSize = 100;\nexport const DefaultPostgreSQLEventStoreProcessorPullingFrequencyInMs = 50;\n\nexport type PostgreSQLEventStoreMessagesBatchHandlerResult = void | {\n type: 'STOP';\n reason?: string;\n error?: EmmettError;\n};\n\nexport type PostgreSQLEventStoreMessageBatchPullerOptions<\n MessageType extends Message = Message,\n> = {\n executor: SQLExecutor;\n pullingFrequencyInMs: number;\n batchSize: number;\n eachBatch: BatchRecordedMessageHandlerWithoutContext<\n MessageType,\n ReadEventMetadataWithGlobalPosition\n >;\n stopWhen?: {\n noMessagesLeft?: boolean;\n };\n signal: AbortSignal;\n};\n\nexport type PostgreSQLEventStoreMessageBatchPullerStartFrom =\n | { lastCheckpoint: ProcessorCheckpoint }\n | 'BEGINNING'\n | 'END';\n\nexport type PostgreSQLEventStoreMessageBatchPullerStartOptions = {\n startFrom: PostgreSQLEventStoreMessageBatchPullerStartFrom;\n signal?: AbortSignal;\n started?: AsyncAwaiter<void>;\n};\n\nexport type PostgreSQLEventStoreMessageBatchPuller = {\n isRunning: boolean;\n start(\n options: PostgreSQLEventStoreMessageBatchPullerStartOptions,\n ): Promise<void>;\n stop(): Promise<void>;\n};\n\nexport const postgreSQLEventStoreMessageBatchPuller = <\n MessageType extends Message = Message,\n>({\n executor,\n batchSize,\n eachBatch,\n pullingFrequencyInMs,\n stopWhen,\n signal,\n}: PostgreSQLEventStoreMessageBatchPullerOptions<MessageType>): PostgreSQLEventStoreMessageBatchPuller => {\n let isRunning = false;\n\n let start: Promise<void>;\n\n const pullMessages = async (\n options: PostgreSQLEventStoreMessageBatchPullerStartOptions,\n ) => {\n let after: bigint;\n try {\n after =\n options.startFrom === 'BEGINNING'\n ? 0n\n : options.startFrom === 'END'\n ? ((await readLastMessageGlobalPosition(executor))\n .currentGlobalPosition ?? 0n)\n : parseBigIntProcessorCheckpoint(options.startFrom.lastCheckpoint);\n } catch (error) {\n options.started?.reject(error);\n throw error;\n }\n\n options.started?.resolve();\n\n const readMessagesOptions: ReadMessagesBatchOptions = {\n after,\n batchSize,\n };\n\n let waitTime = 100;\n\n while (isRunning && !signal?.aborted) {\n const { messages, currentGlobalPosition, areMessagesLeft } =\n await readMessagesBatch<MessageType>(executor, readMessagesOptions);\n\n if (messages.length > 0) {\n const result = await eachBatch(messages);\n\n if (result && result.type === 'STOP') {\n isRunning = false;\n break;\n }\n }\n\n readMessagesOptions.after = currentGlobalPosition;\n\n await new Promise((resolve) => setTimeout(resolve, waitTime));\n\n if (stopWhen?.noMessagesLeft === true && !areMessagesLeft) {\n isRunning = false;\n break;\n }\n\n if (!areMessagesLeft) {\n waitTime = Math.min(waitTime * 2, 1000);\n } else {\n waitTime = pullingFrequencyInMs;\n }\n }\n };\n\n return {\n get isRunning() {\n return isRunning;\n },\n start: (options) => {\n if (isRunning) return start;\n isRunning = true;\n\n start = (async () => {\n return pullMessages(options);\n })();\n\n return start;\n },\n stop: async () => {\n if (!isRunning) return;\n isRunning = false;\n await start;\n },\n };\n};\n\nexport const zipPostgreSQLEventStoreMessageBatchPullerStartFrom = (\n options: (PostgreSQLEventStoreMessageBatchPullerStartFrom | undefined)[],\n): PostgreSQLEventStoreMessageBatchPullerStartFrom => {\n if (\n options.length === 0 ||\n options.some((o) => o === undefined || o === 'BEGINNING')\n )\n return 'BEGINNING';\n\n if (options.every((o) => o === 'END')) return 'END';\n\n return options\n .filter((o) => o !== undefined && o !== 'BEGINNING' && o !== 'END')\n .sort((a, b) => (a > b ? 1 : -1))[0]!;\n};\n","import { SQL } from '@event-driven-io/dumbo';\n\nexport const createFunctionIfDoesNotExistSQL = (\n functionName: string,\n functionDefinition: SQL,\n) =>\n SQL`\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = '${SQL.plain(functionName)}') THEN\n ${functionDefinition}\nEND IF;\nEND $$;\n`;\n","import { SQL } from '@event-driven-io/dumbo';\nimport { createFunctionIfDoesNotExistSQL } from '../createFunctionIfDoesNotExist';\nimport { projectionsTable } from '../typing';\n\nexport const tryAcquireProjectionLockSQL = createFunctionIfDoesNotExistSQL(\n 'emt_try_acquire_projection_lock',\n SQL`\nCREATE OR REPLACE FUNCTION emt_try_acquire_projection_lock(\n p_lock_key BIGINT,\n p_partition TEXT,\n p_name TEXT,\n p_version INT\n)\nRETURNS TABLE (acquired BOOLEAN, is_active BOOLEAN)\nLANGUAGE plpgsql\nAS $emt_try_acquire_projection_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock_shared(p_lock_key) AS acquired\n ),\n status_check AS (\n SELECT status = 'active' AS is_active\n FROM ${SQL.plain(projectionsTable.name)}\n WHERE partition = p_partition AND name = p_name AND version = p_version\n )\n SELECT\n COALESCE((SELECT lc.acquired FROM lock_check lc), false),\n COALESCE((SELECT sc.is_active FROM status_check sc), true);\nEND;\n$emt_try_acquire_projection_lock$;\n`,\n);\n\ntype CallTryAcquireProjectionLockParams = {\n lockKey: string;\n partition: string;\n name: string;\n version: number;\n};\n\nexport const callTryAcquireProjectionLock = (\n params: CallTryAcquireProjectionLockParams,\n) =>\n SQL`SELECT * FROM emt_try_acquire_projection_lock(${params.lockKey}, ${params.partition}, ${params.name}, ${params.version});`;\n","import { single, type SQLExecutor } from '@event-driven-io/dumbo';\nimport { hashText, isBigint } from '@event-driven-io/emmett';\nimport { callTryAcquireProjectionLock } from '../../schema/projections/projectionsLocks';\n\nexport type TryAcquireProjectionLockOptions = {\n projectionName: string;\n partition: string;\n version: number;\n lockKey: string | bigint;\n};\n\nexport const tryAcquireProjectionLock = async (\n execute: SQLExecutor,\n {\n lockKey,\n projectionName,\n partition,\n version,\n }: TryAcquireProjectionLockOptions,\n): Promise<boolean> => {\n const lockKeyBigInt = isBigint(lockKey) ? lockKey : await hashText(lockKey);\n\n const { acquired, is_active } = await single(\n execute.query<{\n acquired: boolean;\n is_active: boolean;\n }>(\n callTryAcquireProjectionLock({\n lockKey: lockKeyBigInt.toString(),\n partition,\n name: projectionName,\n version,\n }),\n ),\n );\n\n return acquired === true && is_active === true;\n};\n","import type { SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n tryAcquireProjectionLock,\n type TryAcquireProjectionLockOptions,\n} from './tryAcquireProjectionLock';\n\nexport type PostgreSQLProjectionLockOptions = {\n projectionName: string;\n partition: string;\n version: number;\n lockKey?: string | bigint;\n};\n\nexport type PostgreSQLProjectionLockContext = {\n execute: SQLExecutor;\n};\n\nexport type PostgreSQLProjectionLock = {\n tryAcquire: (options: PostgreSQLProjectionLockContext) => Promise<boolean>;\n release: (options: PostgreSQLProjectionLockContext) => void;\n};\n\nexport const postgreSQLProjectionLock = (\n options: PostgreSQLProjectionLockOptions,\n): PostgreSQLProjectionLock => {\n let acquired = false;\n const lockKey = options.lockKey ?? toProjectionLockKey(options);\n\n return {\n tryAcquire: async (\n context: PostgreSQLProjectionLockContext,\n ): Promise<boolean> => {\n if (acquired) {\n return true;\n }\n\n acquired = await tryAcquireProjectionLock(context.execute, {\n ...options,\n lockKey,\n });\n\n return acquired;\n },\n\n release: (_context: PostgreSQLProjectionLockContext): void => {\n if (!acquired) return;\n\n acquired = false;\n },\n };\n};\n\nexport const toProjectionLockKey = ({\n projectionName,\n partition,\n version,\n}: Pick<\n TryAcquireProjectionLockOptions,\n 'projectionName' | 'partition' | 'version'\n>): string => `${partition}:${projectionName}:${version}`;\n","import { SQL } from '@event-driven-io/dumbo';\nimport { bigInt } from '@event-driven-io/emmett';\nimport { createFunctionIfDoesNotExistSQL } from '../createFunctionIfDoesNotExist';\nimport {\n defaultTag,\n processorsTable,\n projectionsTable,\n unknownTag,\n} from '../typing';\n\nexport const tryAcquireProcessorLockSQL = createFunctionIfDoesNotExistSQL(\n 'emt_try_acquire_processor_lock',\n SQL`\nCREATE OR REPLACE FUNCTION emt_try_acquire_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_version INT,\n p_partition TEXT DEFAULT '${SQL.plain(defaultTag)}',\n p_processor_instance_id TEXT DEFAULT '${SQL.plain(unknownTag)}',\n p_projection_name TEXT DEFAULT NULL,\n p_projection_type VARCHAR(1) DEFAULT NULL,\n p_projection_kind TEXT DEFAULT NULL,\n p_lock_timeout_seconds INT DEFAULT 300\n)\nRETURNS TABLE (acquired BOOLEAN, checkpoint TEXT)\nLANGUAGE plpgsql\nAS $emt_try_acquire_processor_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n ownership_check AS (\n INSERT INTO ${SQL.plain(processorsTable.name)} (\n processor_id,\n partition,\n version,\n processor_instance_id,\n status,\n last_processed_checkpoint,\n last_processed_transaction_id,\n created_at,\n last_updated\n )\n SELECT p_processor_id, p_partition, p_version, p_processor_instance_id, 'running', '${SQL.plain(bigInt.toNormalizedString(0n))}', '0'::xid8, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (processor_id, partition, version) DO UPDATE\n SET processor_instance_id = p_processor_instance_id,\n status = 'running',\n last_updated = now()\n WHERE ${SQL.plain(processorsTable.name)}.processor_instance_id = p_processor_instance_id\n OR ${SQL.plain(processorsTable.name)}.processor_instance_id = '${SQL.plain(unknownTag)}'\n OR ${SQL.plain(processorsTable.name)}.status = 'stopped'\n OR ${SQL.plain(processorsTable.name)}.last_updated < now() - (p_lock_timeout_seconds || ' seconds')::interval\n RETURNING last_processed_checkpoint\n ),\n projection_status AS (\n INSERT INTO ${SQL.plain(projectionsTable.name)} (\n name,\n partition,\n version,\n type,\n kind,\n status,\n definition\n )\n SELECT p_projection_name, p_partition, p_version, p_projection_type, p_projection_kind, 'async_processing', '{}'::jsonb\n WHERE p_projection_name IS NOT NULL\n AND (SELECT last_processed_checkpoint FROM ownership_check) IS NOT NULL\n ON CONFLICT (name, partition, version) DO UPDATE\n SET status = 'async_processing'\n RETURNING name\n )\n SELECT\n (SELECT COUNT(*) > 0 FROM ownership_check),\n (SELECT oc.last_processed_checkpoint FROM ownership_check oc);\nEND;\n$emt_try_acquire_processor_lock$;\n`,\n);\n\nexport const releaseProcessorLockSQL = createFunctionIfDoesNotExistSQL(\n 'emt_release_processor_lock',\n SQL`\nCREATE OR REPLACE FUNCTION emt_release_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_partition TEXT,\n p_version INT,\n p_processor_instance_id TEXT DEFAULT '${SQL.plain(unknownTag)}',\n p_projection_name TEXT DEFAULT NULL\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_release_processor_lock$\nDECLARE\n v_rows_updated INT;\nBEGIN\n IF p_projection_name IS NOT NULL THEN\n UPDATE ${SQL.plain(projectionsTable.name)}\n SET status = 'active',\n last_updated = now()\n WHERE partition = p_partition\n AND name = p_projection_name\n AND version = p_version;\n END IF;\n\n UPDATE ${SQL.plain(processorsTable.name)}\n SET status = 'stopped',\n processor_instance_id = '${SQL.plain(unknownTag)}',\n last_updated = now()\n WHERE processor_id = p_processor_id\n AND partition = p_partition\n AND version = p_version\n AND processor_instance_id = p_processor_instance_id;\n\n GET DIAGNOSTICS v_rows_updated = ROW_COUNT;\n\n PERFORM pg_advisory_unlock(p_lock_key);\n\n RETURN v_rows_updated > 0;\nEND;\n$emt_release_processor_lock$;\n`,\n);\n\ntype CallTryAcquireProcessorLockParams = {\n lockKey: string;\n processorId: string;\n version: number;\n partition: string;\n processorInstanceId: string;\n projectionName: string | null;\n projectionType: 'i' | 'a' | null;\n projectionKind: string | null;\n lockTimeoutSeconds: number;\n};\n\nexport const callTryAcquireProcessorLock = (\n params: CallTryAcquireProcessorLockParams,\n) =>\n SQL`\n SELECT * FROM emt_try_acquire_processor_lock(\n ${params.lockKey}, \n ${params.processorId}, \n ${params.version}, \n ${params.partition}, \n ${params.processorInstanceId}, \n ${params.projectionName}, \n ${params.projectionType}, \n ${params.projectionKind}, \n ${params.lockTimeoutSeconds}\n );\n `;\n\ntype CallReleaseProcessorLockParams = {\n lockKey: string;\n processorId: string;\n partition: string;\n version: number;\n processorInstanceId: string;\n projectionName: string | null;\n};\n\nexport const callReleaseProcessorLock = (\n params: CallReleaseProcessorLockParams,\n) =>\n SQL`SELECT emt_release_processor_lock(\n ${params.lockKey}, \n ${params.processorId}, \n ${params.partition}, \n ${params.version}, \n ${params.processorInstanceId}, \n ${params.projectionName}\n ) as result;`;\n","import { single, type SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n asyncRetry,\n hashText,\n isBigint,\n type ProjectionHandlingType,\n} from '@event-driven-io/emmett';\nimport {\n callReleaseProcessorLock,\n callTryAcquireProcessorLock,\n} from '../../schema/processors/processorsLocks';\nimport { DefaultPostgreSQLProcessorLockPolicy } from './postgreSQLProcessorLock';\n\nexport type TryAcquireProcessorLockOptions = {\n processorId: string;\n version: number;\n partition: string;\n processorInstanceId: string;\n projection?: {\n name: string;\n handlingType: ProjectionHandlingType;\n kind: string;\n version: number;\n };\n lockKey: string | bigint;\n lockTimeoutSeconds?: number;\n};\n\nexport type TryAcquireProcessorLockResult =\n | {\n acquired: true;\n checkpoint: string;\n }\n | { acquired: false };\n\nexport type LockAcquisitionPolicy =\n | { type: 'fail' }\n | { type: 'skip' }\n | {\n type: 'retry';\n retries: number;\n minTimeout?: number;\n maxTimeout?: number;\n };\n\nexport const PROCESSOR_LOCK_DEFAULT_TIMEOUT_SECONDS = 300;\n\nexport const tryAcquireProcessorLock = async (\n execute: SQLExecutor,\n options: TryAcquireProcessorLockOptions,\n): Promise<TryAcquireProcessorLockResult> => {\n const lockKeyBigInt = isBigint(options.lockKey)\n ? options.lockKey\n : await hashText(options.lockKey);\n\n const { acquired, checkpoint } = await single(\n execute.command<{ acquired: boolean; checkpoint: string | null }>(\n callTryAcquireProcessorLock({\n lockKey: lockKeyBigInt.toString(),\n processorId: options.processorId,\n version: options.version,\n partition: options.partition,\n processorInstanceId: options.processorInstanceId,\n projectionName: options.projection?.name ?? null,\n projectionType: options.projection?.handlingType\n ? options.projection.handlingType === 'inline'\n ? 'i'\n : 'a'\n : null,\n projectionKind: options.projection?.kind ?? null,\n lockTimeoutSeconds:\n options.lockTimeoutSeconds ?? PROCESSOR_LOCK_DEFAULT_TIMEOUT_SECONDS,\n }),\n ),\n );\n\n return acquired\n ? { acquired: true, checkpoint: checkpoint! }\n : { acquired: false };\n};\n\nexport const tryAcquireProcessorLockWithRetry = async (\n execute: SQLExecutor,\n options: TryAcquireProcessorLockOptions & {\n lockAcquisitionPolicy?: LockAcquisitionPolicy;\n },\n): Promise<TryAcquireProcessorLockResult> => {\n const policy =\n options.lockAcquisitionPolicy ?? DefaultPostgreSQLProcessorLockPolicy;\n\n if (policy.type === 'retry') {\n return asyncRetry(() => tryAcquireProcessorLock(execute, options), {\n retries: policy.retries - 1,\n minTimeout: policy.minTimeout,\n maxTimeout: policy.maxTimeout,\n shouldRetryResult: (r) => !r.acquired,\n });\n }\n\n return tryAcquireProcessorLock(execute, options);\n};\n\nexport type ReleaseProcessorLockOptions = {\n processorId: string;\n version: number;\n partition: string;\n processorInstanceId: string;\n projectionName?: string;\n lockKey: string | bigint;\n};\n\nexport const releaseProcessorLock = async (\n execute: SQLExecutor,\n options: ReleaseProcessorLockOptions,\n): Promise<boolean> => {\n const lockKeyBigInt = isBigint(options.lockKey)\n ? options.lockKey\n : await hashText(options.lockKey);\n\n const { result } = await single(\n execute.command<{ result: boolean }>(\n callReleaseProcessorLock({\n lockKey: lockKeyBigInt.toString(),\n processorId: options.processorId,\n partition: options.partition,\n version: options.version,\n processorInstanceId: options.processorInstanceId,\n projectionName: options.projectionName ?? null,\n }),\n ),\n );\n\n return result;\n};\n","import type { SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n EmmettError,\n type ProjectionHandlingType,\n} from '@event-driven-io/emmett';\nimport { toProjectionLockKey } from './postgreSQLProjectionLock';\nimport {\n releaseProcessorLock,\n tryAcquireProcessorLockWithRetry,\n type LockAcquisitionPolicy,\n type TryAcquireProcessorLockOptions,\n} from './tryAcquireProcessorLock';\n\nexport type PostgreSQLProcessorLockOptions = {\n processorId: string;\n version: number;\n partition: string;\n processorInstanceId: string;\n projection?: {\n name: string;\n handlingType: ProjectionHandlingType;\n kind: string;\n version: number;\n };\n lockKey?: string | bigint;\n lockTimeoutSeconds?: number;\n lockAcquisitionPolicy?: LockAcquisitionPolicy;\n};\n\nexport type PostgreSQLProcessorLockContext = {\n execute: SQLExecutor;\n};\n\nexport type PostgreSQLProcessorLock = {\n tryAcquire: (options: PostgreSQLProcessorLockContext) => Promise<boolean>;\n release: (options: PostgreSQLProcessorLockContext) => Promise<void>;\n};\n\nexport const DefaultPostgreSQLProcessorLockPolicy: LockAcquisitionPolicy = {\n type: 'fail',\n};\n\nexport const postgreSQLProcessorLock = (\n options: PostgreSQLProcessorLockOptions,\n): PostgreSQLProcessorLock => {\n let acquired = false;\n const lockKey = options.lockKey ?? toProcessorLockKey(options);\n\n return {\n tryAcquire: async (\n context: PostgreSQLProcessorLockContext,\n ): Promise<boolean> => {\n if (acquired) {\n return true;\n }\n\n const result = await tryAcquireProcessorLockWithRetry(context.execute, {\n ...options,\n lockKey,\n });\n\n // TODO: This should be moved o prcessor\n if (!result.acquired && options.lockAcquisitionPolicy?.type !== 'skip') {\n throw new EmmettError(\n `Failed to acquire lock for processor '${options.processorId}'`,\n );\n }\n acquired = result.acquired;\n return acquired;\n },\n\n release: async (context: PostgreSQLProcessorLockContext): Promise<void> => {\n if (!acquired) return;\n\n const { projection, ...releaseOptions } = options;\n\n await releaseProcessorLock(context.execute, {\n ...releaseOptions,\n lockKey,\n projectionName: projection?.name,\n });\n\n acquired = false;\n },\n };\n};\n\nexport const toProcessorLockKey = ({\n projection,\n processorId,\n partition,\n version,\n}: Pick<\n TryAcquireProcessorLockOptions,\n 'projection' | 'processorId' | 'version' | 'partition'\n>): string =>\n projection\n ? toProjectionLockKey({\n projectionName: projection.name,\n partition: partition,\n version: projection.version,\n })\n : `${partition}:${processorId}:${version}`;\n","import { SQL } from '@event-driven-io/dumbo';\nimport { createFunctionIfDoesNotExistSQL } from '../createFunctionIfDoesNotExist';\nimport { projectionsTable } from '../typing';\n\nexport const registerProjectionSQL = createFunctionIfDoesNotExistSQL(\n 'emt_register_projection',\n SQL`\nCREATE OR REPLACE FUNCTION emt_register_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT,\n p_type VARCHAR(1),\n p_kind TEXT,\n p_status TEXT,\n p_definition JSONB\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_register_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n upsert_result AS (\n INSERT INTO ${SQL.identifier(projectionsTable.name)} (\n name, partition, version, type, kind, status, definition, created_at, last_updated\n )\n SELECT p_name, p_partition, p_version, p_type, p_kind, p_status, p_definition, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (name, partition, version) DO UPDATE\n SET definition = EXCLUDED.definition,\n last_updated = now()\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM upsert_result;\n\n RETURN v_result;\nEND;\n$emt_register_projection$;\n`,\n);\n\nexport const activateProjectionSQL = createFunctionIfDoesNotExistSQL(\n 'emt_activate_projection',\n SQL`\nCREATE OR REPLACE FUNCTION emt_activate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_activate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE ${SQL.identifier(projectionsTable.name)}\n SET status = 'active',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_activate_projection$;\n`,\n);\n\nexport const deactivateProjectionSQL = createFunctionIfDoesNotExistSQL(\n 'emt_deactivate_projection',\n SQL`\nCREATE OR REPLACE FUNCTION emt_deactivate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_deactivate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE ${SQL.identifier(projectionsTable.name)}\n SET status = 'inactive',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_deactivate_projection$;\n`,\n);\n\ntype CallRegisterProjectionParams = {\n lockKey: string;\n name: string;\n partition: string;\n version: number;\n type: 'i' | 'a';\n kind: string;\n status: string;\n definition: string;\n};\n\nexport const callRegisterProjection = (params: CallRegisterProjectionParams) =>\n SQL`\n SELECT emt_register_projection(${params.lockKey}, ${params.name}, ${params.partition}, ${params.version}, ${params.type}, ${params.kind}, ${params.status}, ${params.definition}) AS registered\n `;\n\ntype CallActivateProjectionParams = {\n lockKey: string;\n name: string;\n partition: string;\n version: number;\n};\n\nexport const callActivateProjection = (params: CallActivateProjectionParams) =>\n SQL`SELECT emt_activate_projection(${params.lockKey}, ${params.name}, ${params.partition}, ${params.version}) AS activated`;\n\ntype CallDeactivateProjectionParams = {\n lockKey: string;\n name: string;\n partition: string;\n version: number;\n};\n\nexport const callDeactivateProjection = (\n params: CallDeactivateProjectionParams,\n) =>\n SQL`SELECT emt_deactivate_projection(${params.lockKey}, ${params.name}, ${params.partition}, ${params.version}) AS deactivated`;\n","import {\n JSONSerializer,\n single,\n singleOrNull,\n SQL,\n type SQLExecutor,\n} from '@event-driven-io/dumbo';\nimport {\n hashText,\n type AnyReadEventMetadata,\n type DefaultRecord,\n type ProjectionDefinition,\n type ProjectionHandlingType,\n type ProjectionRegistration,\n} from '@event-driven-io/emmett';\nimport {\n callActivateProjection,\n callDeactivateProjection,\n callRegisterProjection,\n} from '../../schema/projections/registerProjection';\nimport { projectionsTable } from '../../schema/typing';\nimport { toProjectionLockKey } from '../locks/postgreSQLProjectionLock';\n\nexport const registerProjection = async <\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n>(\n execute: SQLExecutor,\n options: {\n partition: string;\n status: 'active' | 'inactive';\n registration: ProjectionRegistration<\n ProjectionHandlingType,\n ReadEventMetadataType,\n ProjectionHandlerContext\n >;\n },\n): Promise<{ registered: boolean }> => {\n const { partition, status, registration } = options;\n\n const type = registration.type === 'inline' ? 'i' : 'a';\n const name = registration.projection.name;\n const version = registration.projection.version ?? 1;\n const kind = registration.projection.kind ?? registration.type;\n const definition = JSONSerializer.serialize(registration.projection);\n\n const lockKey = toProjectionLockKey({\n projectionName: name!,\n partition,\n version,\n });\n\n const lockKeyBigInt = await hashText(lockKey);\n\n const { registered } = await single<{ registered: boolean }>(\n execute.query(\n callRegisterProjection({\n lockKey: lockKeyBigInt.toString(),\n name: name!,\n partition,\n version,\n type,\n kind,\n status,\n definition,\n }),\n ),\n );\n\n return { registered };\n};\n\nexport const activateProjection = async (\n execute: SQLExecutor,\n options: { name: string; partition: string; version: number },\n): Promise<{ activated: boolean }> => {\n const { name, partition, version } = options;\n\n const lockKey = toProjectionLockKey({\n projectionName: name,\n partition,\n version,\n });\n\n const lockKeyBigInt = await hashText(lockKey);\n\n const { activated } = await single<{ activated: boolean }>(\n execute.query(\n callActivateProjection({\n lockKey: lockKeyBigInt.toString(),\n name,\n partition,\n version,\n }),\n ),\n );\n\n return { activated };\n};\n\nexport const deactivateProjection = async (\n execute: SQLExecutor,\n options: { name: string; partition: string; version: number },\n): Promise<{ deactivated: boolean }> => {\n const { name, partition, version } = options;\n\n const lockKey = toProjectionLockKey({\n projectionName: name,\n partition,\n version,\n });\n\n const lockKeyBigInt = await hashText(lockKey);\n\n const { deactivated } = await single<{ deactivated: boolean }>(\n execute.query(\n callDeactivateProjection({\n lockKey: lockKeyBigInt.toString(),\n name,\n partition,\n version,\n }),\n ),\n );\n\n return { deactivated };\n};\n\ntype ProjectionRegistrationWithMandatoryData =\n ProjectionRegistration<ProjectionHandlingType> & {\n projection: Required<\n Pick<ProjectionDefinition, 'kind' | 'version' | 'name'>\n >;\n };\n\nexport type ReadProjectionInfoResult = {\n partition: string;\n status: 'active' | 'inactive';\n registration: ProjectionRegistrationWithMandatoryData;\n createdAt: Date;\n lastUpdated: Date;\n};\n\ntype RawProjectionRow = {\n name: string;\n version: number;\n type: string;\n kind: string;\n status: string;\n definition: ProjectionRegistrationWithMandatoryData['projection'];\n created_at: Date;\n last_updated: Date;\n};\n\nexport const readProjectionInfo = async (\n execute: SQLExecutor,\n {\n name,\n partition,\n version,\n }: { name: string; partition: string; version: number },\n): Promise<ReadProjectionInfoResult | null> => {\n const row = await singleOrNull<RawProjectionRow>(\n execute.query(\n SQL`SELECT name, version, type, kind, status, definition, created_at, last_updated\n FROM ${SQL.identifier(projectionsTable.name)}\n WHERE name = ${name} AND partition = ${partition} AND version = ${version}`,\n ),\n );\n\n return row\n ? {\n partition,\n status: row.status as 'active' | 'inactive',\n registration: {\n type: row.type === 'i' ? 'inline' : 'async',\n projection: {\n ...row.definition,\n name: row.name,\n version: row.version,\n kind: row.kind,\n },\n },\n createdAt: row.created_at,\n lastUpdated: row.last_updated,\n }\n : null;\n};\n","import {\n reduceAsync,\n type CanHandle,\n type Event,\n type EventStoreReadSchemaOptions,\n type JSONSerializationOptions,\n type ReadEvent,\n type TruncateProjection,\n} from '@event-driven-io/emmett';\nimport {\n pongoClient,\n type PongoClient,\n type PongoDBCollectionOptions,\n type PongoDocument,\n} from '@event-driven-io/pongo';\nimport { pgDriver } from '@event-driven-io/pongo/pg';\nimport {\n postgreSQLProjection,\n type PostgreSQLProjectionDefinition,\n type PostgreSQLProjectionHandlerContext,\n} from '..';\nimport type { PostgresReadEventMetadata } from '../../postgreSQLEventStore';\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 PostgresReadEventMetadata =\n PostgresReadEventMetadata,\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 PostgresReadEventMetadata =\n PostgresReadEventMetadata,\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 PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n> =\n | PongoWithNotNullDocumentEvolve<Document, EventType, EventMetaDataType>\n | PongoWithNullableDocumentEvolve<Document, EventType, EventMetaDataType>;\n\nexport type PongoProjectionOptions<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n> = {\n name: string;\n kind?: string;\n version?: number;\n handle: (\n events: ReadEvent<EventType, PostgresReadEventMetadata>[],\n context: PongoProjectionHandlerContext,\n ) => Promise<void>;\n canHandle: CanHandle<EventType>;\n truncate?: TruncateProjection<PongoProjectionHandlerContext>;\n init?: (context: PongoProjectionHandlerContext) => void | Promise<void>;\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\n} & JSONSerializationOptions;\n\nexport const pongoProjection = <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>({\n name,\n kind,\n version,\n truncate,\n handle,\n canHandle,\n eventsOptions,\n}: PongoProjectionOptions<\n EventType,\n EventPayloadType\n>): PostgreSQLProjectionDefinition<EventType, EventPayloadType> =>\n postgreSQLProjection<EventType, EventPayloadType>({\n name,\n version,\n kind: kind ?? 'emt:projections:postgresql:pongo:generic',\n canHandle,\n eventsOptions,\n handle: async (events, context) => {\n const {\n connection: { connectionString, client, pool },\n } = context;\n const pongo = pongoClient({\n connectionString,\n driver: pgDriver,\n connectionOptions: { client, pool },\n });\n try {\n await handle(events, {\n ...context,\n pongo,\n });\n } finally {\n await pongo.close();\n }\n },\n truncate: truncate\n ? async (context) => {\n const {\n connection: { connectionString, client, pool },\n } = context;\n const pongo = pongoClient({\n connectionString,\n driver: pgDriver,\n connectionOptions: { client, pool },\n });\n try {\n await truncate({\n ...context,\n pongo,\n });\n } finally {\n await pongo.close();\n }\n }\n : undefined,\n });\n\nexport type PongoMultiStreamProjectionOptions<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n EventPayloadType extends Event = EventType,\n DocumentPayload extends PongoDocument = Document,\n> = {\n kind?: string;\n canHandle: CanHandle<EventType>;\n version?: number;\n collectionName: string;\n collectionOptions?: PongoDBCollectionOptions<Document, DocumentPayload>;\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\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 JSONSerializationOptions;\n\nexport const pongoMultiStreamProjection = <\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n EventPayloadType extends Event = EventType,\n>(\n options: PongoMultiStreamProjectionOptions<\n Document,\n EventType,\n EventMetaDataType,\n EventPayloadType\n >,\n): PostgreSQLProjectionDefinition<EventType, EventPayloadType> => {\n const { collectionName, getDocumentId, canHandle } = options;\n const collectionNameWithVersion =\n options.version && options.version > 0\n ? `${collectionName}_v${options.version}`\n : collectionName;\n\n return pongoProjection({\n name: collectionNameWithVersion,\n version: options.version,\n kind: options.kind ?? 'emt:projections:postgresql:pongo:multi_stream',\n eventsOptions: options.eventsOptions,\n handle: async (events, { pongo }) => {\n const collection = pongo\n .db()\n .collection<Document>(\n collectionNameWithVersion,\n options.collectionOptions,\n );\n\n const eventsByDocumentId = events\n .map((event) => {\n const documentId = getDocumentId(event);\n\n return {\n documentId,\n event: event as ReadEvent<EventType, EventMetaDataType>,\n };\n })\n .reduce((acc, { documentId, event }) => {\n if (!acc.has(documentId)) {\n acc.set(documentId, []);\n }\n acc.get(documentId)!.push(event);\n return acc;\n }, new Map<string, ReadEvent<EventType, EventMetaDataType>[]>());\n\n await collection.handle(\n [...eventsByDocumentId.keys()],\n (document, id) => {\n const events = eventsByDocumentId.get(id)!;\n\n return reduceAsync(\n events,\n async (acc, event) => await options.evolve(acc!, event),\n document ??\n ('initialState' in options ? options.initialState() : null),\n );\n },\n );\n },\n canHandle,\n truncate: async (context) => {\n const {\n connection: { connectionString, client, pool },\n } = context;\n const pongo = pongoClient({\n connectionString,\n driver: pgDriver,\n connectionOptions: { client, pool },\n });\n\n try {\n await pongo\n .db()\n .collection<Document>(\n collectionNameWithVersion,\n options.collectionOptions,\n )\n .deleteMany();\n } finally {\n await pongo.close();\n }\n },\n init: async (context) => {\n const {\n connection: { connectionString, client, pool },\n } = context;\n const pongo = pongoClient({\n connectionString,\n driver: pgDriver,\n connectionOptions: { client, pool },\n });\n\n try {\n await pongo\n .db()\n .collection<Document>(\n collectionNameWithVersion,\n options.collectionOptions,\n )\n .schema.migrate(context.migrationOptions);\n } finally {\n await pongo.close();\n }\n },\n });\n};\n\nexport type PongoSingleStreamProjectionOptions<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n EventPayloadType extends Event = EventType,\n DocumentPayload extends PongoDocument = Document,\n> = {\n canHandle: CanHandle<EventType>;\n getDocumentId?: (event: ReadEvent<EventType>) => string;\n version?: number;\n collectionName: string;\n collectionOptions?: PongoDBCollectionOptions<Document, DocumentPayload>;\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\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 JSONSerializationOptions;\n\nexport const pongoSingleStreamProjection = <\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n EventPayloadType extends Event = EventType,\n>(\n options: PongoSingleStreamProjectionOptions<\n Document,\n EventType,\n EventMetaDataType,\n EventPayloadType\n >,\n): PostgreSQLProjectionDefinition<EventType, EventPayloadType> => {\n return pongoMultiStreamProjection<\n Document,\n EventType,\n EventMetaDataType,\n EventPayloadType\n >({\n ...options,\n kind: 'emt:projections:postgresql:pongo:single_stream',\n getDocumentId:\n options.getDocumentId ?? ((event) => event.metadata.streamName),\n });\n};\n","import type { Dumbo } from '@event-driven-io/dumbo';\nimport {\n assertDeepEqual,\n assertEqual,\n assertIsNotNull,\n assertIsNull,\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 { pgDriver } from '@event-driven-io/pongo/pg';\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({\n connectionString,\n connectionOptions: { connection },\n driver: pgDriver,\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 assertIsNull(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 dumbo,\n type Dumbo,\n type QueryResultRow,\n type SQL,\n} from '@event-driven-io/dumbo';\nimport type { PgPool, PgPoolOptions } from '@event-driven-io/dumbo/pg';\nimport {\n assertFails,\n AssertionError,\n assertThatArray,\n assertTrue,\n bigIntProcessorCheckpoint,\n isErrorConstructor,\n type CombinedReadEventMetadata,\n type Event,\n type ReadEvent,\n type ThenThrows,\n} from '@event-driven-io/emmett';\nimport { v4 as uuid } from 'uuid';\nimport {\n handleProjections,\n transactionToPostgreSQLProjectionHandlerContext,\n type PostgreSQLProjectionDefinition,\n} from '.';\nimport {\n getPostgreSQLEventStore,\n type PostgresReadEventMetadata,\n} from '../postgreSQLEventStore';\n\nexport type PostgreSQLProjectionSpecEvent<\n EventType extends Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\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<EventType extends Event> = {\n projection: PostgreSQLProjectionDefinition<EventType>;\n} & PgPoolOptions;\n\nexport const PostgreSQLProjectionSpec = {\n for: <EventType extends Event>(\n options: PostgreSQLProjectionSpecOptions<EventType>,\n ): PostgreSQLProjectionSpec<EventType> => {\n {\n const { projection, ...restOptions } = options;\n const dumboOptions = {\n ...restOptions,\n serialization: projection.serialization,\n };\n const { connectionString } = dumboOptions;\n\n let wasInitialised = false;\n\n const initialize = async (pool: Dumbo): Promise<void> => {\n const eventStore = getPostgreSQLEventStore(connectionString, {\n // TODO: This will need to change when we support other drivers\n connectionOptions: { dumbo: pool as PgPool },\n });\n\n if (wasInitialised) return;\n\n wasInitialised = true;\n\n await eventStore.schema.migrate();\n if (projection.init)\n await pool.withTransaction(async (transaction) => {\n await projection.init!({\n registrationType: 'async',\n version: projection.version ?? 1,\n status: 'active',\n context: await transactionToPostgreSQLProjectionHandlerContext(\n connectionString,\n pool,\n transaction,\n ),\n });\n });\n };\n\n return (givenEvents: PostgreSQLProjectionSpecEvent<EventType>[]) => {\n return {\n when: (\n events: PostgreSQLProjectionSpecEvent<EventType>[],\n options?: PostgreSQLProjectionSpecWhenOptions,\n ) => {\n const allEvents: ReadEvent<EventType, PostgresReadEventMetadata>[] =\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 const metadata: PostgresReadEventMetadata = {\n checkpoint: bigIntProcessorCheckpoint(++globalPosition),\n globalPosition: globalPosition,\n streamPosition: globalPosition,\n streamName: `test-${uuid()}`,\n messageId: uuid(),\n };\n\n allEvents.push({\n ...event,\n kind: 'Event',\n metadata: {\n ...metadata,\n ...('metadata' in event ? (event.metadata ?? {}) : {}),\n } as CombinedReadEventMetadata<\n EventType,\n PostgresReadEventMetadata\n >,\n });\n }\n\n await initialize(pool);\n\n await pool.withTransaction(async (transaction) => {\n await handleProjections<EventType>({\n events: allEvents,\n projections: [projection],\n ...(await transactionToPostgreSQLProjectionHandlerContext(\n connectionString,\n pool,\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(dumboOptions);\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(dumboOptions);\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 PostgresReadEventMetadata =\n PostgresReadEventMetadata,\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 PostgresReadEventMetadata =\n PostgresReadEventMetadata,\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 {\n AnyConnection,\n DatabaseTransaction,\n Dumbo,\n SQL,\n SQLExecutor,\n} from '@event-driven-io/dumbo';\nimport type { PgClient, PgTransaction } from '@event-driven-io/dumbo/pg';\nimport {\n projection,\n type CanHandle,\n type Event,\n type EventStoreReadSchemaOptions,\n type JSONSerializationOptions,\n type ProjectionDefinition,\n type ProjectionHandler,\n type ProjectionInitOptions,\n type ReadEvent,\n} from '@event-driven-io/emmett';\nimport type { PostgresReadEventMetadata } from '../postgreSQLEventStore';\nimport type { EventStoreSchemaMigrationOptions } from '../schema';\nimport { defaultTag } from '../schema/typing';\nimport { postgreSQLProjectionLock } from './locks';\nimport { registerProjection } from './management';\n\nexport type PostgreSQLProjectionHandlerContext = {\n execute: SQLExecutor;\n connection: {\n connectionString: string;\n client: PgClient;\n transaction: PgTransaction;\n pool: Dumbo;\n };\n} &\n // TODO: This should be only for Init options\n // Make init options type configurable for projections\n EventStoreSchemaMigrationOptions;\n\nexport const transactionToPostgreSQLProjectionHandlerContext = async (\n connectionString: string,\n pool: Dumbo,\n transaction: PgTransaction | DatabaseTransaction<AnyConnection>,\n): Promise<PostgreSQLProjectionHandlerContext> => ({\n execute: transaction.execute,\n connection: {\n connectionString: connectionString,\n client: (await transaction.connection.open()) as PgClient,\n transaction: transaction as PgTransaction,\n pool,\n },\n});\n\nexport type PostgreSQLProjectionHandler<\n EventType extends Event = Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n> = ProjectionHandler<\n EventType,\n EventMetaDataType,\n PostgreSQLProjectionHandlerContext\n>;\n\nexport type PostgreSQLProjectionDefinition<\n EventType extends Event = Event,\n EventPayloadType extends Event = EventType,\n> = ProjectionDefinition<\n EventType,\n PostgresReadEventMetadata,\n PostgreSQLProjectionHandlerContext,\n EventPayloadType\n>;\n\nexport type PostgreSQLProjectionHandlerOptions<\n EventType extends Event = Event,\n> = {\n events: ReadEvent<EventType, PostgresReadEventMetadata>[];\n projections: PostgreSQLProjectionDefinition<EventType>[];\n partition?: string;\n} & PostgreSQLProjectionHandlerContext;\n\nexport const handleProjections = async <EventType extends Event = Event>(\n options: PostgreSQLProjectionHandlerOptions<EventType>,\n): Promise<void> => {\n const {\n projections: allProjections,\n events,\n connection: { pool, transaction, connectionString },\n partition = defaultTag,\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 PgClient;\n\n for (const projection of projections) {\n // TODO: Make projection name mandatory\n if (projection.name) {\n const lockAcquired = await postgreSQLProjectionLock({\n projectionName: projection.name,\n partition,\n version: projection.version ?? 1,\n }).tryAcquire({ execute: transaction.execute });\n\n if (!lockAcquired) {\n continue;\n }\n }\n\n await projection.handle(events, {\n connection: {\n connectionString,\n pool,\n client,\n transaction,\n },\n execute: transaction.execute,\n });\n }\n};\n\nexport const postgreSQLProjection = <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>(\n definition: PostgreSQLProjectionDefinition<EventType, EventPayloadType>,\n): PostgreSQLProjectionDefinition<EventType, EventPayloadType> =>\n projection<\n EventType,\n PostgresReadEventMetadata,\n PostgreSQLProjectionHandlerContext,\n EventPayloadType\n >({\n ...definition,\n init: async (options) => {\n await registerProjection<\n PostgresReadEventMetadata,\n PostgreSQLProjectionHandlerContext\n >(options.context.execute, {\n // TODO: pass partition from options\n partition: defaultTag,\n status: 'active',\n registration: {\n type: 'async',\n // TODO: fix this\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any\n projection: definition as any,\n },\n });\n if (definition.init) {\n await definition.init(options);\n }\n },\n });\n\nexport type PostgreSQLRawBatchSQLProjection<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n> = {\n name: string;\n kind?: string;\n version?: number;\n evolve: (\n events: EventType[],\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<SQL[]> | SQL[];\n canHandle: CanHandle<EventType>;\n init?: (\n context: ProjectionInitOptions<PostgreSQLProjectionHandlerContext>,\n ) => void | Promise<void> | SQL | Promise<SQL> | Promise<SQL[]> | SQL[];\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\n} & JSONSerializationOptions;\n\nexport const postgreSQLRawBatchSQLProjection = <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>(\n options: PostgreSQLRawBatchSQLProjection<EventType, EventPayloadType>,\n): PostgreSQLProjectionDefinition<EventType, EventPayloadType> =>\n postgreSQLProjection<EventType, EventPayloadType>({\n name: options.name,\n kind: options.kind ?? 'emt:projections:postgresql:raw_sql:batch',\n version: options.version,\n canHandle: options.canHandle,\n eventsOptions: options.eventsOptions,\n handle: async (events, context) => {\n const sqls: SQL[] = await options.evolve(events, context);\n\n await context.execute.batchCommand(sqls);\n },\n init: async (initOptions) => {\n const initSQL = options.init\n ? await options.init(initOptions)\n : undefined;\n\n if (initSQL) {\n if (Array.isArray(initSQL)) {\n await initOptions.context.execute.batchCommand(initSQL);\n } else {\n await initOptions.context.execute.command(initSQL);\n }\n }\n },\n });\n\nexport type PostgreSQLRawSQLProjection<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n> = {\n name: string;\n kind?: string;\n version?: number;\n evolve: (\n events: EventType,\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<SQL[]> | SQL[] | Promise<SQL> | SQL;\n canHandle: CanHandle<EventType>;\n init?: (\n context: ProjectionInitOptions<PostgreSQLProjectionHandlerContext>,\n ) => void | Promise<void> | SQL | Promise<SQL> | Promise<SQL[]> | SQL[];\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\n} & JSONSerializationOptions;\n\nexport const postgreSQLRawSQLProjection = <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>(\n options: PostgreSQLRawSQLProjection<EventType, EventPayloadType>,\n): PostgreSQLProjectionDefinition<EventType, EventPayloadType> => {\n const { evolve, kind, ...rest } = options;\n return postgreSQLRawBatchSQLProjection<EventType, EventPayloadType>({\n kind: kind ?? 'emt:projections:postgresql:raw:_sql:single',\n ...rest,\n evolve: async (events, context) => {\n const sqls: SQL[] = [];\n\n for (const event of events) {\n const pendingSqls = await evolve(event, context);\n if (Array.isArray(pendingSqls)) {\n sqls.push(...pendingSqls);\n } else {\n sqls.push(pendingSqls);\n }\n }\n return sqls;\n },\n });\n};\n","import {\n DumboError,\n single,\n SQL,\n UniqueConstraintError,\n type SQLExecutor,\n} from '@event-driven-io/dumbo';\nimport type { PgPool, PgTransaction } from '@event-driven-io/dumbo/pg';\nimport {\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AppendToStreamOptions,\n type DefaultRecord,\n type ExpectedStreamVersion,\n type Message,\n type RecordedMessage,\n} from '@event-driven-io/emmett';\nimport { v4 as uuid } from 'uuid';\nimport { createFunctionIfDoesNotExistSQL } from './createFunctionIfDoesNotExist';\nimport { defaultTag, messagesTable, streamsTable } from './typing';\n\nexport const appendToStreamSQL = createFunctionIfDoesNotExistSQL(\n 'emt_append_to_stream',\n SQL`CREATE OR REPLACE FUNCTION emt_append_to_stream(\n v_message_ids text[],\n v_messages_data jsonb[],\n v_messages_metadata jsonb[],\n v_message_schema_versions text[],\n v_message_types text[],\n v_message_kinds 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 global_positions bigint[],\n transaction_id xid8\n ) LANGUAGE plpgsql\n AS $emt_append_to_stream$\n DECLARE\n v_next_stream_position bigint;\n v_position bigint;\n v_updated_rows int;\n v_transaction_id xid8;\n v_global_positions bigint[];\n BEGIN\n v_transaction_id := pg_current_xact_id();\n\n IF v_expected_stream_position IS NULL THEN\n SELECT COALESCE(\n (SELECT stream_position \n FROM ${SQL.identifier(streamsTable.name)}\n WHERE stream_id = v_stream_id \n AND partition = v_partition \n AND is_archived = FALSE\n LIMIT 1), \n 0\n ) INTO v_expected_stream_position;\n END IF;\n\n v_next_stream_position := v_expected_stream_position + array_upper(v_messages_data, 1);\n\n IF v_expected_stream_position = 0 THEN\n INSERT INTO ${SQL.identifier(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 ${SQL.identifier(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 WITH ev AS (\n SELECT row_number() OVER () + v_expected_stream_position AS stream_position, \n message_data, \n message_metadata, \n schema_version, \n message_id, \n message_type,\n message_kind\n FROM (\n SELECT *\n FROM \n unnest(v_message_ids, v_messages_data, v_messages_metadata, v_message_schema_versions, v_message_types, v_message_kinds) \n AS message(message_id, message_data, message_metadata, schema_version, message_type, message_kind)\n ) AS message\n ),\n all_messages_insert AS (\n INSERT INTO ${SQL.identifier(messagesTable.name)}\n (stream_id, stream_position, partition, message_data, message_metadata, message_schema_version, message_type, message_kind, message_id, transaction_id)\n SELECT \n v_stream_id, ev.stream_position, v_partition, ev.message_data, ev.message_metadata, ev.schema_version, ev.message_type, ev.message_kind, ev.message_id, v_transaction_id\n FROM ev\n RETURNING global_position\n )\n SELECT \n array_agg(global_position ORDER BY global_position) INTO v_global_positions\n FROM \n all_messages_insert;\n\n RETURN QUERY SELECT TRUE, v_next_stream_position, v_global_positions, v_transaction_id;\n END;\n $emt_append_to_stream$;\n `,\n);\n\ntype CallAppendToStreamParams = {\n messageIds: string[];\n messagesData: DefaultRecord[];\n messagesMetadata: DefaultRecord[];\n schemaVersions: string[];\n messageTypes: string[];\n messageKinds: string[];\n streamId: string;\n streamType: string;\n expectedStreamPosition: bigint | null;\n partition: string;\n};\n\n// TODO: check if we need all those casts\nexport const callAppendToStream = (params: CallAppendToStreamParams) =>\n SQL`SELECT * FROM emt_append_to_stream(\n ${params.messageIds},\n ${params.messagesData},\n ${params.messagesMetadata},\n ${params.schemaVersions},\n ${params.messageTypes},\n ${params.messageKinds},\n ${params.streamId}::text,\n ${params.streamType}::text,\n ${params.expectedStreamPosition},\n ${params.partition}::text\n )`;\n\ntype AppendToStreamResult =\n | {\n success: true;\n nextStreamPosition: bigint;\n globalPositions: bigint[];\n transactionId: string;\n }\n | { success: false };\n\nexport type AppendToStreamBeforeCommitHook = (\n messages: RecordedMessage[],\n context: {\n transaction: PgTransaction;\n },\n) => Promise<void>;\n\nexport const appendToStream = (\n pool: PgPool,\n streamName: string,\n streamType: string,\n messages: Message[],\n options?: AppendToStreamOptions & {\n partition?: string;\n beforeCommitHook?: AppendToStreamBeforeCommitHook;\n },\n): Promise<AppendToStreamResult> =>\n pool.withTransaction<AppendToStreamResult>(async (transaction) => {\n const { execute } = transaction;\n\n if (messages.length === 0)\n return { success: false, result: { success: false } };\n\n try {\n const expectedStreamVersion = toExpectedVersion(\n options?.expectedStreamVersion,\n );\n\n const messagesToAppend: RecordedMessage[] = messages.map((e) => ({\n ...e,\n kind: e.kind ?? 'Event',\n metadata: {\n messageId: uuid(),\n ...('metadata' in e ? (e.metadata ?? {}) : {}),\n },\n })) as RecordedMessage[];\n\n const {\n success,\n next_stream_position,\n global_positions,\n transaction_id,\n } = await appendEventsRaw(\n execute,\n streamName,\n streamType,\n messagesToAppend,\n {\n expectedStreamVersion,\n },\n );\n\n if (\n !success ||\n next_stream_position === null ||\n global_positions === null ||\n global_positions.length === 0 ||\n transaction_id == null\n ) {\n return {\n success: false,\n\n result: { success: false },\n };\n }\n\n const nextStreamPosition = BigInt(next_stream_position);\n\n const globalPositions = global_positions.map(BigInt);\n\n globalPositions.forEach((globalPosition, index) => {\n messagesToAppend[index]!.metadata = {\n ...messagesToAppend[index]!.metadata,\n streamName,\n streamPosition:\n nextStreamPosition -\n BigInt(messagesToAppend.length) +\n BigInt(index + 1),\n globalPosition,\n };\n });\n\n if (options?.beforeCommitHook)\n await options.beforeCommitHook(messagesToAppend, { transaction });\n\n return {\n success: true,\n\n result: {\n success: true,\n nextStreamPosition,\n globalPositions,\n transactionId: transaction_id,\n },\n };\n } catch (error) {\n if (!isOptimisticConcurrencyError(error)) throw error;\n\n return {\n success: false,\n result: { success: false },\n };\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 DumboError.isInstanceOf(error, {\n errorType: UniqueConstraintError.ErrorType,\n });\n\ntype AppendToStreamSqlResult = {\n success: boolean;\n next_stream_position: string | null;\n global_positions: string[] | null;\n transaction_id: string | null | undefined;\n};\n\nconst appendEventsRaw = (\n execute: SQLExecutor,\n streamId: string,\n streamType: string,\n messages: RecordedMessage[],\n options?: {\n expectedStreamVersion: bigint | null;\n partition?: string;\n },\n): Promise<AppendToStreamSqlResult> =>\n single(\n execute.command<AppendToStreamSqlResult>(\n callAppendToStream({\n messageIds: messages.map((e) => e.metadata.messageId),\n messagesData: messages.map((e) => e.data),\n messagesMetadata: messages.map((e) => {\n const { messageId: _messageId, ...rawMetadata } = e.metadata;\n return rawMetadata;\n }),\n schemaVersions: messages.map(() => `'1'`),\n messageTypes: messages.map((e) => e.type),\n messageKinds: messages.map((e) => (e.kind === 'Event' ? 'E' : 'C')),\n streamId,\n streamType,\n expectedStreamPosition: options?.expectedStreamVersion ?? null,\n partition: options?.partition ?? defaultTag,\n }),\n ),\n );\n","import { SQL, type SQLMigration, sqlMigration } from '@event-driven-io/dumbo';\n\nexport const dropFutureConceptModuleAndTenantFunctions = SQL`\n DO $$\n BEGIN\n -- Check and drop functions related to future concept of modules and tenants\n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_module') THEN\n DROP FUNCTION add_module(TEXT);\n END IF;\n \n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_tenant') THEN\n DROP FUNCTION add_tenant(TEXT, TEXT);\n END IF;\n\n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_module_for_all_tenants') THEN\n DROP FUNCTION add_module_for_all_tenants(TEXT);\n END IF;\n \n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_tenant_for_all_modules') THEN\n DROP FUNCTION add_tenant_for_all_modules(TEXT);\n END IF;\n END $$;\n`;\n\nexport const dropOldAppendToSQLWithoutGlobalPositions = SQL`\n DO $$\n DECLARE\n v_current_return_type text;\n BEGIN\n -- Get the current return type definition as text\n SELECT pg_get_function_result(p.oid)\n INTO v_current_return_type\n FROM pg_proc p\n JOIN pg_namespace n ON p.pronamespace = n.oid\n WHERE n.nspname = current_schema() -- or specify your schema\n AND p.proname = 'emt_append_to_stream'\n AND p.pronargs = 10; -- number of arguments\n \n -- Check if it contains the old column name\n IF v_current_return_type IS NOT NULL AND \n v_current_return_type LIKE '%last_global_position%' AND \n v_current_return_type NOT LIKE '%global_positions%' THEN\n DROP FUNCTION emt_append_to_stream(text[], jsonb[], jsonb[], text[], text[], text[], text, text, bigint, text);\n RAISE NOTICE 'Old version of function dropped. Return type was: %', v_current_return_type;\n END IF;\n END $$;\n`;\n\nexport const migrationFromEventsToMessagesSQL = SQL`\nDO $$ \nDECLARE\n partition_record RECORD;\nBEGIN\n -- Rename the main table and its columns if it exists\n IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'emt_events') THEN\n -- Rename all partitions first\n FOR partition_record IN \n SELECT tablename \n FROM pg_tables \n WHERE tablename LIKE 'emt_events_%'\n ORDER BY tablename DESC -- to handle child partitions first\n LOOP\n EXECUTE format('ALTER TABLE %I RENAME TO %I', \n partition_record.tablename, \n REPLACE(partition_record.tablename, 'events', 'messages'));\n END LOOP;\n\n -- Rename the main table\n ALTER TABLE emt_events RENAME TO emt_messages;\n \n -- Rename columns\n ALTER TABLE emt_messages \n RENAME COLUMN event_data TO message_data;\n ALTER TABLE emt_messages \n RENAME COLUMN event_metadata TO message_metadata;\n ALTER TABLE emt_messages \n RENAME COLUMN event_schema_version TO message_schema_version;\n ALTER TABLE emt_messages \n RENAME COLUMN event_type TO message_type;\n ALTER TABLE emt_messages \n RENAME COLUMN event_id TO message_id;\n ALTER TABLE emt_messages \n ADD COLUMN message_kind CHAR(1) NOT NULL DEFAULT 'E';\n\n -- Rename sequence if it exists\n IF EXISTS (SELECT 1 FROM pg_sequences WHERE sequencename = 'emt_global_event_position') THEN\n ALTER SEQUENCE emt_global_event_position \n RENAME TO emt_global_message_position;\n \n ALTER TABLE emt_messages \n ALTER COLUMN global_position \n SET DEFAULT nextval('emt_global_message_position');\n END IF;\n END IF;\nEND $$;`;\n\nexport const migration_0_38_7_and_older: SQLMigration = sqlMigration(\n 'emt:postgresql:eventstore:0.38.7:migrate-events-to-messages',\n [\n dropFutureConceptModuleAndTenantFunctions,\n dropOldAppendToSQLWithoutGlobalPositions,\n migrationFromEventsToMessagesSQL,\n ],\n);\n","import { SQL } from '@event-driven-io/dumbo';\n\nexport const schema_0_38_7 = SQL`\nDO $$ \nDECLARE\n partition_record RECORD;\nBEGIN\n -- Rename the main table and its columns if it exists\n IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'emt_events') THEN\n -- Rename all partitions first\n FOR partition_record IN \n SELECT tablename \n FROM pg_tables \n WHERE tablename LIKE 'emt_events_%'\n ORDER BY tablename DESC -- to handle child partitions first\n LOOP\n EXECUTE format('ALTER TABLE %I RENAME TO %I', \n partition_record.tablename, \n REPLACE(partition_record.tablename, 'events', 'messages'));\n END LOOP;\n\n -- Rename the main table\n ALTER TABLE emt_events RENAME TO emt_messages;\n \n -- Rename columns\n ALTER TABLE emt_messages \n RENAME COLUMN event_data TO message_data;\n ALTER TABLE emt_messages \n RENAME COLUMN event_metadata TO message_metadata;\n ALTER TABLE emt_messages \n RENAME COLUMN event_schema_version TO message_schema_version;\n ALTER TABLE emt_messages \n RENAME COLUMN event_type TO message_type;\n ALTER TABLE emt_messages \n RENAME COLUMN event_id TO message_id;\n ALTER TABLE emt_messages \n ADD COLUMN message_kind CHAR(1) NOT NULL DEFAULT 'E';\n\n -- Rename sequence if it exists\n IF EXISTS (SELECT 1 FROM pg_sequences WHERE sequencename = 'emt_global_event_position') THEN\n ALTER SEQUENCE emt_global_event_position \n RENAME TO emt_global_message_position;\n \n ALTER TABLE emt_messages \n ALTER COLUMN global_position \n SET DEFAULT nextval('emt_global_message_position');\n END IF;\n END IF;\nEND $$;CREATE TABLE IF NOT EXISTS emt_streams(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'global',\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, partition, is_archived)\n ) PARTITION BY LIST (partition);\n \n CREATE UNIQUE INDEX IF NOT EXISTS idx_streams_unique \n ON emt_streams(stream_id, partition, is_archived) \n INCLUDE (stream_position);\n CREATE SEQUENCE IF NOT EXISTS emt_global_message_position;\n\n CREATE TABLE IF NOT EXISTS emt_messages(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'global',\n message_kind CHAR(1) NOT NULL DEFAULT 'E',\n message_data JSONB NOT NULL,\n message_metadata JSONB NOT NULL,\n message_schema_version TEXT NOT NULL,\n message_type TEXT NOT NULL,\n message_id TEXT NOT NULL,\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n global_position BIGINT DEFAULT nextval('emt_global_message_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 CREATE TABLE IF NOT EXISTS emt_subscriptions(\n subscription_id TEXT NOT NULL,\n version INT NOT NULL DEFAULT 1,\n partition TEXT NOT NULL DEFAULT 'global',\n last_processed_position BIGINT NOT NULL,\n last_processed_transaction_id XID8 NOT NULL,\n PRIMARY KEY (subscription_id, partition, version)\n ) PARTITION BY LIST (partition);\nCREATE 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 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\n -- create default 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 CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $$\n BEGIN \n PERFORM emt_add_table_partition('emt_messages', partition_name);\n PERFORM emt_add_table_partition('emt_streams', partition_name);\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_subscriptions' || '_' || partition_name), 'emt_subscriptions', partition_name\n );\n END;\n $$ LANGUAGE plpgsql;\n\n DO $$\n BEGIN\n -- Check and drop functions related to future concept of modules and tenants\n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_module') THEN\n DROP FUNCTION add_module(TEXT);\n END IF;\n \n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_tenant') THEN\n DROP FUNCTION add_tenant(TEXT, TEXT);\n END IF;\n\n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_module_for_all_tenants') THEN\n DROP FUNCTION add_module_for_all_tenants(TEXT);\n END IF;\n \n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_tenant_for_all_modules') THEN\n DROP FUNCTION add_tenant_for_all_modules(TEXT);\n END IF;\n END $$;\n\n\n DO $$\n DECLARE\n v_current_return_type text;\n BEGIN\n -- Get the current return type definition as text\n SELECT pg_get_function_result(p.oid)\n INTO v_current_return_type\n FROM pg_proc p\n JOIN pg_namespace n ON p.pronamespace = n.oid\n WHERE n.nspname = current_schema() -- or specify your schema\n AND p.proname = 'emt_append_to_stream'\n AND p.pronargs = 10; -- number of arguments\n \n -- Check if it contains the old column name\n IF v_current_return_type IS NOT NULL AND \n v_current_return_type LIKE '%last_global_position%' AND \n v_current_return_type NOT LIKE '%global_positions%' THEN\n DROP FUNCTION emt_append_to_stream(text[], jsonb[], jsonb[], text[], text[], text[], text, text, bigint, text);\n RAISE NOTICE 'Old version of function dropped. Return type was: %', v_current_return_type;\n END IF;\n END $$;\nCREATE OR REPLACE FUNCTION emt_append_to_stream(\n v_message_ids text[],\n v_messages_data jsonb[],\n v_messages_metadata jsonb[],\n v_message_schema_versions text[],\n v_message_types text[],\n v_message_kinds 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 global_positions 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_global_positions bigint[];\n BEGIN\n v_transaction_id := pg_current_xact_id();\n\n IF v_expected_stream_position IS NULL THEN\n SELECT COALESCE(\n (SELECT stream_position \n FROM emt_streams\n WHERE stream_id = v_stream_id \n AND partition = v_partition \n AND is_archived = FALSE\n LIMIT 1), \n 0\n ) INTO v_expected_stream_position;\n END IF;\n\n v_next_stream_position := v_expected_stream_position + array_upper(v_messages_data, 1);\n\n IF v_expected_stream_position = 0 THEN\n INSERT INTO emt_streams\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 emt_streams 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 WITH ev AS (\n SELECT row_number() OVER () + v_expected_stream_position AS stream_position, \n message_data, \n message_metadata, \n schema_version, \n message_id, \n message_type,\n message_kind\n FROM (\n SELECT *\n FROM \n unnest(v_message_ids, v_messages_data, v_messages_metadata, v_message_schema_versions, v_message_types, v_message_kinds) \n AS message(message_id, message_data, message_metadata, schema_version, message_type, message_kind)\n ) AS message\n ),\n all_messages_insert AS (\n INSERT INTO emt_messages\n (stream_id, stream_position, partition, message_data, message_metadata, message_schema_version, message_type, message_kind, message_id, transaction_id)\n SELECT \n v_stream_id, ev.stream_position, v_partition, ev.message_data, ev.message_metadata, ev.schema_version, ev.message_type, ev.message_kind, ev.message_id, v_transaction_id\n FROM ev\n RETURNING global_position\n )\n SELECT \n array_agg(global_position ORDER BY global_position) INTO v_global_positions\n FROM \n all_messages_insert;\n\n RETURN QUERY SELECT TRUE, v_next_stream_position, v_global_positions, v_transaction_id;\n END;\n $$;\n SELECT emt_add_partition('emt:default');\nCREATE OR REPLACE FUNCTION store_subscription_checkpoint(\n p_subscription_id VARCHAR(100),\n p_version BIGINT,\n p_position BIGINT,\n p_check_position BIGINT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT 'emt:default'\n) RETURNS INT AS $$\nDECLARE\n current_position BIGINT;\nBEGIN\n -- Handle the case when p_check_position is provided\n IF p_check_position IS NOT NULL THEN\n -- Try to update if the position matches p_check_position\n UPDATE \"emt_subscriptions\"\n SET \n \"last_processed_position\" = p_position, \n \"last_processed_transaction_id\" = p_transaction_id\n WHERE \"subscription_id\" = p_subscription_id AND \"last_processed_position\" = p_check_position AND \"partition\" = p_partition;\n\n IF FOUND THEN\n RETURN 1; -- Successfully updated\n END IF;\n\n -- Retrieve the current position\n SELECT \"last_processed_position\" INTO current_position\n FROM \"emt_subscriptions\"\n WHERE \"subscription_id\" = p_subscription_id AND \"partition\" = p_partition;\n\n -- Return appropriate codes based on current position\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSIF current_position > p_check_position THEN\n RETURN 2; -- Failure: current position is greater\n ELSE\n RETURN 2; -- Default failure case for mismatched positions\n END IF;\n END IF;\n\n -- Handle the case when p_check_position is NULL: Insert if not exists\n BEGIN\n INSERT INTO \"emt_subscriptions\"(\"subscription_id\", \"version\", \"last_processed_position\", \"partition\", \"last_processed_transaction_id\")\n VALUES (p_subscription_id, p_version, p_position, p_partition, p_transaction_id);\n RETURN 1; -- Successfully inserted\n EXCEPTION WHEN unique_violation THEN\n -- If insertion failed, it means the row already exists\n SELECT \"last_processed_position\" INTO current_position\n FROM \"emt_subscriptions\"\n WHERE \"subscription_id\" = p_subscription_id AND \"partition\" = p_partition;\n\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSE\n RETURN 2; -- Insertion failed, row already exists with different position\n END IF;\n END;\nEND;\n$$ LANGUAGE plpgsql;\n`;\n","import { SQL, sqlMigration, type SQLMigration } from '@event-driven-io/dumbo';\nimport { defaultTag } from '../../typing';\n\nexport const migration_0_42_0_FromSubscriptionsToProcessorsSQL = SQL`\nDO $$\nBEGIN\n IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'emt_subscriptions') THEN\n -- 1. Alter message_kind type from CHAR(1) to VARCHAR(1)\n ALTER TABLE emt_messages ALTER COLUMN message_kind TYPE VARCHAR(1);\n\n -- 2. Setup emt_processors table if not exists\n CREATE TABLE IF NOT EXISTS \"emt_processors\"(\n last_processed_transaction_id XID8 NOT NULL,\n version INT NOT NULL DEFAULT 1,\n processor_id TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\n status TEXT NOT NULL DEFAULT 'stopped', \n last_processed_checkpoint TEXT NOT NULL, \n processor_instance_id TEXT DEFAULT 'emt:unknown',\n PRIMARY KEY (processor_id, partition, version)\n ) PARTITION BY LIST (partition);\n\n -- 3. Setup emt_projections table if not exists\n\n CREATE TABLE IF NOT EXISTS \"emt_projections\"(\n version INT NOT NULL DEFAULT 1, \n type VARCHAR(1) NOT NULL,\n name TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\n kind TEXT NOT NULL, \n status TEXT NOT NULL, \n definition JSONB NOT NULL DEFAULT '{}'::jsonb, \n PRIMARY KEY (name, partition, version)\n ) PARTITION BY LIST (partition);\n\n CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $fnpar$\n BEGIN \n PERFORM emt_add_table_partition('emt_messages', partition_name);\n PERFORM emt_add_table_partition('emt_streams', partition_name);\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_subscriptions' || '_' || partition_name), 'emt_subscriptions', partition_name\n );\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_processors' || '_' || partition_name), 'emt_processors', partition_name\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_projections' || '_' || partition_name), 'emt_projections', partition_name\n );\n END;\n $fnpar$ LANGUAGE plpgsql;\n\n PERFORM emt_add_partition('${SQL.plain(defaultTag)}');\n\n -- 3. Copy data from old table to new table\n INSERT INTO \"emt_processors\"\n (\n processor_id,\n version,\n partition,\n last_processed_checkpoint,\n last_processed_transaction_id,\n status,\n processor_instance_id\n )\n SELECT \n subscription_id, \n version,\n partition,\n lpad(last_processed_position::text, 19, '0'),\n last_processed_transaction_id, 'stopped', \n 'emt:unknown'\n FROM emt_subscriptions\n ON CONFLICT DO NOTHING;\n\n -- 4. Create backward-compat store_subscription_checkpoint that dual-writes\n \n CREATE OR REPLACE FUNCTION store_subscription_checkpoint(\n p_subscription_id VARCHAR(100),\n p_version BIGINT,\n p_position BIGINT,\n p_check_position BIGINT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT 'emt:default'\n ) RETURNS INT AS $fn$\n DECLARE\n current_position BIGINT;\n result INT;\n BEGIN\n -- Handle the case when p_check_position is provided\n IF p_check_position IS NOT NULL THEN\n -- Try to update if the position matches p_check_position\n UPDATE \"emt_subscriptions\"\n SET\n \"last_processed_position\" = p_position,\n \"last_processed_transaction_id\" = p_transaction_id\n WHERE \"subscription_id\" = p_subscription_id \n AND \"last_processed_position\" = p_check_position \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF FOUND THEN\n -- Dual-write to emt_processors\n UPDATE \"emt_processors\"\n SET\n \"last_processed_checkpoint\" = lpad(p_position::text, 19, '0'),\n \"last_processed_transaction_id\" = p_transaction_id\n WHERE \"processor_id\" = p_subscription_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF NOT FOUND THEN\n INSERT INTO \"emt_processors\"(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"status\", \"processor_instance_id\")\n VALUES (p_subscription_id, p_version, lpad(p_position::text, 19, '0'), p_partition, p_transaction_id, 'stopped', 'emt:unknown')\n ON CONFLICT DO NOTHING;\n END IF;\n\n RETURN 1;\n END IF;\n\n -- Retrieve the current position\n SELECT \"last_processed_position\" INTO current_position\n FROM \"emt_subscriptions\"\n WHERE \"subscription_id\" = p_subscription_id AND \"partition\" = p_partition AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSIF current_position > p_check_position THEN\n RETURN 2;\n ELSE\n RETURN 2;\n END IF;\n END IF;\n\n -- Handle the case when p_check_position is NULL: Insert if not exists\n BEGIN\n INSERT INTO \"emt_subscriptions\"(\"subscription_id\", \"version\", \"last_processed_position\", \"partition\", \"last_processed_transaction_id\")\n VALUES (p_subscription_id, p_version, p_position, p_partition, p_transaction_id);\n\n -- Dual-write to emt_processors\n INSERT INTO emt_processors(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"status\", \"processor_instance_id\")\n VALUES (p_subscription_id, p_version, lpad(p_position::text, 19, '0'), p_partition, p_transaction_id, 'stopped', 'emt:unknown')\n ON CONFLICT DO NOTHING;\n\n RETURN 1;\n EXCEPTION WHEN unique_violation THEN\n SELECT \"last_processed_position\" INTO current_position\n FROM \"emt_subscriptions\"\n WHERE \"subscription_id\" = p_subscription_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSE\n RETURN 2;\n END IF;\n END;\n END;\n $fn$ LANGUAGE plpgsql;\n\n -- 5. Replace store_processor_checkpoint with dual-write version\n CREATE OR REPLACE FUNCTION store_processor_checkpoint(\n p_processor_id TEXT,\n p_version BIGINT,\n p_position TEXT,\n p_check_position TEXT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT '${SQL.plain(defaultTag)}',\n p_processor_instance_id TEXT DEFAULT 'emt:unknown'\n ) RETURNS INT AS $fn2$\n DECLARE\n current_position TEXT;\n v_position_bigint BIGINT;\n BEGIN\n -- Convert TEXT position to BIGINT for emt_subscriptions\n v_position_bigint := p_position::BIGINT;\n\n -- Handle the case when p_check_position is provided\n IF p_check_position IS NOT NULL THEN\n -- Try to update if the position matches p_check_position\n UPDATE \"emt_processors\"\n SET\n \"last_processed_checkpoint\" = p_position,\n \"last_processed_transaction_id\" = p_transaction_id,\n \"last_updated\" = now()\n WHERE \"processor_id\" = p_processor_id \n AND \"last_processed_checkpoint\" = p_check_position \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF FOUND THEN\n -- Dual-write to emt_subscriptions\n UPDATE \"emt_subscriptions\"\n SET\n \"last_processed_position\" = v_position_bigint,\n \"last_processed_transaction_id\" = p_transaction_id\n WHERE \"subscription_id\" = p_processor_id AND \"partition\" = p_partition AND \"version\" = p_version;\n\n IF NOT FOUND THEN\n INSERT INTO \"emt_subscriptions\"(\"subscription_id\", \"version\", \"last_processed_position\", \"partition\", \"last_processed_transaction_id\")\n VALUES (p_processor_id, p_version, v_position_bigint, p_partition, p_transaction_id)\n ON CONFLICT DO NOTHING;\n END IF;\n\n RETURN 1;\n END IF;\n\n -- Retrieve the current position\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id AND \"partition\" = p_partition AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSIF current_position > p_position THEN\n RETURN 3;\n ELSE\n RETURN 2;\n END IF;\n END IF;\n\n -- Handle the case when p_check_position is NULL: Insert if not exists\n BEGIN\n INSERT INTO \"emt_processors\"(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"created_at\", \"last_updated\")\n VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());\n\n -- Dual-write to emt_subscriptions\n INSERT INTO \"emt_subscriptions\"(\"subscription_id\", \"version\", \"last_processed_position\", \"partition\", \"last_processed_transaction_id\")\n VALUES (p_processor_id, p_version, v_position_bigint, p_partition, p_transaction_id)\n ON CONFLICT DO NOTHING;\n\n RETURN 1;\n EXCEPTION WHEN unique_violation THEN\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id AND \"partition\" = p_partition;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSIF current_position > p_position THEN\n RETURN 3; -- Current ahead: another process has progressed further\n ELSE\n RETURN 2;\n END IF;\n END;\n END;\n $fn2$ LANGUAGE plpgsql;\n END IF;\nEND $$;\n`;\n\nexport const migration_0_42_0_FromSubscriptionsToProcessors: SQLMigration =\n sqlMigration(\n 'emt:postgresql:eventstore:0.42.0:from-subscriptions-to-processors',\n [migration_0_42_0_FromSubscriptionsToProcessorsSQL],\n );\n\nexport const migration_0_42_0_2_AddProcessorProjectionFunctionsSQL = SQL`\nDO $$\nBEGIN\n IF EXISTS (\n SELECT 1 FROM information_schema.tables\n WHERE table_name = 'emt_processors'\n ) AND NOT EXISTS (\n SELECT 1 FROM information_schema.columns\n WHERE table_name = 'emt_processors' AND column_name = 'created_at'\n ) THEN\n ALTER TABLE emt_processors ADD COLUMN created_at TIMESTAMPTZ NOT NULL DEFAULT now();\n END IF;\n\n IF EXISTS (\n SELECT 1 FROM information_schema.tables\n WHERE table_name = 'emt_processors'\n ) AND NOT EXISTS (\n SELECT 1 FROM information_schema.columns\n WHERE table_name = 'emt_processors' AND column_name = 'last_updated'\n ) THEN\n ALTER TABLE emt_processors ADD COLUMN last_updated TIMESTAMPTZ NOT NULL DEFAULT now();\n END IF;\n\n IF EXISTS (\n SELECT 1 FROM information_schema.tables\n WHERE table_name = 'emt_projections'\n ) AND NOT EXISTS (\n SELECT 1 FROM information_schema.columns\n WHERE table_name = 'emt_projections' AND column_name = 'created_at'\n ) THEN\n ALTER TABLE emt_projections ADD COLUMN created_at TIMESTAMPTZ NOT NULL DEFAULT now();\n END IF;\n\n IF EXISTS (\n SELECT 1 FROM information_schema.tables\n WHERE table_name = 'emt_projections'\n ) AND NOT EXISTS (\n SELECT 1 FROM information_schema.columns\n WHERE table_name = 'emt_projections' AND column_name = 'last_updated'\n ) THEN\n ALTER TABLE emt_projections ADD COLUMN last_updated TIMESTAMPTZ NOT NULL DEFAULT now();\n END IF;\nEND $$;\n\nCREATE OR REPLACE FUNCTION emt_try_acquire_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_version INT,\n p_partition TEXT DEFAULT '${SQL.plain(defaultTag)}',\n p_processor_instance_id TEXT DEFAULT 'emt:unknown',\n p_projection_name TEXT DEFAULT NULL,\n p_projection_type VARCHAR(1) DEFAULT NULL,\n p_projection_kind TEXT DEFAULT NULL,\n p_lock_timeout_seconds INT DEFAULT 300\n)\nRETURNS TABLE (acquired BOOLEAN, checkpoint TEXT)\nLANGUAGE plpgsql\nAS $emt_try_acquire_processor_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n ownership_check AS (\n INSERT INTO emt_processors (\n processor_id,\n partition,\n version,\n processor_instance_id,\n status,\n last_processed_checkpoint,\n last_processed_transaction_id,\n created_at,\n last_updated\n )\n SELECT p_processor_id, p_partition, p_version, p_processor_instance_id, 'running', '0000000000000000000', '0'::xid8, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (processor_id, partition, version) DO UPDATE\n SET processor_instance_id = p_processor_instance_id,\n status = 'running',\n last_updated = now()\n WHERE emt_processors.processor_instance_id = p_processor_instance_id\n OR emt_processors.processor_instance_id = 'emt:unknown'\n OR emt_processors.status = 'stopped'\n OR emt_processors.last_updated < now() - (p_lock_timeout_seconds || ' seconds')::interval\n RETURNING last_processed_checkpoint\n ),\n projection_status AS (\n INSERT INTO emt_projections (\n name,\n partition,\n version,\n type,\n kind,\n status,\n definition\n )\n SELECT p_projection_name, p_partition, p_version, p_projection_type, p_projection_kind, 'async_processing', '{}'::jsonb\n WHERE p_projection_name IS NOT NULL\n AND (SELECT last_processed_checkpoint FROM ownership_check) IS NOT NULL\n ON CONFLICT (name, partition, version) DO UPDATE\n SET status = 'async_processing'\n RETURNING name\n )\n SELECT\n (SELECT COUNT(*) > 0 FROM ownership_check),\n (SELECT oc.last_processed_checkpoint FROM ownership_check oc);\nEND;\n$emt_try_acquire_processor_lock$;\n\nCREATE OR REPLACE FUNCTION emt_release_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_partition TEXT,\n p_version INT,\n p_processor_instance_id TEXT DEFAULT 'emt:unknown',\n p_projection_name TEXT DEFAULT NULL\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_release_processor_lock$\nDECLARE\n v_rows_updated INT;\nBEGIN\n IF p_projection_name IS NOT NULL THEN\n UPDATE emt_projections\n SET status = 'active',\n last_updated = now()\n WHERE partition = p_partition\n AND name = p_projection_name\n AND version = p_version;\n END IF;\n\n UPDATE emt_processors\n SET status = 'stopped',\n processor_instance_id = 'emt:unknown',\n last_updated = now()\n WHERE processor_id = p_processor_id\n AND partition = p_partition\n AND version = p_version\n AND processor_instance_id = p_processor_instance_id;\n\n GET DIAGNOSTICS v_rows_updated = ROW_COUNT;\n\n PERFORM pg_advisory_unlock(p_lock_key);\n\n RETURN v_rows_updated > 0;\nEND;\n$emt_release_processor_lock$;\n\nCREATE OR REPLACE FUNCTION emt_try_acquire_projection_lock(\n p_lock_key BIGINT,\n p_partition TEXT,\n p_name TEXT,\n p_version INT\n)\nRETURNS TABLE (acquired BOOLEAN, is_active BOOLEAN)\nLANGUAGE plpgsql\nAS $emt_try_acquire_projection_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock_shared(p_lock_key) AS acquired\n ),\n status_check AS (\n SELECT status = 'active' AS is_active\n FROM emt_projections\n WHERE partition = p_partition AND name = p_name AND version = p_version\n )\n SELECT\n COALESCE((SELECT lc.acquired FROM lock_check lc), false),\n COALESCE((SELECT sc.is_active FROM status_check sc), true);\nEND;\n$emt_try_acquire_projection_lock$;\n\nCREATE OR REPLACE FUNCTION emt_register_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT,\n p_type VARCHAR(1),\n p_kind TEXT,\n p_status TEXT,\n p_definition JSONB\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_register_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n upsert_result AS (\n INSERT INTO emt_projections (\n name, partition, version, type, kind, status, definition, created_at, last_updated\n )\n SELECT p_name, p_partition, p_version, p_type, p_kind, p_status, p_definition, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (name, partition, version) DO UPDATE\n SET definition = EXCLUDED.definition,\n last_updated = now()\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM upsert_result;\n\n RETURN v_result;\nEND;\n$emt_register_projection$;\n\nCREATE OR REPLACE FUNCTION emt_activate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_activate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE emt_projections\n SET status = 'active',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_activate_projection$;\n\nCREATE OR REPLACE FUNCTION emt_deactivate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_deactivate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE emt_projections\n SET status = 'inactive',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_deactivate_projection$;\n`;\n\nexport const migration_0_42_0_2_AddProcessorProjectionFunctions: SQLMigration =\n sqlMigration(\n 'emt:postgresql:eventstore:0.42.0-2:add-processor-projection-functions',\n [migration_0_42_0_2_AddProcessorProjectionFunctionsSQL],\n );\n","import { SQL } from '@event-driven-io/dumbo';\n\nexport const schema_0_42_0 = SQL`\n CREATE TABLE IF NOT EXISTS emt_streams(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\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, partition, is_archived)\n ) PARTITION BY LIST (partition);\n \n CREATE UNIQUE INDEX IF NOT EXISTS idx_streams_unique \n ON emt_streams(stream_id, partition, is_archived) \n INCLUDE (stream_position);\n CREATE SEQUENCE IF NOT EXISTS emt_global_message_position;\n\n CREATE TABLE IF NOT EXISTS emt_messages(\n stream_position BIGINT NOT NULL,\n global_position BIGINT DEFAULT nextval('emt_global_message_position'),\n transaction_id XID8 NOT NULL,\n created TIMESTAMPTZ NOT NULL DEFAULT now(),\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n message_kind VARCHAR(1) NOT NULL DEFAULT 'E',\n stream_id TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\n message_schema_version TEXT NOT NULL,\n message_id TEXT NOT NULL,\n message_type TEXT NOT NULL,\n message_data JSONB NOT NULL,\n message_metadata JSONB NOT NULL,\n PRIMARY KEY (stream_id, stream_position, partition, is_archived)\n ) PARTITION BY LIST (partition);\n CREATE TABLE IF NOT EXISTS emt_projections(\n version INT NOT NULL DEFAULT 1,\n type VARCHAR(1) NOT NULL,\n name TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\n kind TEXT NOT NULL,\n status TEXT NOT NULL,\n definition JSONB NOT NULL DEFAULT '{}'::jsonb,\n created_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (name, partition, version)\n ) PARTITION BY LIST (partition);\n\n CREATE TABLE IF NOT EXISTS emt_processors(\n last_processed_transaction_id XID8 NOT NULL,\n version INT NOT NULL DEFAULT 1,\n processor_id TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\n status TEXT NOT NULL DEFAULT 'stopped',\n last_processed_checkpoint TEXT NOT NULL,\n processor_instance_id TEXT DEFAULT 'emt:unknown',\n created_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (processor_id, partition, version)\n ) PARTITION BY LIST (partition);\n\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_sanitize_name') THEN\n CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $emt_sanitize_name$\n BEGIN\n RETURN REGEXP_REPLACE(input_name, '[^a-zA-Z0-9_]', '_', 'g');\n END;\n $emt_sanitize_name$ LANGUAGE plpgsql;\nEND IF;\nEND $$;\n\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_add_table_partition') THEN\n \n CREATE OR REPLACE FUNCTION emt_add_table_partition(tableName TEXT, partition_name TEXT) RETURNS void AS $emt_add_table_partition$\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\n -- create default 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 $emt_add_table_partition$ LANGUAGE plpgsql;\nEND IF;\nEND $$;\n\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_add_partition') THEN\n \n CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $emt_add_partition$\n BEGIN \n PERFORM emt_add_table_partition('emt_messages', partition_name);\n PERFORM emt_add_table_partition('emt_streams', partition_name);\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_processors' || '_' || partition_name), 'emt_processors', partition_name\n );\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_projections' || '_' || partition_name), 'emt_projections', partition_name\n );\n END;\n $emt_add_partition$ LANGUAGE plpgsql;\nEND IF;\nEND $$;\n\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_append_to_stream') THEN\n CREATE OR REPLACE FUNCTION emt_append_to_stream(\n v_message_ids text[],\n v_messages_data jsonb[],\n v_messages_metadata jsonb[],\n v_message_schema_versions text[],\n v_message_types text[],\n v_message_kinds 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 global_positions bigint[],\n transaction_id xid8\n ) LANGUAGE plpgsql\n AS $emt_append_to_stream$\n DECLARE\n v_next_stream_position bigint;\n v_position bigint;\n v_updated_rows int;\n v_transaction_id xid8;\n v_global_positions bigint[];\n BEGIN\n v_transaction_id := pg_current_xact_id();\n\n IF v_expected_stream_position IS NULL THEN\n SELECT COALESCE(\n (SELECT stream_position \n FROM emt_streams\n WHERE stream_id = v_stream_id \n AND partition = v_partition \n AND is_archived = FALSE\n LIMIT 1), \n 0\n ) INTO v_expected_stream_position;\n END IF;\n\n v_next_stream_position := v_expected_stream_position + array_upper(v_messages_data, 1);\n\n IF v_expected_stream_position = 0 THEN\n INSERT INTO emt_streams\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 emt_streams 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 WITH ev AS (\n SELECT row_number() OVER () + v_expected_stream_position AS stream_position, \n message_data, \n message_metadata, \n schema_version, \n message_id, \n message_type,\n message_kind\n FROM (\n SELECT *\n FROM \n unnest(v_message_ids, v_messages_data, v_messages_metadata, v_message_schema_versions, v_message_types, v_message_kinds) \n AS message(message_id, message_data, message_metadata, schema_version, message_type, message_kind)\n ) AS message\n ),\n all_messages_insert AS (\n INSERT INTO emt_messages\n (stream_id, stream_position, partition, message_data, message_metadata, message_schema_version, message_type, message_kind, message_id, transaction_id)\n SELECT \n v_stream_id, ev.stream_position, v_partition, ev.message_data, ev.message_metadata, ev.schema_version, ev.message_type, ev.message_kind, ev.message_id, v_transaction_id\n FROM ev\n RETURNING global_position\n )\n SELECT \n array_agg(global_position ORDER BY global_position) INTO v_global_positions\n FROM \n all_messages_insert;\n\n RETURN QUERY SELECT TRUE, v_next_stream_position, v_global_positions, v_transaction_id;\n END;\n $emt_append_to_stream$;\n \nEND IF;\nEND $$;\nSELECT emt_add_partition('emt:default');\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'store_processor_checkpoint') THEN\n \nCREATE OR REPLACE FUNCTION store_processor_checkpoint(\n p_processor_id TEXT,\n p_version BIGINT,\n p_position TEXT,\n p_check_position TEXT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT 'emt:default',\n p_processor_instance_id TEXT DEFAULT 'emt:unknown'\n) RETURNS INT AS $spc$\nDECLARE\n current_position TEXT;\nBEGIN\n -- Handle the case when p_check_position is provided\n IF p_check_position IS NOT NULL THEN\n -- Try to update if the position matches p_check_position\n UPDATE \"emt_processors\"\n SET\n \"last_processed_checkpoint\" = p_position,\n \"last_processed_transaction_id\" = p_transaction_id,\n \"last_updated\" = now()\n WHERE \"processor_id\" = p_processor_id\n AND \"last_processed_checkpoint\" = p_check_position\n AND \"partition\" = p_partition\n AND \"version\" = p_version;\n\n IF FOUND THEN\n RETURN 1; -- Successfully updated\n END IF;\n\n -- Retrieve the current position\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n -- Return appropriate codes based on current position\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSIF current_position > p_position THEN\n RETURN 3; -- Current ahead: another process has progressed further\n ELSE\n RETURN 2; -- Mismatch: check position doesn't match current\n END IF;\n END IF;\n\n -- Handle the case when p_check_position is NULL: Insert if not exists\n BEGIN\n INSERT INTO \"emt_processors\"(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"created_at\", \"last_updated\")\n VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());\n RETURN 1; -- Successfully inserted\n EXCEPTION WHEN unique_violation THEN\n -- If insertion failed, it means the row already exists\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSIF current_position > p_position THEN\n RETURN 3; -- Current ahead: another process has progressed further\n ELSE\n RETURN 2; -- Insertion failed, row already exists with different position\n END IF;\n END;\nEND;\n$spc$ LANGUAGE plpgsql;\n\nEND IF;\nEND $$;\n\nCREATE OR REPLACE FUNCTION emt_try_acquire_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_version INT,\n p_partition TEXT DEFAULT 'emt:default',\n p_processor_instance_id TEXT DEFAULT 'emt:unknown',\n p_projection_name TEXT DEFAULT NULL,\n p_projection_type VARCHAR(1) DEFAULT NULL,\n p_projection_kind TEXT DEFAULT NULL,\n p_lock_timeout_seconds INT DEFAULT 300\n)\nRETURNS TABLE (acquired BOOLEAN, checkpoint TEXT)\nLANGUAGE plpgsql\nAS $emt_try_acquire_processor_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n ownership_check AS (\n INSERT INTO emt_processors (\n processor_id,\n partition,\n version,\n processor_instance_id,\n status,\n last_processed_checkpoint,\n last_processed_transaction_id,\n created_at,\n last_updated\n )\n SELECT p_processor_id, p_partition, p_version, p_processor_instance_id, 'running', '0000000000000000000', '0'::xid8, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (processor_id, partition, version) DO UPDATE\n SET processor_instance_id = p_processor_instance_id,\n status = 'running',\n last_updated = now()\n WHERE emt_processors.processor_instance_id = p_processor_instance_id\n OR emt_processors.processor_instance_id = 'emt:unknown'\n OR emt_processors.status = 'stopped'\n OR emt_processors.last_updated < now() - (p_lock_timeout_seconds || ' seconds')::interval\n RETURNING last_processed_checkpoint\n ),\n projection_status AS (\n INSERT INTO emt_projections (\n name,\n partition,\n version,\n type,\n kind,\n status,\n definition\n )\n SELECT p_projection_name, p_partition, p_version, p_projection_type, p_projection_kind, 'async_processing', '{}'::jsonb\n WHERE p_projection_name IS NOT NULL\n AND (SELECT last_processed_checkpoint FROM ownership_check) IS NOT NULL\n ON CONFLICT (name, partition, version) DO UPDATE\n SET status = 'async_processing'\n RETURNING name\n )\n SELECT\n (SELECT COUNT(*) > 0 FROM ownership_check),\n (SELECT oc.last_processed_checkpoint FROM ownership_check oc);\nEND;\n$emt_try_acquire_processor_lock$;\n\nCREATE OR REPLACE FUNCTION emt_release_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_partition TEXT,\n p_version INT,\n p_processor_instance_id TEXT DEFAULT 'emt:unknown',\n p_projection_name TEXT DEFAULT NULL\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_release_processor_lock$\nDECLARE\n v_rows_updated INT;\nBEGIN\n IF p_projection_name IS NOT NULL THEN\n UPDATE emt_projections\n SET status = 'active',\n last_updated = now()\n WHERE partition = p_partition\n AND name = p_projection_name\n AND version = p_version;\n END IF;\n\n UPDATE emt_processors\n SET status = 'stopped',\n processor_instance_id = 'emt:unknown',\n last_updated = now()\n WHERE processor_id = p_processor_id\n AND partition = p_partition\n AND version = p_version\n AND processor_instance_id = p_processor_instance_id;\n\n GET DIAGNOSTICS v_rows_updated = ROW_COUNT;\n\n PERFORM pg_advisory_unlock(p_lock_key);\n\n RETURN v_rows_updated > 0;\nEND;\n$emt_release_processor_lock$;\n\nCREATE OR REPLACE FUNCTION emt_try_acquire_projection_lock(\n p_lock_key BIGINT,\n p_partition TEXT,\n p_name TEXT,\n p_version INT\n)\nRETURNS TABLE (acquired BOOLEAN, is_active BOOLEAN)\nLANGUAGE plpgsql\nAS $emt_try_acquire_projection_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock_shared(p_lock_key) AS acquired\n ),\n status_check AS (\n SELECT status = 'active' AS is_active\n FROM emt_projections\n WHERE partition = p_partition AND name = p_name AND version = p_version\n )\n SELECT\n COALESCE((SELECT lc.acquired FROM lock_check lc), false),\n COALESCE((SELECT sc.is_active FROM status_check sc), true);\nEND;\n$emt_try_acquire_projection_lock$;\n\nCREATE OR REPLACE FUNCTION emt_register_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT,\n p_type VARCHAR(1),\n p_kind TEXT,\n p_status TEXT,\n p_definition JSONB\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_register_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n upsert_result AS (\n INSERT INTO emt_projections (\n name, partition, version, type, kind, status, definition, created_at, last_updated\n )\n SELECT p_name, p_partition, p_version, p_type, p_kind, p_status, p_definition, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (name, partition, version) DO UPDATE\n SET definition = EXCLUDED.definition,\n last_updated = now()\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM upsert_result;\n\n RETURN v_result;\nEND;\n$emt_register_projection$;\n\nCREATE OR REPLACE FUNCTION emt_activate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_activate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE emt_projections\n SET status = 'active',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_activate_projection$;\n\nCREATE OR REPLACE FUNCTION emt_deactivate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_deactivate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE emt_projections\n SET status = 'inactive',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_deactivate_projection$;\n`;\n","import { single, SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport type { ProcessorCheckpoint } from '@event-driven-io/emmett';\nimport { createFunctionIfDoesNotExistSQL } from './createFunctionIfDoesNotExist';\nimport { defaultTag, processorsTable, unknownTag } from './typing';\n\nexport const storeSubscriptionCheckpointSQL = createFunctionIfDoesNotExistSQL(\n 'store_processor_checkpoint',\n SQL`\nCREATE OR REPLACE FUNCTION store_processor_checkpoint(\n p_processor_id TEXT,\n p_version BIGINT,\n p_position TEXT,\n p_check_position TEXT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT '${SQL.plain(defaultTag)}',\n p_processor_instance_id TEXT DEFAULT '${SQL.plain(unknownTag)}'\n) RETURNS INT AS $spc$\nDECLARE\n current_position TEXT;\nBEGIN\n -- Handle the case when p_check_position is provided\n IF p_check_position IS NOT NULL THEN\n -- Try to update if the position matches p_check_position\n UPDATE \"${SQL.plain(processorsTable.name)}\"\n SET\n \"last_processed_checkpoint\" = p_position,\n \"last_processed_transaction_id\" = p_transaction_id,\n \"last_updated\" = now()\n WHERE \"processor_id\" = p_processor_id\n AND \"last_processed_checkpoint\" = p_check_position\n AND \"partition\" = p_partition\n AND \"version\" = p_version;\n\n IF FOUND THEN\n RETURN 1; -- Successfully updated\n END IF;\n\n -- Retrieve the current position\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"${SQL.plain(processorsTable.name)}\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n -- Return appropriate codes based on current position\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSIF current_position > p_position THEN\n RETURN 3; -- Current ahead: another process has progressed further\n ELSE\n RETURN 2; -- Mismatch: check position doesn't match current\n END IF;\n END IF;\n\n -- Handle the case when p_check_position is NULL: Insert if not exists\n BEGIN\n INSERT INTO \"${SQL.plain(processorsTable.name)}\"(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"created_at\", \"last_updated\")\n VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());\n RETURN 1; -- Successfully inserted\n EXCEPTION WHEN unique_violation THEN\n -- If insertion failed, it means the row already exists\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"${SQL.plain(processorsTable.name)}\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSIF current_position > p_position THEN\n RETURN 3; -- Current ahead: another process has progressed further\n ELSE\n RETURN 2; -- Insertion failed, row already exists with different position\n END IF;\n END;\nEND;\n$spc$ LANGUAGE plpgsql;\n`,\n);\n\ntype CallStoreProcessorCheckpointParams = {\n processorId: string;\n version: number;\n position: string | null;\n checkPosition: string | null;\n partition: string;\n processorInstanceId: string;\n};\n\nexport const callStoreProcessorCheckpoint = (\n params: CallStoreProcessorCheckpointParams,\n) =>\n SQL`\n SELECT store_processor_checkpoint(\n ${params.processorId}, \n ${params.version}, \n ${params.position}, \n ${params.checkPosition}, \n pg_current_xact_id(), \n ${params.partition}, \n ${params.processorInstanceId}\n ) as result;`;\n\nexport type StoreProcessorCheckpointResult =\n | {\n success: true;\n newCheckpoint: ProcessorCheckpoint | null;\n }\n | { success: false; reason: 'IGNORED' | 'MISMATCH' | 'CURRENT_AHEAD' };\n\nexport const storeProcessorCheckpoint = async (\n execute: SQLExecutor,\n options: {\n processorId: string;\n version: number | undefined;\n newCheckpoint: ProcessorCheckpoint | null;\n lastProcessedCheckpoint: ProcessorCheckpoint | null;\n partition?: string;\n processorInstanceId?: string;\n },\n): Promise<StoreProcessorCheckpointResult> => {\n try {\n const { result } = await single(\n execute.command<{ result: 0 | 1 | 2 | 3 }>(\n callStoreProcessorCheckpoint({\n processorId: options.processorId,\n version: options.version ?? 1,\n position:\n options.newCheckpoint !== null ? options.newCheckpoint : null,\n checkPosition:\n options.lastProcessedCheckpoint !== null\n ? options.lastProcessedCheckpoint\n : null,\n partition: options.partition ?? defaultTag,\n processorInstanceId: options.processorInstanceId ?? unknownTag,\n }),\n ),\n );\n\n return result === 1\n ? { success: true, newCheckpoint: options.newCheckpoint }\n : {\n success: false,\n reason:\n result === 0\n ? 'IGNORED'\n : result === 3\n ? 'CURRENT_AHEAD'\n : 'MISMATCH',\n };\n } catch (error) {\n console.log(error);\n throw error;\n }\n};\n","import {\n dumbo,\n SQL,\n sqlMigration,\n type SQLMigration,\n} from '@event-driven-io/dumbo';\nimport {\n defaultTag,\n messagesTable,\n processorsTable,\n projectionsTable,\n streamsTable,\n} from '../../typing';\n\nexport const migration_0_43_0_cleanupLegacySubscriptionSQL = SQL`\nDO $$\nBEGIN\nIF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'emt_subscriptions') THEN\n -- Restore clean emt_add_partition (remove creation of emt_subscriptions partitions)\n CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $fnpar$\n BEGIN \n PERFORM emt_add_table_partition('${SQL.plain(messagesTable.name)}', partition_name);\n PERFORM emt_add_table_partition('${SQL.plain(streamsTable.name)}', partition_name);\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('${SQL.plain(processorsTable.name)}' || '_' || partition_name), '${SQL.plain(processorsTable.name)}', partition_name\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('${SQL.plain(projectionsTable.name)}' || '_' || partition_name), '${SQL.plain(projectionsTable.name)}', partition_name\n );\n END;\n $fnpar$ LANGUAGE plpgsql;\n\n -- Drop old subscriptions table if it exists\n DROP TABLE IF EXISTS emt_subscriptions CASCADE;\n\n -- Drop old function if it exists\n DROP FUNCTION IF EXISTS store_subscription_checkpoint(character varying, bigint, bigint, bigint, xid8, text);\n \n -- Restore clean store_processor_checkpoint (remove dual-write logic)\n CREATE OR REPLACE FUNCTION store_processor_checkpoint(\n p_processor_id TEXT,\n p_version BIGINT,\n p_position TEXT,\n p_check_position TEXT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT '${SQL.plain(defaultTag)}',\n p_processor_instance_id TEXT DEFAULT 'emt:unknown'\n ) RETURNS INT AS $fn$\n DECLARE\n current_position TEXT;\n BEGIN\n IF p_check_position IS NOT NULL THEN\n UPDATE \"emt_processors\"\n SET\n \"last_processed_checkpoint\" = p_position,\n \"last_processed_transaction_id\" = p_transaction_id,\n \"last_updated\" = now()\n WHERE \"processor_id\" = p_processor_id\n AND \"last_processed_checkpoint\" = p_check_position\n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF FOUND THEN\n RETURN 1;\n END IF;\n\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version ;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSIF current_position > p_position THEN\n RETURN 3;\n ELSE\n RETURN 2;\n END IF;\n END IF;\n\n BEGIN\n INSERT INTO \"emt_processors\"(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"created_at\", \"last_updated\")\n VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());\n RETURN 1;\n EXCEPTION WHEN unique_violation THEN\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition\n AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSE\n RETURN 2;\n END IF;\n END;\n END;\n $fn$ LANGUAGE plpgsql;\nEND IF;\nEND $$;\n`;\n\nexport const migration_0_43_0_cleanupLegacySubscription: SQLMigration =\n sqlMigration('emt:postgresql:eventstore:0.43.0:cleanup-legacy-subscription', [\n migration_0_43_0_cleanupLegacySubscriptionSQL,\n ]);\n\nexport const cleanupLegacySubscriptionTables = async (\n connectionString: string,\n) => {\n const pool = dumbo({ connectionString });\n\n try {\n await pool.withTransaction(async ({ execute }) => {\n await execute.command(migration_0_43_0_cleanupLegacySubscriptionSQL);\n });\n } finally {\n await pool.close();\n }\n};\n","import { SQL } from '@event-driven-io/dumbo';\nimport {\n defaultTag,\n globalTag,\n messagesTable,\n processorsTable,\n projectionsTable,\n streamsTable,\n unknownTag,\n} from './typing';\n\nimport { createFunctionIfDoesNotExistSQL } from './createFunctionIfDoesNotExist';\nimport { cleanupLegacySubscriptionTables } from './migrations/0_43_0';\nexport { cleanupLegacySubscriptionTables };\n\nexport const streamsTableSQL = SQL`\n CREATE TABLE IF NOT EXISTS ${SQL.identifier(streamsTable.name)}(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${SQL.plain(defaultTag)}',\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, partition, is_archived)\n ) PARTITION BY LIST (partition);\n \n CREATE UNIQUE INDEX IF NOT EXISTS idx_streams_unique \n ON ${SQL.identifier(streamsTable.name)}(stream_id, partition, is_archived) \n INCLUDE (stream_position);`;\n\nexport const messagesTableSQL = SQL`\n CREATE SEQUENCE IF NOT EXISTS emt_global_message_position;\n\n CREATE TABLE IF NOT EXISTS ${SQL.identifier(messagesTable.name)}(\n stream_position BIGINT NOT NULL,\n global_position BIGINT DEFAULT nextval('emt_global_message_position'),\n transaction_id XID8 NOT NULL,\n created TIMESTAMPTZ NOT NULL DEFAULT now(),\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n message_kind VARCHAR(1) NOT NULL DEFAULT 'E',\n stream_id TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${SQL.plain(defaultTag)}',\n message_schema_version TEXT NOT NULL,\n message_id TEXT NOT NULL,\n message_type TEXT NOT NULL,\n message_data JSONB NOT NULL,\n message_metadata JSONB NOT NULL,\n PRIMARY KEY (stream_id, stream_position, partition, is_archived)\n ) PARTITION BY LIST (partition);`;\n\nexport const processorsTableSQL = SQL`\n CREATE TABLE IF NOT EXISTS ${SQL.identifier(processorsTable.name)}(\n last_processed_transaction_id XID8 NOT NULL,\n version INT NOT NULL DEFAULT 1,\n processor_id TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${SQL.plain(defaultTag)}',\n status TEXT NOT NULL DEFAULT 'stopped',\n last_processed_checkpoint TEXT NOT NULL,\n processor_instance_id TEXT DEFAULT '${SQL.plain(unknownTag)}',\n created_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (processor_id, partition, version)\n ) PARTITION BY LIST (partition);\n`;\n\nexport const projectionsTableSQL = SQL`\n CREATE TABLE IF NOT EXISTS ${SQL.identifier(projectionsTable.name)}(\n version INT NOT NULL DEFAULT 1,\n type VARCHAR(1) NOT NULL,\n name TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${SQL.plain(defaultTag)}',\n kind TEXT NOT NULL,\n status TEXT NOT NULL,\n definition JSONB NOT NULL DEFAULT '{}'::jsonb,\n created_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (name, partition, version)\n ) PARTITION BY LIST (partition);\n`;\n\nexport const sanitizeNameSQL = createFunctionIfDoesNotExistSQL(\n 'emt_sanitize_name',\n SQL`CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $emt_sanitize_name$\n BEGIN\n RETURN REGEXP_REPLACE(input_name, '[^a-zA-Z0-9_]', '_', 'g');\n END;\n $emt_sanitize_name$ LANGUAGE plpgsql;`,\n);\n\nexport const addTablePartitions = createFunctionIfDoesNotExistSQL(\n 'emt_add_table_partition',\n SQL`\n CREATE OR REPLACE FUNCTION emt_add_table_partition(tableName TEXT, partition_name TEXT) RETURNS void AS $emt_add_table_partition$\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\n -- create default 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 $emt_add_table_partition$ LANGUAGE plpgsql;`,\n);\n\nexport const addPartitionSQL = createFunctionIfDoesNotExistSQL(\n 'emt_add_partition',\n SQL`\n CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $emt_add_partition$\n BEGIN \n PERFORM emt_add_table_partition('${SQL.plain(messagesTable.name)}', partition_name);\n PERFORM emt_add_table_partition('${SQL.plain(streamsTable.name)}', partition_name);\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('${SQL.plain(processorsTable.name)}' || '_' || partition_name), '${SQL.plain(processorsTable.name)}', partition_name\n );\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('${SQL.plain(projectionsTable.name)}' || '_' || partition_name), '${SQL.plain(projectionsTable.name)}', partition_name\n );\n END;\n $emt_add_partition$ LANGUAGE plpgsql;`,\n);\n\nexport const addModuleSQL = SQL`\n CREATE OR REPLACE FUNCTION add_module(new_module TEXT) RETURNS void AS $$\n BEGIN\n -- For ${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}'), '${SQL.plain(messagesTable.name)}', new_module, '${SQL.plain(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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}' || '_active'), emt_sanitize_name('${SQL.plain(messagesTable.name)}_' || new_module || '__' || '${SQL.plain(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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}' || '_archived'), emt_sanitize_name('${SQL.plain(messagesTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}')\n );\n \n -- For ${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}'), '${SQL.plain(streamsTable.name)}', new_module, '${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}' || '_active'), emt_sanitize_name('${SQL.plain(streamsTable.name)}_' || new_module || '__' || '${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}' || '_archived'), emt_sanitize_name('${SQL.plain(streamsTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}')\n );\n END;\n $$ LANGUAGE plpgsql;\n `;\n\nexport const addTenantSQL = SQL`\n CREATE OR REPLACE FUNCTION add_tenant(new_module TEXT, new_tenant TEXT) RETURNS void AS $$\n BEGIN\n -- For ${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant), '${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant)\n );\n \n -- For ${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant), '${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant)\n );\n END;\n $$ LANGUAGE plpgsql;\n `;\n\nexport const addModuleForAllTenantsSQL = SQL`\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 ${SQL.plain(messagesTable.name)}\n LOOP\n -- For ${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant), '${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant)\n );\n \n -- For ${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant), '${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant)\n );\n END LOOP;\n END;\n $$ LANGUAGE plpgsql;\n `;\n\nexport const addTenantForAllModulesSQL = SQL`\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 = '${SQL.plain(messagesTable.name)}'\n LOOP\n -- For ${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant), '${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant)\n );\n \n -- For ${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant), '${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant)\n );\n END LOOP;\n END;\n $$ LANGUAGE plpgsql;\n `;\n\nexport const addDefaultPartitionSQL = SQL`SELECT emt_add_partition('${SQL.plain(defaultTag)}');`;\n","import { singleOrNull, SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport type { ProcessorCheckpoint } from '@event-driven-io/emmett';\nimport { defaultTag, processorsTable } from './typing';\n\ntype ReadProcessorCheckpointSqlResult = {\n last_processed_checkpoint: string;\n};\n\nexport type ReadProcessorCheckpointResult = {\n lastProcessedCheckpoint: ProcessorCheckpoint | null;\n};\n\nexport const readProcessorCheckpoint = async (\n execute: SQLExecutor,\n options: { processorId: string; partition?: string; version?: number },\n): Promise<ReadProcessorCheckpointResult> => {\n const result = await singleOrNull(\n execute.query<ReadProcessorCheckpointSqlResult>(\n SQL`SELECT last_processed_checkpoint\n FROM ${SQL.identifier(processorsTable.name)}\n WHERE partition = ${options?.partition ?? defaultTag} AND processor_id = ${options.processorId} AND version = ${options.version ?? 1}\n LIMIT 1`,\n ),\n );\n\n return {\n lastProcessedCheckpoint:\n result !== null\n ? (result.last_processed_checkpoint as ProcessorCheckpoint)\n : null,\n };\n};\n","import { mapRows, SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n bigIntProcessorCheckpoint,\n upcastRecordedMessage,\n type CombinedReadEventMetadata,\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 { PostgreSQLEventStoreDefaultStreamVersion } from '../postgreSQLEventStore';\nimport { defaultTag, messagesTable } from './typing';\n\ntype ReadStreamSqlResult<EventType extends Event> = {\n stream_position: string;\n message_data: EventDataOf<EventType>;\n message_metadata: EventMetaDataOf<EventType>;\n message_schema_version: string;\n message_type: EventTypeOf<EventType>;\n message_id: string;\n global_position: string;\n transaction_id: string;\n created: string;\n};\n\nexport const readStream = async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>(\n execute: SQLExecutor,\n streamId: string,\n options?: ReadStreamOptions<EventType, EventPayloadType> & {\n partition?: string;\n },\n): Promise<\n ReadStreamResult<EventType, ReadEventMetadataWithGlobalPosition>\n> => {\n const fromCondition: string = options?.from\n ? `AND stream_position >= ${options.from}`\n : '';\n\n const to = Number(\n options?.to ??\n (options?.maxCount ? (options.from ?? 0n) + options.maxCount : 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<EventPayloadType>>(\n SQL`SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id\n FROM ${SQL.identifier(messagesTable.name)}\n WHERE stream_id = ${streamId} AND partition = ${options?.partition ?? defaultTag} AND is_archived = FALSE ${SQL.plain(fromCondition)} ${SQL.plain(toCondition)}\n ORDER BY stream_position ASC`,\n ),\n (row) => {\n const rawEvent = {\n type: row.message_type,\n data: row.message_data,\n metadata: row.message_metadata,\n } as unknown as EventPayloadType;\n\n const metadata: ReadEventMetadataWithGlobalPosition = {\n ...('metadata' in rawEvent ? (rawEvent.metadata ?? {}) : {}),\n messageId: row.message_id,\n streamName: streamId,\n streamPosition: BigInt(row.stream_position),\n globalPosition: BigInt(row.global_position),\n checkpoint: bigIntProcessorCheckpoint(BigInt(row.global_position)),\n };\n\n const event = {\n ...rawEvent,\n kind: 'Event',\n metadata: metadata as CombinedReadEventMetadata<\n EventPayloadType,\n ReadEventMetadataWithGlobalPosition\n >,\n };\n\n return upcastRecordedMessage(event, options?.schema?.versioning);\n },\n );\n\n return events.length > 0\n ? {\n currentStreamVersion:\n events[events.length - 1]!.metadata.streamPosition,\n events,\n streamExists: true,\n }\n : {\n currentStreamVersion: PostgreSQLEventStoreDefaultStreamVersion,\n events: [],\n streamExists: false,\n };\n};\n","import { SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport type { StreamExistsResult } from '@event-driven-io/emmett';\nimport { defaultTag, streamsTable } from './typing';\n\ntype StreamExistsSqlResult = { exists: boolean };\n\nexport type PostgresStreamExistsOptions = { partition: string };\n\nexport const streamExists = async (\n execute: SQLExecutor,\n streamId: string,\n options?: PostgresStreamExistsOptions,\n): Promise<StreamExistsResult> => {\n const queryResult = await execute.query<StreamExistsSqlResult>(\n SQL`SELECT EXISTS (\n SELECT 1\n from ${SQL.identifier(streamsTable.name)}\n WHERE stream_id = ${streamId} AND partition = ${options?.partition ?? defaultTag} AND is_archived = FALSE)\n `,\n );\n\n return queryResult.rows[0]?.exists ?? false;\n};\n","import {\n dumbo,\n runSQLMigrations,\n sqlMigration,\n type Dumbo,\n type RunSQLMigrationsResult,\n type SQL,\n type SQLMigration,\n} from '@event-driven-io/dumbo';\nimport type { PgPool, PgTransaction } from '@event-driven-io/dumbo/pg';\nimport type { JSONSerializationOptions } from '@event-driven-io/emmett';\nimport type { PostgresEventStoreOptions } from '../postgreSQLEventStore';\nimport { transactionToPostgreSQLProjectionHandlerContext } from '../projections';\nimport { appendToStreamSQL } from './appendToStream';\nimport { migration_0_38_7_and_older } from './migrations/0_38_7';\nimport {\n migration_0_42_0_2_AddProcessorProjectionFunctions,\n migration_0_42_0_FromSubscriptionsToProcessors,\n} from './migrations/0_42_0';\nimport {\n releaseProcessorLockSQL,\n tryAcquireProcessorLockSQL,\n} from './processors';\nimport {\n activateProjectionSQL,\n deactivateProjectionSQL,\n registerProjectionSQL,\n} from './projections';\nimport { storeSubscriptionCheckpointSQL } from './storeProcessorCheckpoint';\nimport {\n addDefaultPartitionSQL,\n addPartitionSQL,\n addTablePartitions,\n messagesTableSQL,\n processorsTableSQL,\n projectionsTableSQL,\n sanitizeNameSQL,\n streamsTableSQL,\n} from './tables';\nexport * from './typing';\n\nexport * from './appendToStream';\nexport * from './migrations';\nexport * from './processors';\nexport * from './projections';\nexport * from './readLastMessageGlobalPosition';\nexport * from './readMessagesBatch';\nexport * from './readProcessorCheckpoint';\nexport * from './readStream';\nexport * from './storeProcessorCheckpoint';\nexport * from './streamExists';\nexport * from './tables';\n\nexport const schemaSQL: SQL[] = [\n streamsTableSQL,\n messagesTableSQL,\n projectionsTableSQL,\n processorsTableSQL,\n sanitizeNameSQL,\n addTablePartitions,\n addPartitionSQL,\n appendToStreamSQL,\n addDefaultPartitionSQL,\n storeSubscriptionCheckpointSQL,\n tryAcquireProcessorLockSQL,\n releaseProcessorLockSQL,\n registerProjectionSQL,\n activateProjectionSQL,\n deactivateProjectionSQL,\n];\n\nexport const schemaMigration = sqlMigration(\n 'emt:postgresql:eventstore:initial',\n schemaSQL,\n);\n\nexport const eventStoreSchemaMigrations: SQLMigration[] = [\n migration_0_38_7_and_older,\n migration_0_42_0_FromSubscriptionsToProcessors,\n migration_0_42_0_2_AddProcessorProjectionFunctions,\n schemaMigration,\n];\n\nexport type CreateEventStoreSchemaOptions = {\n dryRun?: boolean | undefined;\n ignoreMigrationHashMismatch?: boolean | undefined;\n migrationTimeoutMs?: number | undefined;\n} & JSONSerializationOptions;\n\nexport type EventStoreSchemaMigrationOptions = {\n migrationOptions?: CreateEventStoreSchemaOptions;\n};\n\nexport const createEventStoreSchema = (\n connectionString: string,\n pool: PgPool,\n hooks?: PostgresEventStoreOptions['hooks'],\n options?: CreateEventStoreSchemaOptions,\n): Promise<RunSQLMigrationsResult> => {\n return pool.withTransaction(async (tx: PgTransaction) => {\n const context = await transactionToPostgreSQLProjectionHandlerContext(\n connectionString,\n pool as Dumbo,\n tx,\n );\n const nestedPool = dumbo({\n connectionString,\n connection: tx.connection,\n serialization: options?.serialization,\n });\n\n try {\n if (hooks?.onBeforeSchemaCreated) {\n await hooks.onBeforeSchemaCreated(context);\n }\n\n const result = await runSQLMigrations(\n nestedPool,\n eventStoreSchemaMigrations,\n options,\n );\n\n if (hooks?.onAfterSchemaCreated) {\n await hooks.onAfterSchemaCreated(context);\n }\n return result;\n } finally {\n await nestedPool.close();\n }\n });\n};\n","import { SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n messagesTable,\n processorsTable,\n projectionsTable,\n streamsTable,\n} from './typing';\n\nexport const truncateTables = async (\n execute: SQLExecutor,\n options?: { resetSequences?: boolean },\n): Promise<void> => {\n await execute.command(\n SQL`TRUNCATE TABLE \n ${SQL.identifier(streamsTable.name)}, \n ${SQL.identifier(messagesTable.name)}, \n ${SQL.identifier(processorsTable.name)}, \n ${SQL.identifier(projectionsTable.name)} \n CASCADE${SQL.plain(options?.resetSequences ? '; ALTER SEQUENCE emt_global_message_position RESTART WITH 1' : '')};`,\n );\n};\n","import {\n dumbo,\n fromDatabaseDriverType,\n getFormatter,\n SQL,\n type MigrationStyle,\n type RunSQLMigrationsResult,\n} from '@event-driven-io/dumbo';\nimport type {\n PgClientConnection,\n PgConnection,\n PgDriverType,\n PgPool,\n PgPoolClientConnection,\n} from '@event-driven-io/dumbo/pg';\nimport {\n assertExpectedVersionMatchesCurrent,\n downcastRecordedMessages,\n ExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResultWithGlobalPosition,\n type Event,\n type EventStore,\n type EventStoreSession,\n type EventStoreSessionFactory,\n type JSONSerializationOptions,\n type ProjectionRegistration,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n type StreamExistsResult,\n} from '@event-driven-io/emmett';\nimport type pg from 'pg';\nimport {\n postgreSQLEventStoreConsumer,\n type PostgreSQLEventStoreConsumer,\n type PostgreSQLEventStoreConsumerConfig,\n} from './consumers';\nimport {\n handleProjections,\n transactionToPostgreSQLProjectionHandlerContext,\n type PostgreSQLProjectionHandlerContext,\n} from './projections';\nimport {\n appendToStream,\n createEventStoreSchema,\n readStream,\n schemaSQL,\n streamExists,\n unknownTag,\n type AppendToStreamBeforeCommitHook,\n type CreateEventStoreSchemaOptions,\n type PostgresStreamExistsOptions,\n} from './schema';\nimport { truncateTables } from './schema/truncateTables';\n\nexport interface PostgresEventStore\n extends\n EventStore<PostgresReadEventMetadata>,\n EventStoreSessionFactory<PostgresEventStore> {\n appendToStream<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResultWithGlobalPosition>;\n consumer<ConsumerEventType extends Event = Event>(\n options?: PostgreSQLEventStoreConsumerConfig<ConsumerEventType>,\n ): PostgreSQLEventStoreConsumer<ConsumerEventType>;\n close(): Promise<void>;\n streamExists(\n streamName: string,\n options?: PostgresStreamExistsOptions,\n ): Promise<StreamExistsResult>;\n schema: {\n sql(): string;\n print(): void;\n migrate(\n options?: CreateEventStoreSchemaOptions,\n ): Promise<RunSQLMigrationsResult>;\n dangerous: {\n truncate(options?: {\n resetSequences?: boolean;\n truncateProjections?: boolean;\n }): Promise<void>;\n };\n };\n}\n\nexport type PostgresReadEventMetadata = ReadEventMetadataWithGlobalPosition;\n\nexport type PostgresReadEvent<EventType extends Event = Event> = ReadEvent<\n EventType,\n PostgresReadEventMetadata\n>;\n\ntype PostgresEventStorePooledOptions =\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n pooled: true;\n pool: pg.Pool;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n pool: pg.Pool;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n pooled: true;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n };\n\ntype PostgresEventStoreNotPooledOptions =\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n pooled: false;\n client: pg.Client;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n client: pg.Client;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n pooled: false;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n connection: PgPoolClientConnection | PgClientConnection;\n pooled?: false;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n dumbo: PgPool;\n pooled?: false;\n };\n\nexport type PostgresEventStoreConnectionOptions =\n | PostgresEventStorePooledOptions\n | PostgresEventStoreNotPooledOptions;\n\nexport type PostgresEventStoreOptions = {\n projections?: ProjectionRegistration<\n 'inline',\n PostgresReadEventMetadata,\n PostgreSQLProjectionHandlerContext\n >[];\n schema?: { autoMigration?: MigrationStyle };\n connectionOptions?: PostgresEventStoreConnectionOptions;\n hooks?: {\n /**\n * This hook will be called **BEFORE** event store schema is created\n */\n onBeforeSchemaCreated?: (\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<void> | void;\n /**\n * This hook will be called **AFTER** event store schema was created but before transaction commits\n */\n onAfterSchemaCreated?: (\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<void> | void;\n };\n} & JSONSerializationOptions;\n\nexport const defaultPostgreSQLOptions: PostgresEventStoreOptions = {\n projections: [],\n schema: { autoMigration: 'CreateOrUpdate' },\n};\n\nexport const PostgreSQLEventStoreDefaultStreamVersion = 0n;\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 =\n 'dumbo' in poolOptions\n ? poolOptions.dumbo\n : dumbo({ ...poolOptions, serialization: options.serialization });\n let migrateSchema: Promise<RunSQLMigrationsResult> | undefined = undefined;\n\n const autoGenerateSchema =\n options.schema?.autoMigration === undefined ||\n options.schema?.autoMigration !== 'None';\n\n const inlineProjections = (options.projections ?? [])\n .filter(({ type }) => type === 'inline')\n .map(({ projection }) => projection);\n\n const migrate = async (migrationOptions?: CreateEventStoreSchemaOptions) => {\n if (!migrateSchema) {\n // TODO: Fix this cast when introducing more drivers\n migrateSchema = createEventStoreSchema(\n connectionString,\n pool as PgPool,\n {\n onBeforeSchemaCreated: async (context) => {\n if (options.hooks?.onBeforeSchemaCreated) {\n await options.hooks.onBeforeSchemaCreated(context);\n }\n },\n onAfterSchemaCreated: async (context) => {\n for (const projection of inlineProjections) {\n if (projection.init) {\n await projection.init({\n version: projection.version ?? 1,\n status: 'active',\n registrationType: 'inline',\n context: { ...context, migrationOptions },\n });\n }\n }\n if (options.hooks?.onAfterSchemaCreated) {\n await options.hooks.onAfterSchemaCreated(context);\n }\n },\n },\n migrationOptions,\n );\n }\n return migrateSchema;\n };\n\n const ensureSchemaExists = () => {\n if (!autoGenerateSchema) return Promise.resolve();\n\n return migrate();\n };\n\n const beforeCommitHook: AppendToStreamBeforeCommitHook | undefined =\n inlineProjections.length > 0\n ? async (events, { transaction }) =>\n handleProjections({\n projections: inlineProjections,\n // TODO: Add proper handling of global data\n // Currently it's not available as append doesn't return array of global position but just the last one\n events: events as ReadEvent<Event, PostgresReadEventMetadata>[],\n ...(await transactionToPostgreSQLProjectionHandlerContext(\n connectionString,\n pool,\n transaction,\n )),\n })\n : undefined;\n\n return {\n schema: {\n sql: () =>\n SQL.describe(\n schemaSQL,\n getFormatter(fromDatabaseDriverType(pool.driverType).databaseType),\n ),\n print: () =>\n console.log(\n SQL.describe(\n schemaSQL,\n getFormatter(fromDatabaseDriverType(pool.driverType).databaseType),\n ),\n ),\n migrate,\n dangerous: {\n truncate: (truncateOptions?: {\n resetSequences?: boolean;\n truncateProjections?: boolean;\n }): Promise<void> =>\n pool.withTransaction(async (transaction) => {\n await ensureSchemaExists();\n await truncateTables(transaction.execute, truncateOptions);\n\n if (truncateOptions?.truncateProjections) {\n const projectionContext =\n await transactionToPostgreSQLProjectionHandlerContext(\n connectionString,\n pool,\n transaction,\n );\n for (const projection of options?.projections ?? []) {\n if (projection.projection.truncate)\n await projection.projection.truncate(projectionContext);\n }\n }\n }),\n },\n },\n async aggregateStream<\n State,\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n PostgresReadEventMetadata,\n EventPayloadType\n >,\n ): Promise<AggregateStreamResult<State>> {\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, EventPayloadType>(\n streamName,\n read,\n );\n const currentStreamVersion = result.currentStreamVersion;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n PostgreSQLEventStoreDefaultStreamVersion,\n );\n\n for (const event of result.events) {\n if (!event) continue;\n state = evolve(state, event);\n }\n\n return {\n currentStreamVersion: currentStreamVersion,\n state,\n streamExists: result.streamExists,\n };\n },\n\n readStream: async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n readOptions?: ReadStreamOptions<EventType, EventPayloadType>,\n ): Promise<ReadStreamResult<EventType, PostgresReadEventMetadata>> => {\n await ensureSchemaExists();\n return readStream<EventType, EventPayloadType>(pool.execute, streamName, {\n ...readOptions,\n serialization: options.serialization ?? readOptions?.serialization,\n });\n },\n\n appendToStream: async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n appendOptions?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResultWithGlobalPosition> => {\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 = firstPart && rest.length > 0 ? firstPart : unknownTag;\n\n const appendResult = await appendToStream(\n // TODO: Fix this when introducing more drivers\n pool as PgPool,\n streamName,\n streamType,\n downcastRecordedMessages(events, appendOptions?.schema?.versioning),\n {\n ...(appendOptions as AppendToStreamOptions),\n beforeCommitHook,\n },\n );\n\n if (!appendResult.success)\n throw new ExpectedVersionConflictError(\n -1n, //TODO: Return actual version in case of error\n appendOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n );\n\n return {\n nextExpectedStreamVersion: appendResult.nextStreamPosition,\n lastEventGlobalPosition:\n appendResult.globalPositions[\n appendResult.globalPositions.length - 1\n ]!,\n createdNewStream:\n appendResult.nextStreamPosition >= BigInt(events.length),\n };\n },\n\n streamExists: async (\n streamName: string,\n options?: PostgresStreamExistsOptions,\n ): Promise<StreamExistsResult> => {\n await ensureSchemaExists();\n return streamExists(pool.execute, streamName, options);\n },\n\n consumer: <ConsumerEventType extends Event = Event>(\n options?: PostgreSQLEventStoreConsumerConfig<ConsumerEventType>,\n ): PostgreSQLEventStoreConsumer<ConsumerEventType> =>\n postgreSQLEventStoreConsumer<ConsumerEventType>({\n ...(options ?? {}),\n pool,\n connectionString,\n }),\n\n close: () => pool.close(),\n\n async withSession<T = unknown>(\n callback: (session: EventStoreSession<PostgresEventStore>) => Promise<T>,\n ): Promise<T> {\n return await pool.withConnection(async (connection) => {\n const storeOptions: PostgresEventStoreOptions = {\n ...options,\n connectionOptions: {\n connection: connection as PgConnection,\n },\n schema: {\n ...(options.schema ?? {}),\n autoMigration: 'None',\n },\n };\n\n const eventStore = getPostgreSQLEventStore(\n connectionString,\n storeOptions,\n );\n\n return ensureSchemaExists().then(() =>\n callback({\n eventStore,\n close: () => Promise.resolve(),\n }),\n );\n });\n },\n };\n};\n","import { dumbo, type Dumbo, type SQLExecutor } from '@event-driven-io/dumbo';\nimport type {\n PgClient,\n PgClientConnection,\n PgDriverType,\n PgPool,\n PgPoolClientConnection,\n PgTransaction,\n} from '@event-driven-io/dumbo/pg';\nimport type {\n AnyCommand,\n AnyEvent,\n AnyMessage,\n AnyRecordedMessageMetadata,\n BatchRecordedMessageHandlerWithContext,\n Checkpointer,\n Event,\n JSONSerializationOptions,\n Message,\n MessageProcessingScope,\n MessageProcessor,\n ProcessorHooks,\n ProjectorOptions,\n ReactorOptions,\n ReadEventMetadataWithGlobalPosition,\n SingleMessageHandlerResult,\n SingleRecordedMessageHandlerWithContext,\n WorkflowProcessorContext,\n WorkflowProcessorOptions,\n} from '@event-driven-io/emmett';\nimport {\n defaultProcessorPartition,\n defaultProcessorVersion,\n EmmettError,\n getCheckpoint,\n getProcessorInstanceId,\n getProjectorId,\n getWorkflowId,\n projector,\n reactor,\n unknownTag,\n workflowProcessor,\n} from '@event-driven-io/emmett';\nimport type pg from 'pg';\nimport {\n getPostgreSQLEventStore,\n type PostgresEventStore,\n} from '../postgreSQLEventStore';\nimport {\n DefaultPostgreSQLProcessorLockPolicy,\n postgreSQLProcessorLock,\n type LockAcquisitionPolicy,\n} from '../projections';\nimport {\n readProcessorCheckpoint,\n storeProcessorCheckpoint,\n type EventStoreSchemaMigrationOptions,\n} from '../schema';\nimport type { PostgreSQLEventStoreMessageBatchPullerStartFrom } from './messageBatchProcessing';\n\nexport type PostgreSQLProcessorHandlerContext = {\n partition: string;\n execute: SQLExecutor;\n connection: {\n connectionString: string;\n client: PgClient;\n transaction: PgTransaction;\n pool: Dumbo;\n messageStore: PostgresEventStore;\n };\n} &\n // TODO: Reconsider if it should be for all processors\n EventStoreSchemaMigrationOptions;\n\nexport type PostgreSQLProcessor<MessageType extends Message = AnyMessage> =\n MessageProcessor<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n >;\n\nexport type PostgreSQLProcessorEachMessageHandler<\n MessageType extends Message = Message,\n> = SingleRecordedMessageHandlerWithContext<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n>;\n\nexport type PostgreSQLProcessorEachBatchHandler<\n MessageType extends Message = Message,\n> = BatchRecordedMessageHandlerWithContext<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n>;\n\nexport type PostgreSQLProcessorStartFrom =\n | PostgreSQLEventStoreMessageBatchPullerStartFrom\n | 'CURRENT';\n\ntype PostgreSQLProcessorPooledOptions =\n | {\n connector?: PgDriverType;\n database?: string;\n pooled: true;\n pool: pg.Pool;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n pool: pg.Pool;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n pooled: true;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n };\n\ntype PostgreSQLProcessorNotPooledOptions =\n | {\n connector?: PgDriverType;\n database?: string;\n pooled: false;\n client: pg.Client;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n client: pg.Client;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n pooled: false;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n connection: PgPoolClientConnection | PgClientConnection;\n pooled?: false;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n dumbo: PgPool;\n pooled?: false;\n };\n\nexport type PostgreSQLProcessorConnectionOptions = {\n connectionString: string;\n} & (PostgreSQLProcessorPooledOptions | PostgreSQLProcessorNotPooledOptions);\n\nexport type PostgreSQLCheckpointer<\n MessageType extends AnyMessage = AnyMessage,\n> = Checkpointer<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n>;\n\nexport const postgreSQLCheckpointer = <\n MessageType extends Message = Message,\n>(): PostgreSQLCheckpointer<MessageType> => ({\n read: async (options, context) => {\n const result = await readProcessorCheckpoint(context.execute, options);\n\n return { lastCheckpoint: result?.lastProcessedCheckpoint };\n },\n store: async (options, context) => {\n const newCheckpoint = getCheckpoint(options.message);\n\n const result = await storeProcessorCheckpoint(context.execute, {\n lastProcessedCheckpoint: options.lastCheckpoint,\n newCheckpoint,\n processorId: options.processorId,\n partition: options.partition,\n version: options.version,\n });\n\n return result.success\n ? { success: true, newCheckpoint: result.newCheckpoint }\n : result;\n },\n});\n\ntype PostgreSQLConnectionOptions = {\n connectionOptions?: PostgreSQLProcessorConnectionOptions;\n} & JSONSerializationOptions;\n\ntype PostgreSQLProcessorOptionsBase = PostgreSQLConnectionOptions & {\n lock?: {\n acquisitionPolicy?: LockAcquisitionPolicy;\n timeoutSeconds?: number;\n };\n partition?: string;\n};\nexport type PostgreSQLReactorOptions<\n MessageType extends Message = Message,\n MessagePayloadType extends AnyMessage = MessageType,\n> = ReactorOptions<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext,\n MessagePayloadType\n> &\n PostgreSQLProcessorOptionsBase;\n\nexport type PostgreSQLProjectorOptions<\n EventType extends AnyEvent = AnyEvent,\n EventPayloadType extends Event = EventType,\n> = ProjectorOptions<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext,\n EventPayloadType\n> &\n PostgreSQLProcessorOptionsBase &\n EventStoreSchemaMigrationOptions;\n\nexport type PostgreSQLWorkflowProcessorOptions<\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MetaDataType extends AnyRecordedMessageMetadata = AnyRecordedMessageMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n> = WorkflowProcessorOptions<\n Input,\n State,\n Output,\n MetaDataType,\n HandlerContext,\n StoredMessage\n> &\n PostgreSQLProcessorOptionsBase;\n\nconst postgreSQLProcessingScope = (options: {\n pool: Dumbo | null;\n connectionString: string | null;\n processorId: string;\n partition: string;\n}): MessageProcessingScope<PostgreSQLProcessorHandlerContext> => {\n const processorConnectionString = options.connectionString;\n\n const processorPool = options.pool;\n\n const processingScope: MessageProcessingScope<\n PostgreSQLProcessorHandlerContext\n > = async <Result = SingleMessageHandlerResult>(\n handler: (\n context: PostgreSQLProcessorHandlerContext,\n ) => Result | Promise<Result>,\n partialContext: Partial<PostgreSQLProcessorHandlerContext>,\n ) => {\n const connection = partialContext?.connection;\n const connectionString =\n processorConnectionString ?? connection?.connectionString;\n\n if (!connectionString)\n throw new EmmettError(\n `PostgreSQL processor '${options.processorId}' is missing connection string. Ensure that you passed it through options`,\n );\n\n const pool =\n (!processorConnectionString ||\n connectionString == processorConnectionString\n ? connection?.pool\n : processorPool) ?? processorPool;\n\n if (!pool)\n throw new EmmettError(\n `PostgreSQL processor '${options.processorId}' is missing connection string. Ensure that you passed it through options`,\n );\n\n return pool.withTransaction(async (transaction) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n const client = (await transaction.connection.open()) as PgClient;\n return handler({\n ...partialContext,\n partition: options.partition,\n execute: transaction.execute,\n connection: {\n connectionString,\n pool,\n client,\n transaction: transaction as PgTransaction,\n messageStore: getPostgreSQLEventStore(connectionString, {\n connectionOptions: { client },\n }),\n },\n });\n });\n };\n\n return processingScope;\n};\n\nconst getProcessorPool = (options: PostgreSQLConnectionOptions) => {\n const poolOptions = {\n ...(options.connectionOptions ? options.connectionOptions : {}),\n };\n const processorConnectionString =\n 'connectionString' in poolOptions\n ? (poolOptions.connectionString ?? null)\n : null;\n\n const processorPool =\n 'dumbo' in poolOptions\n ? (poolOptions.dumbo as PgPool)\n : processorConnectionString\n ? dumbo({\n connectionString: processorConnectionString,\n ...poolOptions,\n serialization: options.serialization,\n })\n : null;\n\n return {\n pool: processorPool,\n connectionString: processorConnectionString,\n close:\n processorPool != null && !('dumbo' in poolOptions)\n ? processorPool.close\n : undefined,\n };\n};\n\nconst wrapHooksWithProcessorLocks = <\n HandlerContext extends PostgreSQLProcessorHandlerContext,\n>(\n hooks: ProcessorHooks<HandlerContext> | undefined,\n processorLock: ReturnType<typeof postgreSQLProcessorLock>,\n): ProcessorHooks<HandlerContext> => ({\n ...(hooks ?? {}),\n onStart: async (context: HandlerContext) => {\n await processorLock.tryAcquire({ execute: context.execute });\n\n if (hooks?.onStart) await hooks.onStart(context);\n },\n onClose:\n hooks?.onClose || processorLock\n ? async (context: HandlerContext) => {\n await processorLock.release({ execute: context.execute });\n\n if (hooks?.onClose) await hooks.onClose(context);\n }\n : undefined,\n});\n\nexport const postgreSQLProjector = <\n EventType extends Event = Event,\n EventPayloadType extends Event = EventType,\n>(\n options: PostgreSQLProjectorOptions<EventType, EventPayloadType>,\n): PostgreSQLProcessor<EventType> => {\n const {\n processorId = getProjectorId({\n projectionName: options.projection.name ?? 'unknown',\n }),\n processorInstanceId = getProcessorInstanceId(processorId),\n version = defaultProcessorVersion,\n partition = defaultProcessorPartition,\n lock,\n } = options;\n\n const { pool, connectionString, close } = getProcessorPool(options);\n\n const processorLock = postgreSQLProcessorLock({\n processorId,\n version,\n partition,\n processorInstanceId,\n projection: options.projection\n ? {\n name: options.projection.name ?? unknownTag,\n kind: options.projection.kind ?? unknownTag,\n version: options.projection.version ?? version,\n handlingType: 'async' as const,\n }\n : undefined,\n lockAcquisitionPolicy:\n lock?.acquisitionPolicy ?? DefaultPostgreSQLProcessorLockPolicy,\n lockTimeoutSeconds: lock?.timeoutSeconds,\n });\n\n const hooks: ProcessorHooks<PostgreSQLProcessorHandlerContext> =\n wrapHooksWithProcessorLocks(\n {\n ...(options.hooks ?? {}),\n onInit:\n options.projection.init !== undefined || options.hooks?.onInit\n ? async (context: PostgreSQLProcessorHandlerContext) => {\n if (options.projection.init)\n await options.projection.init({\n version: options.projection.version ?? version,\n status: 'active',\n registrationType: 'async',\n context: {\n ...context,\n migrationOptions: options.migrationOptions,\n },\n });\n if (options.hooks?.onInit)\n await options.hooks.onInit({\n ...context,\n migrationOptions: options.migrationOptions,\n });\n }\n : options.hooks?.onInit,\n onClose: close\n ? async (context: PostgreSQLProcessorHandlerContext) => {\n if (options.hooks?.onClose) await options.hooks?.onClose(context);\n if (close) await close();\n }\n : options.hooks?.onClose,\n },\n processorLock,\n );\n\n const processor = projector<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext,\n EventPayloadType\n >({\n ...options,\n processorId,\n processorInstanceId,\n version,\n partition,\n hooks,\n processingScope: postgreSQLProcessingScope({\n pool,\n connectionString,\n processorId,\n partition,\n }),\n checkpoints: postgreSQLCheckpointer<EventType>(),\n });\n\n return processor;\n};\n\nexport const postgreSQLWorkflowProcessor = <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MetaDataType extends AnyRecordedMessageMetadata = AnyRecordedMessageMetadata,\n HandlerContext extends PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext = PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n>(\n options: PostgreSQLWorkflowProcessorOptions<\n Input,\n State,\n Output,\n MetaDataType,\n HandlerContext,\n StoredMessage\n >,\n): PostgreSQLProcessor<Input | Output> => {\n const {\n processorId = options.processorId ??\n getWorkflowId({\n workflowName: options.workflow.name ?? 'unknown',\n }),\n processorInstanceId = getProcessorInstanceId(processorId),\n version = defaultProcessorVersion,\n partition = defaultProcessorPartition,\n lock,\n } = options;\n\n const { pool, connectionString, close } = getProcessorPool(options);\n\n const processorLock = postgreSQLProcessorLock({\n processorId,\n version,\n partition,\n processorInstanceId,\n projection: undefined,\n lockAcquisitionPolicy:\n lock?.acquisitionPolicy ?? DefaultPostgreSQLProcessorLockPolicy,\n lockTimeoutSeconds: lock?.timeoutSeconds,\n });\n\n const hooks: ProcessorHooks<HandlerContext> = wrapHooksWithProcessorLocks(\n {\n ...(options.hooks ?? {}),\n onClose: close\n ? async (context: PostgreSQLProcessorHandlerContext) => {\n if (options.hooks?.onClose)\n await options.hooks?.onClose(context as HandlerContext);\n if (close) await close();\n }\n : options.hooks?.onClose,\n },\n processorLock,\n );\n\n return workflowProcessor({\n ...options,\n processorId,\n processorInstanceId,\n version,\n partition,\n hooks,\n processingScope: postgreSQLProcessingScope({\n pool,\n connectionString,\n processorId,\n partition,\n }) as unknown as MessageProcessingScope<HandlerContext>,\n checkpoints: postgreSQLCheckpointer<Input | Output>() as Checkpointer<\n Input | Output,\n MetaDataType,\n HandlerContext\n >,\n }) as PostgreSQLProcessor<Input | Output>;\n};\n\nexport const postgreSQLReactor = <\n MessageType extends Message = Message,\n MessagePayloadType extends AnyMessage = MessageType,\n>(\n options: PostgreSQLReactorOptions<MessageType, MessagePayloadType>,\n): PostgreSQLProcessor<MessageType> => {\n const {\n processorId = options.processorId,\n processorInstanceId = getProcessorInstanceId(processorId),\n version = defaultProcessorVersion,\n partition = defaultProcessorPartition,\n lock,\n } = options;\n\n const { pool, connectionString, close } = getProcessorPool(options);\n\n const processorLock = postgreSQLProcessorLock({\n processorId,\n version,\n partition,\n processorInstanceId,\n projection: undefined,\n lockAcquisitionPolicy:\n lock?.acquisitionPolicy ?? DefaultPostgreSQLProcessorLockPolicy,\n lockTimeoutSeconds: lock?.timeoutSeconds,\n });\n\n const hooks: ProcessorHooks<PostgreSQLProcessorHandlerContext> =\n wrapHooksWithProcessorLocks(\n {\n ...(options.hooks ?? {}),\n onClose: close\n ? async (context: PostgreSQLProcessorHandlerContext) => {\n if (options.hooks?.onClose) await options.hooks?.onClose(context);\n if (close) await close();\n }\n : options.hooks?.onClose,\n },\n processorLock,\n );\n\n return reactor({\n ...options,\n processorId,\n processorInstanceId,\n version,\n partition,\n hooks,\n processingScope: postgreSQLProcessingScope({\n pool,\n connectionString,\n processorId,\n partition,\n }),\n checkpoints: postgreSQLCheckpointer<MessageType>(),\n });\n};\n","import { dumbo, type Dumbo } from '@event-driven-io/dumbo';\nimport type {\n AnyCommand,\n JSONSerializationOptions,\n MessageProcessor,\n WorkflowProcessorContext,\n} from '@event-driven-io/emmett';\nimport {\n asyncAwaiter,\n EmmettError,\n type AnyEvent,\n type AnyMessage,\n type AnyRecordedMessageMetadata,\n type AsyncAwaiter,\n type BatchRecordedMessageHandlerWithoutContext,\n type DefaultRecord,\n type Message,\n type MessageConsumer,\n type MessageConsumerOptions,\n type ReadEventMetadataWithGlobalPosition,\n} from '@event-driven-io/emmett';\nimport { v7 as uuid } from 'uuid';\nimport {\n DefaultPostgreSQLEventStoreProcessorBatchSize,\n DefaultPostgreSQLEventStoreProcessorPullingFrequencyInMs,\n postgreSQLEventStoreMessageBatchPuller,\n zipPostgreSQLEventStoreMessageBatchPullerStartFrom,\n type PostgreSQLEventStoreMessageBatchPuller,\n} from './messageBatchProcessing';\nimport {\n postgreSQLProjector,\n postgreSQLReactor,\n postgreSQLWorkflowProcessor,\n type PostgreSQLProcessor,\n type PostgreSQLProcessorHandlerContext,\n type PostgreSQLProjectorOptions,\n type PostgreSQLReactorOptions,\n type PostgreSQLWorkflowProcessorOptions,\n} from './postgreSQLProcessor';\n\nexport type PostgreSQLEventStoreConsumerConfig<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ConsumerMessageType extends Message = any,\n> = MessageConsumerOptions<ConsumerMessageType> & {\n stopWhen?: {\n noMessagesLeft?: boolean;\n };\n pulling?: {\n batchSize?: number;\n pullingFrequencyInMs?: number;\n };\n} & JSONSerializationOptions;\n\nexport type PostgreSQLEventStoreConsumerOptions<\n ConsumerMessageType extends Message = Message,\n> = PostgreSQLEventStoreConsumerConfig<ConsumerMessageType> & {\n connectionString: string;\n pool?: Dumbo;\n};\n\nexport type PostgreSQLEventStoreConsumer<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ConsumerMessageType extends AnyMessage = any,\n> = MessageConsumer<ConsumerMessageType> &\n Readonly<{\n reactor: <MessageType extends AnyMessage = ConsumerMessageType>(\n options: PostgreSQLReactorOptions<MessageType>,\n ) => PostgreSQLProcessor<MessageType>;\n\n workflowProcessor: <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n HandlerContext extends PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext = PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n >(\n options: PostgreSQLWorkflowProcessorOptions<\n Input,\n State,\n Output,\n MetaDataType,\n HandlerContext,\n StoredMessage\n >,\n ) => PostgreSQLProcessor<Input | Output>;\n }> &\n (AnyEvent extends ConsumerMessageType\n ? Readonly<{\n projector: <\n EventType extends AnyEvent = ConsumerMessageType & AnyEvent,\n >(\n options: PostgreSQLProjectorOptions<EventType>,\n ) => PostgreSQLProcessor<EventType>;\n }>\n : object);\n\nexport const postgreSQLEventStoreConsumer = <\n ConsumerMessageType extends Message = AnyMessage,\n>(\n options: PostgreSQLEventStoreConsumerOptions<ConsumerMessageType>,\n): PostgreSQLEventStoreConsumer<ConsumerMessageType> => {\n let isRunning = false;\n let isInitialized = false;\n const { pulling } = options;\n const processors = options.processors ?? [];\n let abortController: AbortController | null = null;\n\n let start: Promise<void>;\n\n let messagePuller: PostgreSQLEventStoreMessageBatchPuller | undefined;\n\n const startedAwaiter: AsyncAwaiter<void> = asyncAwaiter<void>();\n\n const pool = options.pool\n ? options.pool\n : dumbo({\n connectionString: options.connectionString,\n serialization: options.serialization,\n });\n\n const eachBatch: BatchRecordedMessageHandlerWithoutContext<\n ConsumerMessageType,\n ReadEventMetadataWithGlobalPosition\n > = async (messagesBatch) => {\n const activeProcessors = processors.filter((s) => s.isActive);\n\n if (activeProcessors.length === 0)\n return {\n type: 'STOP',\n reason: 'No active processors',\n };\n\n const result = await Promise.allSettled(\n activeProcessors.map(async (s) => {\n // TODO: Add here filtering to only pass messages that can be handled by processor\n return await s.handle(messagesBatch, {\n connection: {\n connectionString: options.connectionString,\n pool,\n },\n });\n }),\n );\n\n return result.some(\n (r) => r.status === 'fulfilled' && r.value?.type !== 'STOP',\n )\n ? undefined\n : {\n type: 'STOP',\n };\n };\n\n const processorContext = {\n execute: pool.execute,\n connection: {\n connectionString: options.connectionString,\n pool,\n client: undefined as never,\n transaction: undefined as never,\n messageStore: undefined as never,\n },\n };\n\n const stopProcessors = () =>\n Promise.all(processors.map((p) => p.close(processorContext)));\n\n const stop = async () => {\n if (!isRunning) return;\n isRunning = false;\n if (messagePuller) {\n abortController?.abort();\n await messagePuller.stop();\n }\n await start;\n\n messagePuller = undefined;\n abortController = null;\n\n await stopProcessors();\n };\n\n const init = async (): Promise<void> => {\n if (isInitialized) return;\n\n const postgresProcessors = processors as unknown as PostgreSQLProcessor[];\n\n for (const processor of postgresProcessors) {\n if (processor.init) {\n await processor.init(processorContext);\n }\n }\n\n isInitialized = true;\n };\n\n return {\n consumerId: options.consumerId ?? uuid(),\n get isRunning() {\n return isRunning;\n },\n whenStarted: (): Promise<void> => startedAwaiter.wait,\n processors,\n init,\n reactor: <MessageType extends AnyMessage = ConsumerMessageType>(\n options: PostgreSQLReactorOptions<MessageType>,\n ): PostgreSQLProcessor<MessageType> => {\n const processor = postgreSQLReactor(options);\n\n processors.push(\n // TODO: change that\n processor as unknown as MessageProcessor<\n ConsumerMessageType,\n AnyRecordedMessageMetadata,\n DefaultRecord\n >,\n );\n\n return processor;\n },\n projector: <EventType extends AnyEvent = ConsumerMessageType & AnyEvent>(\n options: PostgreSQLProjectorOptions<EventType>,\n ): PostgreSQLProcessor<EventType> => {\n const processor = postgreSQLProjector(options);\n\n processors.push(\n // TODO: change that\n processor as unknown as MessageProcessor<\n ConsumerMessageType,\n AnyRecordedMessageMetadata,\n DefaultRecord\n >,\n );\n\n return processor;\n },\n workflowProcessor: <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n HandlerContext extends PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext = PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n >(\n options: PostgreSQLWorkflowProcessorOptions<\n Input,\n State,\n Output,\n MetaDataType,\n HandlerContext,\n StoredMessage\n >,\n ): PostgreSQLProcessor<Input | Output> => {\n const processor = postgreSQLWorkflowProcessor(options);\n\n processors.push(\n // TODO: change that\n processor as unknown as MessageProcessor<\n ConsumerMessageType,\n AnyRecordedMessageMetadata,\n DefaultRecord\n >,\n );\n\n return processor;\n },\n start: () => {\n if (isRunning) return start;\n\n startedAwaiter.reset();\n\n if (processors.length === 0) {\n const error = new EmmettError(\n 'Cannot start consumer without at least a single processor',\n );\n startedAwaiter.reject(error);\n return Promise.reject(error);\n }\n\n isRunning = true;\n abortController = new AbortController();\n\n start = (async () => {\n if (!isRunning) return;\n\n try {\n messagePuller = postgreSQLEventStoreMessageBatchPuller({\n stopWhen: options.stopWhen,\n executor: pool.execute,\n eachBatch,\n batchSize:\n pulling?.batchSize ??\n DefaultPostgreSQLEventStoreProcessorBatchSize,\n pullingFrequencyInMs:\n pulling?.pullingFrequencyInMs ??\n DefaultPostgreSQLEventStoreProcessorPullingFrequencyInMs,\n signal: abortController.signal,\n });\n\n if (!isInitialized) {\n await init();\n }\n\n const startFrom = zipPostgreSQLEventStoreMessageBatchPullerStartFrom(\n await Promise.all(\n processors.map(async (o) => {\n const result = await o.start({\n execute: pool.execute,\n connection: {\n connectionString: options.connectionString,\n pool,\n },\n });\n\n return result;\n }),\n ),\n );\n\n await messagePuller.start({\n startFrom,\n started: startedAwaiter,\n });\n } catch (error) {\n isRunning = false;\n startedAwaiter.reject(error);\n throw error;\n } finally {\n await stopProcessors();\n }\n })();\n\n return start;\n },\n stop,\n close: async () => {\n await stop();\n await pool.close();\n },\n };\n};\n","import {\n getProjectorId,\n unknownTag,\n type AnyEvent,\n type ProjectorOptions,\n type ReadEventMetadataWithGlobalPosition,\n} from '@event-driven-io/emmett';\nimport type { PostgreSQLProjectionDefinition } from '../projections';\nimport type { LockAcquisitionPolicy } from '../projections/locks';\nimport {\n postgreSQLEventStoreConsumer,\n type PostgreSQLEventStoreConsumer,\n type PostgreSQLEventStoreConsumerOptions,\n} from './postgreSQLEventStoreConsumer';\nimport type { PostgreSQLProcessorHandlerContext } from './postgreSQLProcessor';\n\nconst defaultRebuildLockPolicy: LockAcquisitionPolicy = {\n type: 'retry',\n retries: 100,\n minTimeout: 100,\n maxTimeout: 5000,\n};\n\nexport const rebuildPostgreSQLProjections = <\n EventType extends AnyEvent = AnyEvent,\n>(\n options: Omit<\n PostgreSQLEventStoreConsumerOptions<EventType>,\n 'stopWhen' | 'processors'\n > & {\n lock?: {\n acquisitionPolicy?: LockAcquisitionPolicy;\n timeoutSeconds?: number;\n };\n } & (\n | {\n projections: (\n | ProjectorOptions<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n >\n | PostgreSQLProjectionDefinition<EventType>\n )[];\n }\n | ProjectorOptions<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n >\n ),\n): PostgreSQLEventStoreConsumer<EventType> => {\n const consumer = postgreSQLEventStoreConsumer({\n ...options,\n stopWhen: { noMessagesLeft: true },\n });\n\n const lock = { acquisitionPolicy: defaultRebuildLockPolicy, ...options.lock };\n\n const projections: (Omit<\n ProjectorOptions<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n >,\n 'processorId'\n > & { processorId?: string })[] =\n 'projections' in options\n ? options.projections.map((p) =>\n 'projection' in p\n ? {\n truncateOnStart: true,\n processorId: getProjectorId({\n projectionName: p.projection.name ?? unknownTag,\n }),\n ...p,\n }\n : {\n projection: p,\n processorId: getProjectorId({\n projectionName: p.name ?? unknownTag,\n }),\n truncateOnStart: true,\n },\n )\n : [options];\n\n for (const projectionDefinition of projections) {\n consumer.projector({\n ...projectionDefinition,\n truncateOnStart: projectionDefinition.truncateOnStart ?? true,\n lock,\n });\n }\n\n return consumer;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["SQL","SQL","SQL","SQL","SQL","bigInt","EmmettError","SQL","JSONSerializer","SQL","pgDriver","pgDriver","AssertionError","SQL","NO_CONCURRENCY_CHECK","STREAM_DOES_NOT_EXIST","STREAM_EXISTS","DumboError","UniqueConstraintError","SQL","SQL","SQL","SQL","SQL","SQL","SQL","SQL","SQL","ExpectedVersionConflictError","NO_CONCURRENCY_CHECK","EmmettError","defaultProcessorVersion","defaultProcessorPartition","unknownTag","EmmettError","unknownTag"],"sources":["../src/eventStore/schema/typing.ts","../src/eventStore/schema/readLastMessageGlobalPosition.ts","../src/eventStore/schema/readMessagesBatch.ts","../src/eventStore/consumers/messageBatchProcessing/index.ts","../src/eventStore/schema/createFunctionIfDoesNotExist.ts","../src/eventStore/schema/projections/projectionsLocks.ts","../src/eventStore/projections/locks/tryAcquireProjectionLock.ts","../src/eventStore/projections/locks/postgreSQLProjectionLock.ts","../src/eventStore/schema/processors/processorsLocks.ts","../src/eventStore/projections/locks/tryAcquireProcessorLock.ts","../src/eventStore/projections/locks/postgreSQLProcessorLock.ts","../src/eventStore/schema/projections/registerProjection.ts","../src/eventStore/projections/management/projectionManagement.ts","../src/eventStore/projections/pongo/pongoProjections.ts","../src/eventStore/projections/pongo/pongoProjectionSpec.ts","../src/eventStore/projections/postgresProjectionSpec.ts","../src/eventStore/projections/postgreSQLProjection.ts","../src/eventStore/schema/appendToStream.ts","../src/eventStore/schema/migrations/0_38_7/0_38_7.migration.ts","../src/eventStore/schema/migrations/0_38_7/0_38_7.snapshot.ts","../src/eventStore/schema/migrations/0_42_0/0_42_0.migration.ts","../src/eventStore/schema/migrations/0_42_0/0_42_0.snapshot.ts","../src/eventStore/schema/storeProcessorCheckpoint.ts","../src/eventStore/schema/migrations/0_43_0/index.ts","../src/eventStore/schema/tables.ts","../src/eventStore/schema/readProcessorCheckpoint.ts","../src/eventStore/schema/readStream.ts","../src/eventStore/schema/streamExists.ts","../src/eventStore/schema/index.ts","../src/eventStore/schema/truncateTables.ts","../src/eventStore/postgreSQLEventStore.ts","../src/eventStore/consumers/postgreSQLProcessor.ts","../src/eventStore/consumers/postgreSQLEventStoreConsumer.ts","../src/eventStore/consumers/rebuildPostgreSQLProjections.ts"],"sourcesContent":["export const emmettPrefix = 'emt';\n\nexport const globalTag = 'global';\nexport const defaultTag = `${emmettPrefix}:default`;\nexport const unknownTag = `${emmettPrefix}:unknown`;\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 messagesTable = {\n name: `${emmettPrefix}_messages`,\n columns: {\n partition: columns.partition,\n isArchived: columns.isArchived,\n },\n};\n\nexport const processorsTable = {\n name: `${emmettPrefix}_processors`,\n};\n\nexport const projectionsTable = {\n name: `${emmettPrefix}_projections`,\n};\n","import { singleOrNull, SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport { defaultTag, messagesTable } from './typing';\n\ntype ReadLastMessageGlobalPositionSqlResult = {\n global_position: string;\n};\n\nexport type ReadLastMessageGlobalPositionResult = {\n currentGlobalPosition: bigint | null;\n};\n\nexport const readLastMessageGlobalPosition = async (\n execute: SQLExecutor,\n options?: { partition?: string },\n): Promise<ReadLastMessageGlobalPositionResult> => {\n const result = await singleOrNull(\n execute.query<ReadLastMessageGlobalPositionSqlResult>(\n SQL`SELECT global_position\n FROM ${SQL.identifier(messagesTable.name)}\n WHERE partition = ${options?.partition ?? defaultTag} AND is_archived = FALSE AND transaction_id < pg_snapshot_xmin(pg_current_snapshot())\n ORDER BY transaction_id DESC, global_position DESC\n LIMIT 1`,\n ),\n );\n\n return {\n currentGlobalPosition:\n result !== null ? BigInt(result.global_position) : null,\n };\n};\n","import { mapRows, SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n bigIntProcessorCheckpoint,\n type CombinedMessageMetadata,\n type Message,\n type MessageDataOf,\n type MessageMetaDataOf,\n type MessageTypeOf,\n type RecordedMessage,\n type RecordedMessageMetadata,\n type RecordedMessageMetadataWithGlobalPosition,\n} from '@event-driven-io/emmett';\nimport { defaultTag, messagesTable } from './typing';\n\ntype ReadMessagesBatchSqlResult<MessageType extends Message> = {\n stream_position: string;\n stream_id: string;\n message_data: MessageDataOf<MessageType>;\n message_metadata: MessageMetaDataOf<MessageType>;\n message_schema_version: string;\n message_type: MessageTypeOf<MessageType>;\n message_id: string;\n global_position: string;\n transaction_id: string;\n created: string;\n};\n\nexport type ReadMessagesBatchOptions =\n | {\n after: bigint;\n batchSize: number;\n }\n | {\n from: bigint;\n batchSize: number;\n }\n | { to: bigint; batchSize: number }\n | { from: bigint; to: bigint };\n\nexport type ReadMessagesBatchResult<\n MessageType extends Message,\n MessageMetadataType extends RecordedMessageMetadata = RecordedMessageMetadata,\n> = {\n currentGlobalPosition: bigint;\n messages: RecordedMessage<MessageType, MessageMetadataType>[];\n areMessagesLeft: boolean;\n};\n\nexport const readMessagesBatch = async <\n MessageType extends Message,\n RecordedMessageMetadataType extends\n RecordedMessageMetadataWithGlobalPosition =\n RecordedMessageMetadataWithGlobalPosition,\n>(\n execute: SQLExecutor,\n options: ReadMessagesBatchOptions & { partition?: string },\n): Promise<\n ReadMessagesBatchResult<MessageType, RecordedMessageMetadataType>\n> => {\n const from = 'from' in options ? options.from : undefined;\n const after = 'after' in options ? options.after : undefined;\n const batchSize =\n 'batchSize' in options ? options.batchSize : options.to - options.from;\n\n const fromCondition: SQL =\n from !== undefined\n ? SQL`AND global_position >= ${from}`\n : after !== undefined\n ? SQL`AND global_position > ${after}`\n : SQL.EMPTY;\n\n const toCondition: SQL =\n 'to' in options ? SQL`AND global_position <= ${options.to}` : SQL.EMPTY;\n\n const limitCondition: SQL =\n 'batchSize' in options ? SQL`LIMIT ${options.batchSize}` : SQL.EMPTY;\n\n const messages: RecordedMessage<MessageType, RecordedMessageMetadataType>[] =\n await mapRows(\n execute.query<ReadMessagesBatchSqlResult<MessageType>>(\n SQL`\n SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id\n FROM ${SQL.identifier(messagesTable.name)}\n WHERE partition = ${options?.partition ?? defaultTag} AND is_archived = FALSE AND transaction_id < pg_snapshot_xmin(pg_current_snapshot()) ${fromCondition} ${toCondition}\n ORDER BY transaction_id, global_position\n ${limitCondition}`,\n ),\n (row) => {\n const rawEvent = {\n type: row.message_type,\n data: row.message_data,\n metadata: row.message_metadata,\n } as unknown as MessageType;\n\n const metadata: RecordedMessageMetadataWithGlobalPosition = {\n ...('metadata' in rawEvent ? (rawEvent.metadata ?? {}) : {}),\n messageId: row.message_id,\n streamName: row.stream_id,\n streamPosition: BigInt(row.stream_position),\n globalPosition: BigInt(row.global_position),\n checkpoint: bigIntProcessorCheckpoint(BigInt(row.global_position)),\n };\n\n return {\n ...rawEvent,\n kind: 'Event',\n metadata: metadata as CombinedMessageMetadata<\n MessageType,\n RecordedMessageMetadataType\n >,\n };\n },\n );\n\n return messages.length > 0\n ? {\n currentGlobalPosition:\n messages[messages.length - 1]!.metadata.globalPosition,\n messages: messages,\n areMessagesLeft: messages.length === batchSize,\n }\n : {\n currentGlobalPosition:\n 'from' in options\n ? options.from\n : 'after' in options\n ? options.after\n : 0n,\n messages: [],\n areMessagesLeft: false,\n };\n};\n","import type { SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n parseBigIntProcessorCheckpoint,\n type AsyncAwaiter,\n type BatchRecordedMessageHandlerWithoutContext,\n type EmmettError,\n type Message,\n type ProcessorCheckpoint,\n type ReadEventMetadataWithGlobalPosition,\n} from '@event-driven-io/emmett';\nimport { readLastMessageGlobalPosition } from '../../schema/readLastMessageGlobalPosition';\nimport {\n readMessagesBatch,\n type ReadMessagesBatchOptions,\n} from '../../schema/readMessagesBatch';\n\nexport const DefaultPostgreSQLEventStoreProcessorBatchSize = 100;\nexport const DefaultPostgreSQLEventStoreProcessorPullingFrequencyInMs = 50;\n\nexport type PostgreSQLEventStoreMessagesBatchHandlerResult = void | {\n type: 'STOP';\n reason?: string;\n error?: EmmettError;\n};\n\nexport type PostgreSQLEventStoreMessageBatchPullerOptions<\n MessageType extends Message = Message,\n> = {\n executor: SQLExecutor;\n pullingFrequencyInMs: number;\n batchSize: number;\n eachBatch: BatchRecordedMessageHandlerWithoutContext<\n MessageType,\n ReadEventMetadataWithGlobalPosition\n >;\n stopWhen?: {\n noMessagesLeft?: boolean;\n };\n signal: AbortSignal;\n};\n\nexport type PostgreSQLEventStoreMessageBatchPullerStartFrom =\n | { lastCheckpoint: ProcessorCheckpoint }\n | 'BEGINNING'\n | 'END';\n\nexport type PostgreSQLEventStoreMessageBatchPullerStartOptions = {\n startFrom: PostgreSQLEventStoreMessageBatchPullerStartFrom;\n signal?: AbortSignal;\n started?: AsyncAwaiter<void>;\n};\n\nexport type PostgreSQLEventStoreMessageBatchPuller = {\n isRunning: boolean;\n start(\n options: PostgreSQLEventStoreMessageBatchPullerStartOptions,\n ): Promise<void>;\n stop(): Promise<void>;\n};\n\nexport const postgreSQLEventStoreMessageBatchPuller = <\n MessageType extends Message = Message,\n>({\n executor,\n batchSize,\n eachBatch,\n pullingFrequencyInMs,\n stopWhen,\n signal,\n}: PostgreSQLEventStoreMessageBatchPullerOptions<MessageType>): PostgreSQLEventStoreMessageBatchPuller => {\n let isRunning = false;\n\n let start: Promise<void>;\n\n const pullMessages = async (\n options: PostgreSQLEventStoreMessageBatchPullerStartOptions,\n ) => {\n let after: bigint;\n try {\n after =\n options.startFrom === 'BEGINNING'\n ? 0n\n : options.startFrom === 'END'\n ? ((await readLastMessageGlobalPosition(executor))\n .currentGlobalPosition ?? 0n)\n : parseBigIntProcessorCheckpoint(options.startFrom.lastCheckpoint);\n } catch (error) {\n options.started?.reject(error);\n throw error;\n }\n\n options.started?.resolve();\n\n const readMessagesOptions: ReadMessagesBatchOptions = {\n after,\n batchSize,\n };\n\n let waitTime = 100;\n\n while (isRunning && !signal?.aborted) {\n const { messages, currentGlobalPosition, areMessagesLeft } =\n await readMessagesBatch<MessageType>(executor, readMessagesOptions);\n\n if (messages.length > 0) {\n const result = await eachBatch(messages);\n\n if (result && result.type === 'STOP') {\n isRunning = false;\n break;\n }\n }\n\n readMessagesOptions.after = currentGlobalPosition;\n\n await new Promise((resolve) => setTimeout(resolve, waitTime));\n\n if (stopWhen?.noMessagesLeft === true && !areMessagesLeft) {\n isRunning = false;\n break;\n }\n\n if (!areMessagesLeft) {\n waitTime = Math.min(waitTime * 2, 1000);\n } else {\n waitTime = pullingFrequencyInMs;\n }\n }\n };\n\n return {\n get isRunning() {\n return isRunning;\n },\n start: (options) => {\n if (isRunning) return start;\n isRunning = true;\n\n start = (async () => {\n return pullMessages(options);\n })();\n\n return start;\n },\n stop: async () => {\n if (!isRunning) return;\n isRunning = false;\n await start;\n },\n };\n};\n\nexport const zipPostgreSQLEventStoreMessageBatchPullerStartFrom = (\n options: (PostgreSQLEventStoreMessageBatchPullerStartFrom | undefined)[],\n): PostgreSQLEventStoreMessageBatchPullerStartFrom => {\n if (\n options.length === 0 ||\n options.some((o) => o === undefined || o === 'BEGINNING')\n )\n return 'BEGINNING';\n\n if (options.every((o) => o === 'END')) return 'END';\n\n return options\n .filter((o) => o !== undefined && o !== 'BEGINNING' && o !== 'END')\n .sort((a, b) => (a > b ? 1 : -1))[0]!;\n};\n","import { SQL } from '@event-driven-io/dumbo';\n\nexport const createFunctionIfDoesNotExistSQL = (\n functionName: string,\n functionDefinition: SQL,\n) =>\n SQL`\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = '${SQL.plain(functionName)}') THEN\n ${functionDefinition}\nEND IF;\nEND $$;\n`;\n","import { SQL } from '@event-driven-io/dumbo';\nimport { createFunctionIfDoesNotExistSQL } from '../createFunctionIfDoesNotExist';\nimport { projectionsTable } from '../typing';\n\nexport const tryAcquireProjectionLockSQL = createFunctionIfDoesNotExistSQL(\n 'emt_try_acquire_projection_lock',\n SQL`\nCREATE OR REPLACE FUNCTION emt_try_acquire_projection_lock(\n p_lock_key BIGINT,\n p_partition TEXT,\n p_name TEXT,\n p_version INT\n)\nRETURNS TABLE (acquired BOOLEAN, is_active BOOLEAN)\nLANGUAGE plpgsql\nAS $emt_try_acquire_projection_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock_shared(p_lock_key) AS acquired\n ),\n status_check AS (\n SELECT status = 'active' AS is_active\n FROM ${SQL.plain(projectionsTable.name)}\n WHERE partition = p_partition AND name = p_name AND version = p_version\n )\n SELECT\n COALESCE((SELECT lc.acquired FROM lock_check lc), false),\n COALESCE((SELECT sc.is_active FROM status_check sc), true);\nEND;\n$emt_try_acquire_projection_lock$;\n`,\n);\n\ntype CallTryAcquireProjectionLockParams = {\n lockKey: string;\n partition: string;\n name: string;\n version: number;\n};\n\nexport const callTryAcquireProjectionLock = (\n params: CallTryAcquireProjectionLockParams,\n) =>\n SQL`SELECT * FROM emt_try_acquire_projection_lock(${params.lockKey}, ${params.partition}, ${params.name}, ${params.version});`;\n","import { single, type SQLExecutor } from '@event-driven-io/dumbo';\nimport { hashText, isBigint } from '@event-driven-io/emmett';\nimport { callTryAcquireProjectionLock } from '../../schema/projections/projectionsLocks';\n\nexport type TryAcquireProjectionLockOptions = {\n projectionName: string;\n partition: string;\n version: number;\n lockKey: string | bigint;\n};\n\nexport const tryAcquireProjectionLock = async (\n execute: SQLExecutor,\n {\n lockKey,\n projectionName,\n partition,\n version,\n }: TryAcquireProjectionLockOptions,\n): Promise<boolean> => {\n const lockKeyBigInt = isBigint(lockKey) ? lockKey : await hashText(lockKey);\n\n const { acquired, is_active } = await single(\n execute.query<{\n acquired: boolean;\n is_active: boolean;\n }>(\n callTryAcquireProjectionLock({\n lockKey: lockKeyBigInt.toString(),\n partition,\n name: projectionName,\n version,\n }),\n ),\n );\n\n return acquired === true && is_active === true;\n};\n","import type { SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n tryAcquireProjectionLock,\n type TryAcquireProjectionLockOptions,\n} from './tryAcquireProjectionLock';\n\nexport type PostgreSQLProjectionLockOptions = {\n projectionName: string;\n partition: string;\n version: number;\n lockKey?: string | bigint;\n};\n\nexport type PostgreSQLProjectionLockContext = {\n execute: SQLExecutor;\n};\n\nexport type PostgreSQLProjectionLock = {\n tryAcquire: (options: PostgreSQLProjectionLockContext) => Promise<boolean>;\n release: (options: PostgreSQLProjectionLockContext) => void;\n};\n\nexport const postgreSQLProjectionLock = (\n options: PostgreSQLProjectionLockOptions,\n): PostgreSQLProjectionLock => {\n let acquired = false;\n const lockKey = options.lockKey ?? toProjectionLockKey(options);\n\n return {\n tryAcquire: async (\n context: PostgreSQLProjectionLockContext,\n ): Promise<boolean> => {\n if (acquired) {\n return true;\n }\n\n acquired = await tryAcquireProjectionLock(context.execute, {\n ...options,\n lockKey,\n });\n\n return acquired;\n },\n\n release: (_context: PostgreSQLProjectionLockContext): void => {\n if (!acquired) return;\n\n acquired = false;\n },\n };\n};\n\nexport const toProjectionLockKey = ({\n projectionName,\n partition,\n version,\n}: Pick<\n TryAcquireProjectionLockOptions,\n 'projectionName' | 'partition' | 'version'\n>): string => `${partition}:${projectionName}:${version}`;\n","import { SQL } from '@event-driven-io/dumbo';\nimport { bigInt } from '@event-driven-io/emmett';\nimport { createFunctionIfDoesNotExistSQL } from '../createFunctionIfDoesNotExist';\nimport {\n defaultTag,\n processorsTable,\n projectionsTable,\n unknownTag,\n} from '../typing';\n\nexport const tryAcquireProcessorLockSQL = createFunctionIfDoesNotExistSQL(\n 'emt_try_acquire_processor_lock',\n SQL`\nCREATE OR REPLACE FUNCTION emt_try_acquire_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_version INT,\n p_partition TEXT DEFAULT '${SQL.plain(defaultTag)}',\n p_processor_instance_id TEXT DEFAULT '${SQL.plain(unknownTag)}',\n p_projection_name TEXT DEFAULT NULL,\n p_projection_type VARCHAR(1) DEFAULT NULL,\n p_projection_kind TEXT DEFAULT NULL,\n p_lock_timeout_seconds INT DEFAULT 300\n)\nRETURNS TABLE (acquired BOOLEAN, checkpoint TEXT)\nLANGUAGE plpgsql\nAS $emt_try_acquire_processor_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n ownership_check AS (\n INSERT INTO ${SQL.plain(processorsTable.name)} (\n processor_id,\n partition,\n version,\n processor_instance_id,\n status,\n last_processed_checkpoint,\n last_processed_transaction_id,\n created_at,\n last_updated\n )\n SELECT p_processor_id, p_partition, p_version, p_processor_instance_id, 'running', '${SQL.plain(bigInt.toNormalizedString(0n))}', '0'::xid8, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (processor_id, partition, version) DO UPDATE\n SET processor_instance_id = p_processor_instance_id,\n status = 'running',\n last_updated = now()\n WHERE ${SQL.plain(processorsTable.name)}.processor_instance_id = p_processor_instance_id\n OR ${SQL.plain(processorsTable.name)}.processor_instance_id = '${SQL.plain(unknownTag)}'\n OR ${SQL.plain(processorsTable.name)}.status = 'stopped'\n OR ${SQL.plain(processorsTable.name)}.last_updated < now() - (p_lock_timeout_seconds || ' seconds')::interval\n RETURNING last_processed_checkpoint\n ),\n projection_status AS (\n INSERT INTO ${SQL.plain(projectionsTable.name)} (\n name,\n partition,\n version,\n type,\n kind,\n status,\n definition\n )\n SELECT p_projection_name, p_partition, p_version, p_projection_type, p_projection_kind, 'async_processing', '{}'::jsonb\n WHERE p_projection_name IS NOT NULL\n AND (SELECT last_processed_checkpoint FROM ownership_check) IS NOT NULL\n ON CONFLICT (name, partition, version) DO UPDATE\n SET status = 'async_processing'\n RETURNING name\n )\n SELECT\n (SELECT COUNT(*) > 0 FROM ownership_check),\n (SELECT oc.last_processed_checkpoint FROM ownership_check oc);\nEND;\n$emt_try_acquire_processor_lock$;\n`,\n);\n\nexport const releaseProcessorLockSQL = createFunctionIfDoesNotExistSQL(\n 'emt_release_processor_lock',\n SQL`\nCREATE OR REPLACE FUNCTION emt_release_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_partition TEXT,\n p_version INT,\n p_processor_instance_id TEXT DEFAULT '${SQL.plain(unknownTag)}',\n p_projection_name TEXT DEFAULT NULL\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_release_processor_lock$\nDECLARE\n v_rows_updated INT;\nBEGIN\n IF p_projection_name IS NOT NULL THEN\n UPDATE ${SQL.plain(projectionsTable.name)}\n SET status = 'active',\n last_updated = now()\n WHERE partition = p_partition\n AND name = p_projection_name\n AND version = p_version;\n END IF;\n\n UPDATE ${SQL.plain(processorsTable.name)}\n SET status = 'stopped',\n processor_instance_id = '${SQL.plain(unknownTag)}',\n last_updated = now()\n WHERE processor_id = p_processor_id\n AND partition = p_partition\n AND version = p_version\n AND processor_instance_id = p_processor_instance_id;\n\n GET DIAGNOSTICS v_rows_updated = ROW_COUNT;\n\n PERFORM pg_advisory_unlock(p_lock_key);\n\n RETURN v_rows_updated > 0;\nEND;\n$emt_release_processor_lock$;\n`,\n);\n\ntype CallTryAcquireProcessorLockParams = {\n lockKey: string;\n processorId: string;\n version: number;\n partition: string;\n processorInstanceId: string;\n projectionName: string | null;\n projectionType: 'i' | 'a' | null;\n projectionKind: string | null;\n lockTimeoutSeconds: number;\n};\n\nexport const callTryAcquireProcessorLock = (\n params: CallTryAcquireProcessorLockParams,\n) =>\n SQL`\n SELECT * FROM emt_try_acquire_processor_lock(\n ${params.lockKey}, \n ${params.processorId}, \n ${params.version}, \n ${params.partition}, \n ${params.processorInstanceId}, \n ${params.projectionName}, \n ${params.projectionType}, \n ${params.projectionKind}, \n ${params.lockTimeoutSeconds}\n );\n `;\n\ntype CallReleaseProcessorLockParams = {\n lockKey: string;\n processorId: string;\n partition: string;\n version: number;\n processorInstanceId: string;\n projectionName: string | null;\n};\n\nexport const callReleaseProcessorLock = (\n params: CallReleaseProcessorLockParams,\n) =>\n SQL`SELECT emt_release_processor_lock(\n ${params.lockKey}, \n ${params.processorId}, \n ${params.partition}, \n ${params.version}, \n ${params.processorInstanceId}, \n ${params.projectionName}\n ) as result;`;\n","import { single, type SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n asyncRetry,\n hashText,\n isBigint,\n type ProjectionHandlingType,\n} from '@event-driven-io/emmett';\nimport {\n callReleaseProcessorLock,\n callTryAcquireProcessorLock,\n} from '../../schema/processors/processorsLocks';\nimport { DefaultPostgreSQLProcessorLockPolicy } from './postgreSQLProcessorLock';\n\nexport type TryAcquireProcessorLockOptions = {\n processorId: string;\n version: number;\n partition: string;\n processorInstanceId: string;\n projection?: {\n name: string;\n handlingType: ProjectionHandlingType;\n kind: string;\n version: number;\n };\n lockKey: string | bigint;\n lockTimeoutSeconds?: number;\n};\n\nexport type TryAcquireProcessorLockResult =\n | {\n acquired: true;\n checkpoint: string;\n }\n | { acquired: false };\n\nexport type LockAcquisitionPolicy =\n | { type: 'fail' }\n | { type: 'skip' }\n | {\n type: 'retry';\n retries: number;\n minTimeout?: number;\n maxTimeout?: number;\n };\n\nexport const PROCESSOR_LOCK_DEFAULT_TIMEOUT_SECONDS = 300;\n\nexport const tryAcquireProcessorLock = async (\n execute: SQLExecutor,\n options: TryAcquireProcessorLockOptions,\n): Promise<TryAcquireProcessorLockResult> => {\n const lockKeyBigInt = isBigint(options.lockKey)\n ? options.lockKey\n : await hashText(options.lockKey);\n\n const { acquired, checkpoint } = await single(\n execute.command<{ acquired: boolean; checkpoint: string | null }>(\n callTryAcquireProcessorLock({\n lockKey: lockKeyBigInt.toString(),\n processorId: options.processorId,\n version: options.version,\n partition: options.partition,\n processorInstanceId: options.processorInstanceId,\n projectionName: options.projection?.name ?? null,\n projectionType: options.projection?.handlingType\n ? options.projection.handlingType === 'inline'\n ? 'i'\n : 'a'\n : null,\n projectionKind: options.projection?.kind ?? null,\n lockTimeoutSeconds:\n options.lockTimeoutSeconds ?? PROCESSOR_LOCK_DEFAULT_TIMEOUT_SECONDS,\n }),\n ),\n );\n\n return acquired\n ? { acquired: true, checkpoint: checkpoint! }\n : { acquired: false };\n};\n\nexport const tryAcquireProcessorLockWithRetry = async (\n execute: SQLExecutor,\n options: TryAcquireProcessorLockOptions & {\n lockAcquisitionPolicy?: LockAcquisitionPolicy;\n },\n): Promise<TryAcquireProcessorLockResult> => {\n const policy =\n options.lockAcquisitionPolicy ?? DefaultPostgreSQLProcessorLockPolicy;\n\n if (policy.type === 'retry') {\n return asyncRetry(() => tryAcquireProcessorLock(execute, options), {\n retries: policy.retries - 1,\n minTimeout: policy.minTimeout,\n maxTimeout: policy.maxTimeout,\n shouldRetryResult: (r) => !r.acquired,\n });\n }\n\n return tryAcquireProcessorLock(execute, options);\n};\n\nexport type ReleaseProcessorLockOptions = {\n processorId: string;\n version: number;\n partition: string;\n processorInstanceId: string;\n projectionName?: string;\n lockKey: string | bigint;\n};\n\nexport const releaseProcessorLock = async (\n execute: SQLExecutor,\n options: ReleaseProcessorLockOptions,\n): Promise<boolean> => {\n const lockKeyBigInt = isBigint(options.lockKey)\n ? options.lockKey\n : await hashText(options.lockKey);\n\n const { result } = await single(\n execute.command<{ result: boolean }>(\n callReleaseProcessorLock({\n lockKey: lockKeyBigInt.toString(),\n processorId: options.processorId,\n partition: options.partition,\n version: options.version,\n processorInstanceId: options.processorInstanceId,\n projectionName: options.projectionName ?? null,\n }),\n ),\n );\n\n return result;\n};\n","import type { SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n EmmettError,\n type ProjectionHandlingType,\n} from '@event-driven-io/emmett';\nimport { toProjectionLockKey } from './postgreSQLProjectionLock';\nimport {\n releaseProcessorLock,\n tryAcquireProcessorLockWithRetry,\n type LockAcquisitionPolicy,\n type TryAcquireProcessorLockOptions,\n} from './tryAcquireProcessorLock';\n\nexport type PostgreSQLProcessorLockOptions = {\n processorId: string;\n version: number;\n partition: string;\n processorInstanceId: string;\n projection?: {\n name: string;\n handlingType: ProjectionHandlingType;\n kind: string;\n version: number;\n };\n lockKey?: string | bigint;\n lockTimeoutSeconds?: number;\n lockAcquisitionPolicy?: LockAcquisitionPolicy;\n};\n\nexport type PostgreSQLProcessorLockContext = {\n execute: SQLExecutor;\n};\n\nexport type PostgreSQLProcessorLock = {\n tryAcquire: (options: PostgreSQLProcessorLockContext) => Promise<boolean>;\n release: (options: PostgreSQLProcessorLockContext) => Promise<void>;\n};\n\nexport const DefaultPostgreSQLProcessorLockPolicy: LockAcquisitionPolicy = {\n type: 'fail',\n};\n\nexport const postgreSQLProcessorLock = (\n options: PostgreSQLProcessorLockOptions,\n): PostgreSQLProcessorLock => {\n let acquired = false;\n const lockKey = options.lockKey ?? toProcessorLockKey(options);\n\n return {\n tryAcquire: async (\n context: PostgreSQLProcessorLockContext,\n ): Promise<boolean> => {\n if (acquired) {\n return true;\n }\n\n const result = await tryAcquireProcessorLockWithRetry(context.execute, {\n ...options,\n lockKey,\n });\n\n // TODO: This should be moved o prcessor\n if (!result.acquired && options.lockAcquisitionPolicy?.type !== 'skip') {\n throw new EmmettError(\n `Failed to acquire lock for processor '${options.processorId}'`,\n );\n }\n acquired = result.acquired;\n return acquired;\n },\n\n release: async (context: PostgreSQLProcessorLockContext): Promise<void> => {\n if (!acquired) return;\n\n const { projection, ...releaseOptions } = options;\n\n await releaseProcessorLock(context.execute, {\n ...releaseOptions,\n lockKey,\n projectionName: projection?.name,\n });\n\n acquired = false;\n },\n };\n};\n\nexport const toProcessorLockKey = ({\n projection,\n processorId,\n partition,\n version,\n}: Pick<\n TryAcquireProcessorLockOptions,\n 'projection' | 'processorId' | 'version' | 'partition'\n>): string =>\n projection\n ? toProjectionLockKey({\n projectionName: projection.name,\n partition: partition,\n version: projection.version,\n })\n : `${partition}:${processorId}:${version}`;\n","import { SQL } from '@event-driven-io/dumbo';\nimport { createFunctionIfDoesNotExistSQL } from '../createFunctionIfDoesNotExist';\nimport { projectionsTable } from '../typing';\n\nexport const registerProjectionSQL = createFunctionIfDoesNotExistSQL(\n 'emt_register_projection',\n SQL`\nCREATE OR REPLACE FUNCTION emt_register_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT,\n p_type VARCHAR(1),\n p_kind TEXT,\n p_status TEXT,\n p_definition JSONB\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_register_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n upsert_result AS (\n INSERT INTO ${SQL.identifier(projectionsTable.name)} (\n name, partition, version, type, kind, status, definition, created_at, last_updated\n )\n SELECT p_name, p_partition, p_version, p_type, p_kind, p_status, p_definition, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (name, partition, version) DO UPDATE\n SET definition = EXCLUDED.definition,\n last_updated = now()\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM upsert_result;\n\n RETURN v_result;\nEND;\n$emt_register_projection$;\n`,\n);\n\nexport const activateProjectionSQL = createFunctionIfDoesNotExistSQL(\n 'emt_activate_projection',\n SQL`\nCREATE OR REPLACE FUNCTION emt_activate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_activate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE ${SQL.identifier(projectionsTable.name)}\n SET status = 'active',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_activate_projection$;\n`,\n);\n\nexport const deactivateProjectionSQL = createFunctionIfDoesNotExistSQL(\n 'emt_deactivate_projection',\n SQL`\nCREATE OR REPLACE FUNCTION emt_deactivate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_deactivate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE ${SQL.identifier(projectionsTable.name)}\n SET status = 'inactive',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_deactivate_projection$;\n`,\n);\n\ntype CallRegisterProjectionParams = {\n lockKey: string;\n name: string;\n partition: string;\n version: number;\n type: 'i' | 'a';\n kind: string;\n status: string;\n definition: string;\n};\n\nexport const callRegisterProjection = (params: CallRegisterProjectionParams) =>\n SQL`\n SELECT emt_register_projection(${params.lockKey}, ${params.name}, ${params.partition}, ${params.version}, ${params.type}, ${params.kind}, ${params.status}, ${params.definition}) AS registered\n `;\n\ntype CallActivateProjectionParams = {\n lockKey: string;\n name: string;\n partition: string;\n version: number;\n};\n\nexport const callActivateProjection = (params: CallActivateProjectionParams) =>\n SQL`SELECT emt_activate_projection(${params.lockKey}, ${params.name}, ${params.partition}, ${params.version}) AS activated`;\n\ntype CallDeactivateProjectionParams = {\n lockKey: string;\n name: string;\n partition: string;\n version: number;\n};\n\nexport const callDeactivateProjection = (\n params: CallDeactivateProjectionParams,\n) =>\n SQL`SELECT emt_deactivate_projection(${params.lockKey}, ${params.name}, ${params.partition}, ${params.version}) AS deactivated`;\n","import {\n JSONSerializer,\n single,\n singleOrNull,\n SQL,\n type SQLExecutor,\n} from '@event-driven-io/dumbo';\nimport {\n hashText,\n type AnyReadEventMetadata,\n type DefaultRecord,\n type ProjectionDefinition,\n type ProjectionHandlingType,\n type ProjectionRegistration,\n} from '@event-driven-io/emmett';\nimport {\n callActivateProjection,\n callDeactivateProjection,\n callRegisterProjection,\n} from '../../schema/projections/registerProjection';\nimport { projectionsTable } from '../../schema/typing';\nimport { toProjectionLockKey } from '../locks/postgreSQLProjectionLock';\n\nexport const registerProjection = async <\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n>(\n execute: SQLExecutor,\n options: {\n partition: string;\n status: 'active' | 'inactive';\n registration: ProjectionRegistration<\n ProjectionHandlingType,\n ReadEventMetadataType,\n ProjectionHandlerContext\n >;\n },\n): Promise<{ registered: boolean }> => {\n const { partition, status, registration } = options;\n\n const type = registration.type === 'inline' ? 'i' : 'a';\n const name = registration.projection.name;\n const version = registration.projection.version ?? 1;\n const kind = registration.projection.kind ?? registration.type;\n const definition = JSONSerializer.serialize(registration.projection);\n\n const lockKey = toProjectionLockKey({\n projectionName: name!,\n partition,\n version,\n });\n\n const lockKeyBigInt = await hashText(lockKey);\n\n const { registered } = await single<{ registered: boolean }>(\n execute.query(\n callRegisterProjection({\n lockKey: lockKeyBigInt.toString(),\n name: name!,\n partition,\n version,\n type,\n kind,\n status,\n definition,\n }),\n ),\n );\n\n return { registered };\n};\n\nexport const activateProjection = async (\n execute: SQLExecutor,\n options: { name: string; partition: string; version: number },\n): Promise<{ activated: boolean }> => {\n const { name, partition, version } = options;\n\n const lockKey = toProjectionLockKey({\n projectionName: name,\n partition,\n version,\n });\n\n const lockKeyBigInt = await hashText(lockKey);\n\n const { activated } = await single<{ activated: boolean }>(\n execute.query(\n callActivateProjection({\n lockKey: lockKeyBigInt.toString(),\n name,\n partition,\n version,\n }),\n ),\n );\n\n return { activated };\n};\n\nexport const deactivateProjection = async (\n execute: SQLExecutor,\n options: { name: string; partition: string; version: number },\n): Promise<{ deactivated: boolean }> => {\n const { name, partition, version } = options;\n\n const lockKey = toProjectionLockKey({\n projectionName: name,\n partition,\n version,\n });\n\n const lockKeyBigInt = await hashText(lockKey);\n\n const { deactivated } = await single<{ deactivated: boolean }>(\n execute.query(\n callDeactivateProjection({\n lockKey: lockKeyBigInt.toString(),\n name,\n partition,\n version,\n }),\n ),\n );\n\n return { deactivated };\n};\n\ntype ProjectionRegistrationWithMandatoryData =\n ProjectionRegistration<ProjectionHandlingType> & {\n projection: Required<\n Pick<ProjectionDefinition, 'kind' | 'version' | 'name'>\n >;\n };\n\nexport type ReadProjectionInfoResult = {\n partition: string;\n status: 'active' | 'inactive';\n registration: ProjectionRegistrationWithMandatoryData;\n createdAt: Date;\n lastUpdated: Date;\n};\n\ntype RawProjectionRow = {\n name: string;\n version: number;\n type: string;\n kind: string;\n status: string;\n definition: ProjectionRegistrationWithMandatoryData['projection'];\n created_at: Date;\n last_updated: Date;\n};\n\nexport const readProjectionInfo = async (\n execute: SQLExecutor,\n {\n name,\n partition,\n version,\n }: { name: string; partition: string; version: number },\n): Promise<ReadProjectionInfoResult | null> => {\n const row = await singleOrNull<RawProjectionRow>(\n execute.query(\n SQL`SELECT name, version, type, kind, status, definition, created_at, last_updated\n FROM ${SQL.identifier(projectionsTable.name)}\n WHERE name = ${name} AND partition = ${partition} AND version = ${version}`,\n ),\n );\n\n return row\n ? {\n partition,\n status: row.status as 'active' | 'inactive',\n registration: {\n type: row.type === 'i' ? 'inline' : 'async',\n projection: {\n ...row.definition,\n name: row.name,\n version: row.version,\n kind: row.kind,\n },\n },\n createdAt: row.created_at,\n lastUpdated: row.last_updated,\n }\n : null;\n};\n","import {\n reduceAsync,\n type CanHandle,\n type Event,\n type EventStoreReadSchemaOptions,\n type JSONSerializationOptions,\n type ReadEvent,\n type TruncateProjection,\n} from '@event-driven-io/emmett';\nimport {\n pongoClient,\n type PongoClient,\n type PongoDBCollectionOptions,\n type PongoDocument,\n} from '@event-driven-io/pongo';\nimport { pgDriver } from '@event-driven-io/pongo/pg';\nimport {\n postgreSQLProjection,\n type PostgreSQLProjectionDefinition,\n type PostgreSQLProjectionHandlerContext,\n} from '..';\nimport type { PostgresReadEventMetadata } from '../../postgreSQLEventStore';\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 PostgresReadEventMetadata =\n PostgresReadEventMetadata,\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 PostgresReadEventMetadata =\n PostgresReadEventMetadata,\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 PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n> =\n | PongoWithNotNullDocumentEvolve<Document, EventType, EventMetaDataType>\n | PongoWithNullableDocumentEvolve<Document, EventType, EventMetaDataType>;\n\nexport type PongoProjectionOptions<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n> = {\n name: string;\n kind?: string;\n version?: number;\n handle: (\n events: ReadEvent<EventType, PostgresReadEventMetadata>[],\n context: PongoProjectionHandlerContext,\n ) => Promise<void>;\n canHandle: CanHandle<EventType>;\n truncate?: TruncateProjection<PongoProjectionHandlerContext>;\n init?: (context: PongoProjectionHandlerContext) => void | Promise<void>;\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\n} & JSONSerializationOptions;\n\nexport const pongoProjection = <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>({\n name,\n kind,\n version,\n truncate,\n handle,\n canHandle,\n eventsOptions,\n}: PongoProjectionOptions<\n EventType,\n EventPayloadType\n>): PostgreSQLProjectionDefinition<EventType, EventPayloadType> =>\n postgreSQLProjection<EventType, EventPayloadType>({\n name,\n version,\n kind: kind ?? 'emt:projections:postgresql:pongo:generic',\n canHandle,\n eventsOptions,\n handle: async (events, context) => {\n const {\n connection: { connectionString, client, pool },\n } = context;\n const pongo = pongoClient({\n connectionString,\n driver: pgDriver,\n connectionOptions: { client, pool },\n });\n try {\n await handle(events, {\n ...context,\n pongo,\n });\n } finally {\n await pongo.close();\n }\n },\n truncate: truncate\n ? async (context) => {\n const {\n connection: { connectionString, client, pool },\n } = context;\n const pongo = pongoClient({\n connectionString,\n driver: pgDriver,\n connectionOptions: { client, pool },\n });\n try {\n await truncate({\n ...context,\n pongo,\n });\n } finally {\n await pongo.close();\n }\n }\n : undefined,\n });\n\nexport type PongoMultiStreamProjectionOptions<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n EventPayloadType extends Event = EventType,\n DocumentPayload extends PongoDocument = Document,\n> = {\n kind?: string;\n canHandle: CanHandle<EventType>;\n version?: number;\n collectionName: string;\n collectionOptions?: PongoDBCollectionOptions<Document, DocumentPayload>;\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\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 JSONSerializationOptions;\n\nexport const pongoMultiStreamProjection = <\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n EventPayloadType extends Event = EventType,\n>(\n options: PongoMultiStreamProjectionOptions<\n Document,\n EventType,\n EventMetaDataType,\n EventPayloadType\n >,\n): PostgreSQLProjectionDefinition<EventType, EventPayloadType> => {\n const { collectionName, getDocumentId, canHandle } = options;\n const collectionNameWithVersion =\n options.version && options.version > 0\n ? `${collectionName}_v${options.version}`\n : collectionName;\n\n return pongoProjection({\n name: collectionNameWithVersion,\n version: options.version,\n kind: options.kind ?? 'emt:projections:postgresql:pongo:multi_stream',\n eventsOptions: options.eventsOptions,\n handle: async (events, { pongo }) => {\n const collection = pongo\n .db()\n .collection<Document>(\n collectionNameWithVersion,\n options.collectionOptions,\n );\n\n const eventsByDocumentId = events\n .map((event) => {\n const documentId = getDocumentId(event);\n\n return {\n documentId,\n event: event as ReadEvent<EventType, EventMetaDataType>,\n };\n })\n .reduce((acc, { documentId, event }) => {\n if (!acc.has(documentId)) {\n acc.set(documentId, []);\n }\n acc.get(documentId)!.push(event);\n return acc;\n }, new Map<string, ReadEvent<EventType, EventMetaDataType>[]>());\n\n await collection.handle(\n [...eventsByDocumentId.keys()],\n (document, id) => {\n const events = eventsByDocumentId.get(id)!;\n\n return reduceAsync(\n events,\n async (acc, event) => await options.evolve(acc!, event),\n document ??\n ('initialState' in options ? options.initialState() : null),\n );\n },\n );\n },\n canHandle,\n truncate: async (context) => {\n const {\n connection: { connectionString, client, pool },\n } = context;\n const pongo = pongoClient({\n connectionString,\n driver: pgDriver,\n connectionOptions: { client, pool },\n });\n\n try {\n await pongo\n .db()\n .collection<Document>(\n collectionNameWithVersion,\n options.collectionOptions,\n )\n .deleteMany();\n } finally {\n await pongo.close();\n }\n },\n init: async (context) => {\n const {\n connection: { connectionString, client, pool },\n } = context;\n const pongo = pongoClient({\n connectionString,\n driver: pgDriver,\n connectionOptions: { client, pool },\n });\n\n try {\n await pongo\n .db()\n .collection<Document>(\n collectionNameWithVersion,\n options.collectionOptions,\n )\n .schema.migrate(context.migrationOptions);\n } finally {\n await pongo.close();\n }\n },\n });\n};\n\nexport type PongoSingleStreamProjectionOptions<\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n EventPayloadType extends Event = EventType,\n DocumentPayload extends PongoDocument = Document,\n> = {\n canHandle: CanHandle<EventType>;\n getDocumentId?: (event: ReadEvent<EventType>) => string;\n version?: number;\n collectionName: string;\n collectionOptions?: PongoDBCollectionOptions<Document, DocumentPayload>;\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\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 JSONSerializationOptions;\n\nexport const pongoSingleStreamProjection = <\n Document extends PongoDocument,\n EventType extends Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n EventPayloadType extends Event = EventType,\n>(\n options: PongoSingleStreamProjectionOptions<\n Document,\n EventType,\n EventMetaDataType,\n EventPayloadType\n >,\n): PostgreSQLProjectionDefinition<EventType, EventPayloadType> => {\n return pongoMultiStreamProjection<\n Document,\n EventType,\n EventMetaDataType,\n EventPayloadType\n >({\n ...options,\n kind: 'emt:projections:postgresql:pongo:single_stream',\n getDocumentId:\n options.getDocumentId ?? ((event) => event.metadata.streamName),\n });\n};\n","import type { Dumbo } from '@event-driven-io/dumbo';\nimport {\n assertDeepEqual,\n assertEqual,\n assertIsNotNull,\n assertIsNull,\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 { pgDriver } from '@event-driven-io/pongo/pg';\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({\n connectionString,\n connectionOptions: { connection },\n driver: pgDriver,\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 assertIsNull(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 dumbo,\n type Dumbo,\n type QueryResultRow,\n type SQL,\n} from '@event-driven-io/dumbo';\nimport type { PgPool, PgPoolOptions } from '@event-driven-io/dumbo/pg';\nimport {\n assertFails,\n AssertionError,\n assertThatArray,\n assertTrue,\n bigIntProcessorCheckpoint,\n isErrorConstructor,\n type CombinedReadEventMetadata,\n type Event,\n type ReadEvent,\n type ThenThrows,\n} from '@event-driven-io/emmett';\nimport { v4 as uuid } from 'uuid';\nimport {\n handleProjections,\n transactionToPostgreSQLProjectionHandlerContext,\n type PostgreSQLProjectionDefinition,\n} from '.';\nimport {\n getPostgreSQLEventStore,\n type PostgresReadEventMetadata,\n} from '../postgreSQLEventStore';\n\nexport type PostgreSQLProjectionSpecEvent<\n EventType extends Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\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<EventType extends Event> = {\n projection: PostgreSQLProjectionDefinition<EventType>;\n} & PgPoolOptions;\n\nexport const PostgreSQLProjectionSpec = {\n for: <EventType extends Event>(\n options: PostgreSQLProjectionSpecOptions<EventType>,\n ): PostgreSQLProjectionSpec<EventType> => {\n {\n const { projection, ...restOptions } = options;\n const dumboOptions = {\n ...restOptions,\n serialization: projection.serialization,\n };\n const { connectionString } = dumboOptions;\n\n let wasInitialised = false;\n\n const initialize = async (pool: Dumbo): Promise<void> => {\n const eventStore = getPostgreSQLEventStore(connectionString, {\n // TODO: This will need to change when we support other drivers\n connectionOptions: { dumbo: pool as PgPool },\n });\n\n if (wasInitialised) return;\n\n wasInitialised = true;\n\n await eventStore.schema.migrate();\n if (projection.init)\n await pool.withTransaction(async (transaction) => {\n await projection.init!({\n registrationType: 'async',\n version: projection.version ?? 1,\n status: 'active',\n context: await transactionToPostgreSQLProjectionHandlerContext(\n connectionString,\n pool,\n transaction,\n ),\n });\n });\n };\n\n return (givenEvents: PostgreSQLProjectionSpecEvent<EventType>[]) => {\n return {\n when: (\n events: PostgreSQLProjectionSpecEvent<EventType>[],\n options?: PostgreSQLProjectionSpecWhenOptions,\n ) => {\n const allEvents: ReadEvent<EventType, PostgresReadEventMetadata>[] =\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 const metadata: PostgresReadEventMetadata = {\n checkpoint: bigIntProcessorCheckpoint(++globalPosition),\n globalPosition: globalPosition,\n streamPosition: globalPosition,\n streamName: `test-${uuid()}`,\n messageId: uuid(),\n };\n\n allEvents.push({\n ...event,\n kind: 'Event',\n metadata: {\n ...metadata,\n ...('metadata' in event ? (event.metadata ?? {}) : {}),\n } as CombinedReadEventMetadata<\n EventType,\n PostgresReadEventMetadata\n >,\n });\n }\n\n await initialize(pool);\n\n await pool.withTransaction(async (transaction) => {\n await handleProjections<EventType>({\n events: allEvents,\n projections: [projection],\n ...(await transactionToPostgreSQLProjectionHandlerContext(\n connectionString,\n pool,\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(dumboOptions);\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(dumboOptions);\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 PostgresReadEventMetadata =\n PostgresReadEventMetadata,\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 PostgresReadEventMetadata =\n PostgresReadEventMetadata,\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 {\n AnyConnection,\n DatabaseTransaction,\n Dumbo,\n SQL,\n SQLExecutor,\n} from '@event-driven-io/dumbo';\nimport type { PgClient, PgTransaction } from '@event-driven-io/dumbo/pg';\nimport {\n projection,\n type CanHandle,\n type Event,\n type EventStoreReadSchemaOptions,\n type JSONSerializationOptions,\n type ProjectionDefinition,\n type ProjectionHandler,\n type ProjectionInitOptions,\n type ReadEvent,\n} from '@event-driven-io/emmett';\nimport type { PostgresReadEventMetadata } from '../postgreSQLEventStore';\nimport type { EventStoreSchemaMigrationOptions } from '../schema';\nimport { defaultTag } from '../schema/typing';\nimport { postgreSQLProjectionLock } from './locks';\nimport { registerProjection } from './management';\n\nexport type PostgreSQLProjectionHandlerContext = {\n execute: SQLExecutor;\n connection: {\n connectionString: string;\n client: PgClient;\n transaction: PgTransaction;\n pool: Dumbo;\n };\n} &\n // TODO: This should be only for Init options\n // Make init options type configurable for projections\n EventStoreSchemaMigrationOptions;\n\nexport const transactionToPostgreSQLProjectionHandlerContext = async (\n connectionString: string,\n pool: Dumbo,\n transaction: PgTransaction | DatabaseTransaction<AnyConnection>,\n): Promise<PostgreSQLProjectionHandlerContext> => ({\n execute: transaction.execute,\n connection: {\n connectionString: connectionString,\n client: (await transaction.connection.open()) as PgClient,\n transaction: transaction as PgTransaction,\n pool,\n },\n});\n\nexport type PostgreSQLProjectionHandler<\n EventType extends Event = Event,\n EventMetaDataType extends PostgresReadEventMetadata =\n PostgresReadEventMetadata,\n> = ProjectionHandler<\n EventType,\n EventMetaDataType,\n PostgreSQLProjectionHandlerContext\n>;\n\nexport type PostgreSQLProjectionDefinition<\n EventType extends Event = Event,\n EventPayloadType extends Event = EventType,\n> = ProjectionDefinition<\n EventType,\n PostgresReadEventMetadata,\n PostgreSQLProjectionHandlerContext,\n EventPayloadType\n>;\n\nexport type PostgreSQLProjectionHandlerOptions<\n EventType extends Event = Event,\n> = {\n events: ReadEvent<EventType, PostgresReadEventMetadata>[];\n projections: PostgreSQLProjectionDefinition<EventType>[];\n partition?: string;\n} & PostgreSQLProjectionHandlerContext;\n\nexport const handleProjections = async <EventType extends Event = Event>(\n options: PostgreSQLProjectionHandlerOptions<EventType>,\n): Promise<void> => {\n const {\n projections: allProjections,\n events,\n connection: { pool, transaction, connectionString },\n partition = defaultTag,\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 PgClient;\n\n for (const projection of projections) {\n // TODO: Make projection name mandatory\n if (projection.name) {\n const lockAcquired = await postgreSQLProjectionLock({\n projectionName: projection.name,\n partition,\n version: projection.version ?? 1,\n }).tryAcquire({ execute: transaction.execute });\n\n if (!lockAcquired) {\n continue;\n }\n }\n\n await projection.handle(events, {\n connection: {\n connectionString,\n pool,\n client,\n transaction,\n },\n execute: transaction.execute,\n });\n }\n};\n\nexport const postgreSQLProjection = <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>(\n definition: PostgreSQLProjectionDefinition<EventType, EventPayloadType>,\n): PostgreSQLProjectionDefinition<EventType, EventPayloadType> =>\n projection<\n EventType,\n PostgresReadEventMetadata,\n PostgreSQLProjectionHandlerContext,\n EventPayloadType\n >({\n ...definition,\n init: async (options) => {\n await registerProjection<\n PostgresReadEventMetadata,\n PostgreSQLProjectionHandlerContext\n >(options.context.execute, {\n // TODO: pass partition from options\n partition: defaultTag,\n status: 'active',\n registration: {\n type: 'async',\n // TODO: fix this\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any\n projection: definition as any,\n },\n });\n if (definition.init) {\n await definition.init(options);\n }\n },\n });\n\nexport type PostgreSQLRawBatchSQLProjection<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n> = {\n name: string;\n kind?: string;\n version?: number;\n evolve: (\n events: EventType[],\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<SQL[]> | SQL[];\n canHandle: CanHandle<EventType>;\n init?: (\n context: ProjectionInitOptions<PostgreSQLProjectionHandlerContext>,\n ) => void | Promise<void> | SQL | Promise<SQL> | Promise<SQL[]> | SQL[];\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\n} & JSONSerializationOptions;\n\nexport const postgreSQLRawBatchSQLProjection = <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>(\n options: PostgreSQLRawBatchSQLProjection<EventType, EventPayloadType>,\n): PostgreSQLProjectionDefinition<EventType, EventPayloadType> =>\n postgreSQLProjection<EventType, EventPayloadType>({\n name: options.name,\n kind: options.kind ?? 'emt:projections:postgresql:raw_sql:batch',\n version: options.version,\n canHandle: options.canHandle,\n eventsOptions: options.eventsOptions,\n handle: async (events, context) => {\n const sqls: SQL[] = await options.evolve(events, context);\n\n await context.execute.batchCommand(sqls);\n },\n init: async (initOptions) => {\n const initSQL = options.init\n ? await options.init(initOptions)\n : undefined;\n\n if (initSQL) {\n if (Array.isArray(initSQL)) {\n await initOptions.context.execute.batchCommand(initSQL);\n } else {\n await initOptions.context.execute.command(initSQL);\n }\n }\n },\n });\n\nexport type PostgreSQLRawSQLProjection<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n> = {\n name: string;\n kind?: string;\n version?: number;\n evolve: (\n events: EventType,\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<SQL[]> | SQL[] | Promise<SQL> | SQL;\n canHandle: CanHandle<EventType>;\n init?: (\n context: ProjectionInitOptions<PostgreSQLProjectionHandlerContext>,\n ) => void | Promise<void> | SQL | Promise<SQL> | Promise<SQL[]> | SQL[];\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\n} & JSONSerializationOptions;\n\nexport const postgreSQLRawSQLProjection = <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>(\n options: PostgreSQLRawSQLProjection<EventType, EventPayloadType>,\n): PostgreSQLProjectionDefinition<EventType, EventPayloadType> => {\n const { evolve, kind, ...rest } = options;\n return postgreSQLRawBatchSQLProjection<EventType, EventPayloadType>({\n kind: kind ?? 'emt:projections:postgresql:raw:_sql:single',\n ...rest,\n evolve: async (events, context) => {\n const sqls: SQL[] = [];\n\n for (const event of events) {\n const pendingSqls = await evolve(event, context);\n if (Array.isArray(pendingSqls)) {\n sqls.push(...pendingSqls);\n } else {\n sqls.push(pendingSqls);\n }\n }\n return sqls;\n },\n });\n};\n","import {\n DumboError,\n single,\n SQL,\n UniqueConstraintError,\n type SQLExecutor,\n} from '@event-driven-io/dumbo';\nimport type { PgPool, PgTransaction } from '@event-driven-io/dumbo/pg';\nimport {\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AppendToStreamOptions,\n type DefaultRecord,\n type ExpectedStreamVersion,\n type Message,\n type RecordedMessage,\n} from '@event-driven-io/emmett';\nimport { v4 as uuid } from 'uuid';\nimport { createFunctionIfDoesNotExistSQL } from './createFunctionIfDoesNotExist';\nimport { defaultTag, messagesTable, streamsTable } from './typing';\n\nexport const appendToStreamSQL = createFunctionIfDoesNotExistSQL(\n 'emt_append_to_stream',\n SQL`CREATE OR REPLACE FUNCTION emt_append_to_stream(\n v_message_ids text[],\n v_messages_data jsonb[],\n v_messages_metadata jsonb[],\n v_message_schema_versions text[],\n v_message_types text[],\n v_message_kinds 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 global_positions bigint[],\n transaction_id xid8\n ) LANGUAGE plpgsql\n AS $emt_append_to_stream$\n DECLARE\n v_next_stream_position bigint;\n v_position bigint;\n v_updated_rows int;\n v_transaction_id xid8;\n v_global_positions bigint[];\n BEGIN\n v_transaction_id := pg_current_xact_id();\n\n IF v_expected_stream_position IS NULL THEN\n SELECT COALESCE(\n (SELECT stream_position \n FROM ${SQL.identifier(streamsTable.name)}\n WHERE stream_id = v_stream_id \n AND partition = v_partition \n AND is_archived = FALSE\n LIMIT 1), \n 0\n ) INTO v_expected_stream_position;\n END IF;\n\n v_next_stream_position := v_expected_stream_position + array_upper(v_messages_data, 1);\n\n IF v_expected_stream_position = 0 THEN\n INSERT INTO ${SQL.identifier(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 ${SQL.identifier(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 WITH ev AS (\n SELECT row_number() OVER () + v_expected_stream_position AS stream_position, \n message_data, \n message_metadata, \n schema_version, \n message_id, \n message_type,\n message_kind\n FROM (\n SELECT *\n FROM \n unnest(v_message_ids, v_messages_data, v_messages_metadata, v_message_schema_versions, v_message_types, v_message_kinds) \n AS message(message_id, message_data, message_metadata, schema_version, message_type, message_kind)\n ) AS message\n ),\n all_messages_insert AS (\n INSERT INTO ${SQL.identifier(messagesTable.name)}\n (stream_id, stream_position, partition, message_data, message_metadata, message_schema_version, message_type, message_kind, message_id, transaction_id)\n SELECT \n v_stream_id, ev.stream_position, v_partition, ev.message_data, ev.message_metadata, ev.schema_version, ev.message_type, ev.message_kind, ev.message_id, v_transaction_id\n FROM ev\n RETURNING global_position\n )\n SELECT \n array_agg(global_position ORDER BY global_position) INTO v_global_positions\n FROM \n all_messages_insert;\n\n RETURN QUERY SELECT TRUE, v_next_stream_position, v_global_positions, v_transaction_id;\n END;\n $emt_append_to_stream$;\n `,\n);\n\ntype CallAppendToStreamParams = {\n messageIds: string[];\n messagesData: DefaultRecord[];\n messagesMetadata: DefaultRecord[];\n schemaVersions: string[];\n messageTypes: string[];\n messageKinds: string[];\n streamId: string;\n streamType: string;\n expectedStreamPosition: bigint | null;\n partition: string;\n};\n\n// TODO: check if we need all those casts\nexport const callAppendToStream = (params: CallAppendToStreamParams) =>\n SQL`SELECT * FROM emt_append_to_stream(\n ${params.messageIds},\n ${params.messagesData},\n ${params.messagesMetadata},\n ${params.schemaVersions},\n ${params.messageTypes},\n ${params.messageKinds},\n ${params.streamId}::text,\n ${params.streamType}::text,\n ${params.expectedStreamPosition},\n ${params.partition}::text\n )`;\n\ntype AppendToStreamResult =\n | {\n success: true;\n nextStreamPosition: bigint;\n globalPositions: bigint[];\n transactionId: string;\n }\n | { success: false };\n\nexport type AppendToStreamBeforeCommitHook = (\n messages: RecordedMessage[],\n context: {\n transaction: PgTransaction;\n },\n) => Promise<void>;\n\nexport const appendToStream = (\n pool: PgPool,\n streamName: string,\n streamType: string,\n messages: Message[],\n options?: AppendToStreamOptions & {\n partition?: string;\n beforeCommitHook?: AppendToStreamBeforeCommitHook;\n },\n): Promise<AppendToStreamResult> =>\n pool.withTransaction<AppendToStreamResult>(async (transaction) => {\n const { execute } = transaction;\n\n if (messages.length === 0)\n return { success: false, result: { success: false } };\n\n try {\n const expectedStreamVersion = toExpectedVersion(\n options?.expectedStreamVersion,\n );\n\n const messagesToAppend: RecordedMessage[] = messages.map((e) => ({\n ...e,\n kind: e.kind ?? 'Event',\n metadata: {\n messageId: uuid(),\n ...('metadata' in e ? (e.metadata ?? {}) : {}),\n },\n })) as RecordedMessage[];\n\n const {\n success,\n next_stream_position,\n global_positions,\n transaction_id,\n } = await appendEventsRaw(\n execute,\n streamName,\n streamType,\n messagesToAppend,\n {\n expectedStreamVersion,\n },\n );\n\n if (\n !success ||\n next_stream_position === null ||\n global_positions === null ||\n global_positions.length === 0 ||\n transaction_id == null\n ) {\n return {\n success: false,\n\n result: { success: false },\n };\n }\n\n const nextStreamPosition = BigInt(next_stream_position);\n\n const globalPositions = global_positions.map(BigInt);\n\n globalPositions.forEach((globalPosition, index) => {\n messagesToAppend[index]!.metadata = {\n ...messagesToAppend[index]!.metadata,\n streamName,\n streamPosition:\n nextStreamPosition -\n BigInt(messagesToAppend.length) +\n BigInt(index + 1),\n globalPosition,\n };\n });\n\n if (options?.beforeCommitHook)\n await options.beforeCommitHook(messagesToAppend, { transaction });\n\n return {\n success: true,\n\n result: {\n success: true,\n nextStreamPosition,\n globalPositions,\n transactionId: transaction_id,\n },\n };\n } catch (error) {\n if (!isOptimisticConcurrencyError(error)) throw error;\n\n return {\n success: false,\n result: { success: false },\n };\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 DumboError.isInstanceOf(error, {\n errorType: UniqueConstraintError.ErrorType,\n });\n\ntype AppendToStreamSqlResult = {\n success: boolean;\n next_stream_position: string | null;\n global_positions: string[] | null;\n transaction_id: string | null | undefined;\n};\n\nconst appendEventsRaw = (\n execute: SQLExecutor,\n streamId: string,\n streamType: string,\n messages: RecordedMessage[],\n options?: {\n expectedStreamVersion: bigint | null;\n partition?: string;\n },\n): Promise<AppendToStreamSqlResult> =>\n single(\n execute.command<AppendToStreamSqlResult>(\n callAppendToStream({\n messageIds: messages.map((e) => e.metadata.messageId),\n messagesData: messages.map((e) => e.data),\n messagesMetadata: messages.map((e) => {\n const { messageId: _messageId, ...rawMetadata } = e.metadata;\n return rawMetadata;\n }),\n schemaVersions: messages.map(() => `'1'`),\n messageTypes: messages.map((e) => e.type),\n messageKinds: messages.map((e) => (e.kind === 'Event' ? 'E' : 'C')),\n streamId,\n streamType,\n expectedStreamPosition: options?.expectedStreamVersion ?? null,\n partition: options?.partition ?? defaultTag,\n }),\n ),\n );\n","import { SQL, type SQLMigration, sqlMigration } from '@event-driven-io/dumbo';\n\nexport const dropFutureConceptModuleAndTenantFunctions = SQL`\n DO $$\n BEGIN\n -- Check and drop functions related to future concept of modules and tenants\n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_module') THEN\n DROP FUNCTION add_module(TEXT);\n END IF;\n \n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_tenant') THEN\n DROP FUNCTION add_tenant(TEXT, TEXT);\n END IF;\n\n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_module_for_all_tenants') THEN\n DROP FUNCTION add_module_for_all_tenants(TEXT);\n END IF;\n \n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_tenant_for_all_modules') THEN\n DROP FUNCTION add_tenant_for_all_modules(TEXT);\n END IF;\n END $$;\n`;\n\nexport const dropOldAppendToSQLWithoutGlobalPositions = SQL`\n DO $$\n DECLARE\n v_current_return_type text;\n BEGIN\n -- Get the current return type definition as text\n SELECT pg_get_function_result(p.oid)\n INTO v_current_return_type\n FROM pg_proc p\n JOIN pg_namespace n ON p.pronamespace = n.oid\n WHERE n.nspname = current_schema() -- or specify your schema\n AND p.proname = 'emt_append_to_stream'\n AND p.pronargs = 10; -- number of arguments\n \n -- Check if it contains the old column name\n IF v_current_return_type IS NOT NULL AND \n v_current_return_type LIKE '%last_global_position%' AND \n v_current_return_type NOT LIKE '%global_positions%' THEN\n DROP FUNCTION emt_append_to_stream(text[], jsonb[], jsonb[], text[], text[], text[], text, text, bigint, text);\n RAISE NOTICE 'Old version of function dropped. Return type was: %', v_current_return_type;\n END IF;\n END $$;\n`;\n\nexport const migrationFromEventsToMessagesSQL = SQL`\nDO $$ \nDECLARE\n partition_record RECORD;\nBEGIN\n -- Rename the main table and its columns if it exists\n IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'emt_events') THEN\n -- Rename all partitions first\n FOR partition_record IN \n SELECT tablename \n FROM pg_tables \n WHERE tablename LIKE 'emt_events_%'\n ORDER BY tablename DESC -- to handle child partitions first\n LOOP\n EXECUTE format('ALTER TABLE %I RENAME TO %I', \n partition_record.tablename, \n REPLACE(partition_record.tablename, 'events', 'messages'));\n END LOOP;\n\n -- Rename the main table\n ALTER TABLE emt_events RENAME TO emt_messages;\n \n -- Rename columns\n ALTER TABLE emt_messages \n RENAME COLUMN event_data TO message_data;\n ALTER TABLE emt_messages \n RENAME COLUMN event_metadata TO message_metadata;\n ALTER TABLE emt_messages \n RENAME COLUMN event_schema_version TO message_schema_version;\n ALTER TABLE emt_messages \n RENAME COLUMN event_type TO message_type;\n ALTER TABLE emt_messages \n RENAME COLUMN event_id TO message_id;\n ALTER TABLE emt_messages \n ADD COLUMN message_kind CHAR(1) NOT NULL DEFAULT 'E';\n\n -- Rename sequence if it exists\n IF EXISTS (SELECT 1 FROM pg_sequences WHERE sequencename = 'emt_global_event_position') THEN\n ALTER SEQUENCE emt_global_event_position \n RENAME TO emt_global_message_position;\n \n ALTER TABLE emt_messages \n ALTER COLUMN global_position \n SET DEFAULT nextval('emt_global_message_position');\n END IF;\n END IF;\nEND $$;`;\n\nexport const migration_0_38_7_and_older: SQLMigration = sqlMigration(\n 'emt:postgresql:eventstore:0.38.7:migrate-events-to-messages',\n [\n dropFutureConceptModuleAndTenantFunctions,\n dropOldAppendToSQLWithoutGlobalPositions,\n migrationFromEventsToMessagesSQL,\n ],\n);\n","import { SQL } from '@event-driven-io/dumbo';\n\nexport const schema_0_38_7 = SQL`\nDO $$ \nDECLARE\n partition_record RECORD;\nBEGIN\n -- Rename the main table and its columns if it exists\n IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'emt_events') THEN\n -- Rename all partitions first\n FOR partition_record IN \n SELECT tablename \n FROM pg_tables \n WHERE tablename LIKE 'emt_events_%'\n ORDER BY tablename DESC -- to handle child partitions first\n LOOP\n EXECUTE format('ALTER TABLE %I RENAME TO %I', \n partition_record.tablename, \n REPLACE(partition_record.tablename, 'events', 'messages'));\n END LOOP;\n\n -- Rename the main table\n ALTER TABLE emt_events RENAME TO emt_messages;\n \n -- Rename columns\n ALTER TABLE emt_messages \n RENAME COLUMN event_data TO message_data;\n ALTER TABLE emt_messages \n RENAME COLUMN event_metadata TO message_metadata;\n ALTER TABLE emt_messages \n RENAME COLUMN event_schema_version TO message_schema_version;\n ALTER TABLE emt_messages \n RENAME COLUMN event_type TO message_type;\n ALTER TABLE emt_messages \n RENAME COLUMN event_id TO message_id;\n ALTER TABLE emt_messages \n ADD COLUMN message_kind CHAR(1) NOT NULL DEFAULT 'E';\n\n -- Rename sequence if it exists\n IF EXISTS (SELECT 1 FROM pg_sequences WHERE sequencename = 'emt_global_event_position') THEN\n ALTER SEQUENCE emt_global_event_position \n RENAME TO emt_global_message_position;\n \n ALTER TABLE emt_messages \n ALTER COLUMN global_position \n SET DEFAULT nextval('emt_global_message_position');\n END IF;\n END IF;\nEND $$;CREATE TABLE IF NOT EXISTS emt_streams(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'global',\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, partition, is_archived)\n ) PARTITION BY LIST (partition);\n \n CREATE UNIQUE INDEX IF NOT EXISTS idx_streams_unique \n ON emt_streams(stream_id, partition, is_archived) \n INCLUDE (stream_position);\n CREATE SEQUENCE IF NOT EXISTS emt_global_message_position;\n\n CREATE TABLE IF NOT EXISTS emt_messages(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'global',\n message_kind CHAR(1) NOT NULL DEFAULT 'E',\n message_data JSONB NOT NULL,\n message_metadata JSONB NOT NULL,\n message_schema_version TEXT NOT NULL,\n message_type TEXT NOT NULL,\n message_id TEXT NOT NULL,\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n global_position BIGINT DEFAULT nextval('emt_global_message_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 CREATE TABLE IF NOT EXISTS emt_subscriptions(\n subscription_id TEXT NOT NULL,\n version INT NOT NULL DEFAULT 1,\n partition TEXT NOT NULL DEFAULT 'global',\n last_processed_position BIGINT NOT NULL,\n last_processed_transaction_id XID8 NOT NULL,\n PRIMARY KEY (subscription_id, partition, version)\n ) PARTITION BY LIST (partition);\nCREATE 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 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\n -- create default 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 CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $$\n BEGIN \n PERFORM emt_add_table_partition('emt_messages', partition_name);\n PERFORM emt_add_table_partition('emt_streams', partition_name);\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_subscriptions' || '_' || partition_name), 'emt_subscriptions', partition_name\n );\n END;\n $$ LANGUAGE plpgsql;\n\n DO $$\n BEGIN\n -- Check and drop functions related to future concept of modules and tenants\n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_module') THEN\n DROP FUNCTION add_module(TEXT);\n END IF;\n \n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_tenant') THEN\n DROP FUNCTION add_tenant(TEXT, TEXT);\n END IF;\n\n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_module_for_all_tenants') THEN\n DROP FUNCTION add_module_for_all_tenants(TEXT);\n END IF;\n \n IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_tenant_for_all_modules') THEN\n DROP FUNCTION add_tenant_for_all_modules(TEXT);\n END IF;\n END $$;\n\n\n DO $$\n DECLARE\n v_current_return_type text;\n BEGIN\n -- Get the current return type definition as text\n SELECT pg_get_function_result(p.oid)\n INTO v_current_return_type\n FROM pg_proc p\n JOIN pg_namespace n ON p.pronamespace = n.oid\n WHERE n.nspname = current_schema() -- or specify your schema\n AND p.proname = 'emt_append_to_stream'\n AND p.pronargs = 10; -- number of arguments\n \n -- Check if it contains the old column name\n IF v_current_return_type IS NOT NULL AND \n v_current_return_type LIKE '%last_global_position%' AND \n v_current_return_type NOT LIKE '%global_positions%' THEN\n DROP FUNCTION emt_append_to_stream(text[], jsonb[], jsonb[], text[], text[], text[], text, text, bigint, text);\n RAISE NOTICE 'Old version of function dropped. Return type was: %', v_current_return_type;\n END IF;\n END $$;\nCREATE OR REPLACE FUNCTION emt_append_to_stream(\n v_message_ids text[],\n v_messages_data jsonb[],\n v_messages_metadata jsonb[],\n v_message_schema_versions text[],\n v_message_types text[],\n v_message_kinds 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 global_positions 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_global_positions bigint[];\n BEGIN\n v_transaction_id := pg_current_xact_id();\n\n IF v_expected_stream_position IS NULL THEN\n SELECT COALESCE(\n (SELECT stream_position \n FROM emt_streams\n WHERE stream_id = v_stream_id \n AND partition = v_partition \n AND is_archived = FALSE\n LIMIT 1), \n 0\n ) INTO v_expected_stream_position;\n END IF;\n\n v_next_stream_position := v_expected_stream_position + array_upper(v_messages_data, 1);\n\n IF v_expected_stream_position = 0 THEN\n INSERT INTO emt_streams\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 emt_streams 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 WITH ev AS (\n SELECT row_number() OVER () + v_expected_stream_position AS stream_position, \n message_data, \n message_metadata, \n schema_version, \n message_id, \n message_type,\n message_kind\n FROM (\n SELECT *\n FROM \n unnest(v_message_ids, v_messages_data, v_messages_metadata, v_message_schema_versions, v_message_types, v_message_kinds) \n AS message(message_id, message_data, message_metadata, schema_version, message_type, message_kind)\n ) AS message\n ),\n all_messages_insert AS (\n INSERT INTO emt_messages\n (stream_id, stream_position, partition, message_data, message_metadata, message_schema_version, message_type, message_kind, message_id, transaction_id)\n SELECT \n v_stream_id, ev.stream_position, v_partition, ev.message_data, ev.message_metadata, ev.schema_version, ev.message_type, ev.message_kind, ev.message_id, v_transaction_id\n FROM ev\n RETURNING global_position\n )\n SELECT \n array_agg(global_position ORDER BY global_position) INTO v_global_positions\n FROM \n all_messages_insert;\n\n RETURN QUERY SELECT TRUE, v_next_stream_position, v_global_positions, v_transaction_id;\n END;\n $$;\n SELECT emt_add_partition('emt:default');\nCREATE OR REPLACE FUNCTION store_subscription_checkpoint(\n p_subscription_id VARCHAR(100),\n p_version BIGINT,\n p_position BIGINT,\n p_check_position BIGINT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT 'emt:default'\n) RETURNS INT AS $$\nDECLARE\n current_position BIGINT;\nBEGIN\n -- Handle the case when p_check_position is provided\n IF p_check_position IS NOT NULL THEN\n -- Try to update if the position matches p_check_position\n UPDATE \"emt_subscriptions\"\n SET \n \"last_processed_position\" = p_position, \n \"last_processed_transaction_id\" = p_transaction_id\n WHERE \"subscription_id\" = p_subscription_id AND \"last_processed_position\" = p_check_position AND \"partition\" = p_partition;\n\n IF FOUND THEN\n RETURN 1; -- Successfully updated\n END IF;\n\n -- Retrieve the current position\n SELECT \"last_processed_position\" INTO current_position\n FROM \"emt_subscriptions\"\n WHERE \"subscription_id\" = p_subscription_id AND \"partition\" = p_partition;\n\n -- Return appropriate codes based on current position\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSIF current_position > p_check_position THEN\n RETURN 2; -- Failure: current position is greater\n ELSE\n RETURN 2; -- Default failure case for mismatched positions\n END IF;\n END IF;\n\n -- Handle the case when p_check_position is NULL: Insert if not exists\n BEGIN\n INSERT INTO \"emt_subscriptions\"(\"subscription_id\", \"version\", \"last_processed_position\", \"partition\", \"last_processed_transaction_id\")\n VALUES (p_subscription_id, p_version, p_position, p_partition, p_transaction_id);\n RETURN 1; -- Successfully inserted\n EXCEPTION WHEN unique_violation THEN\n -- If insertion failed, it means the row already exists\n SELECT \"last_processed_position\" INTO current_position\n FROM \"emt_subscriptions\"\n WHERE \"subscription_id\" = p_subscription_id AND \"partition\" = p_partition;\n\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSE\n RETURN 2; -- Insertion failed, row already exists with different position\n END IF;\n END;\nEND;\n$$ LANGUAGE plpgsql;\n`;\n","import { SQL, sqlMigration, type SQLMigration } from '@event-driven-io/dumbo';\nimport { defaultTag } from '../../typing';\n\nexport const migration_0_42_0_FromSubscriptionsToProcessorsSQL = SQL`\nDO $$\nBEGIN\n IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'emt_subscriptions') THEN\n -- 1. Alter message_kind type from CHAR(1) to VARCHAR(1)\n ALTER TABLE emt_messages ALTER COLUMN message_kind TYPE VARCHAR(1);\n\n -- 2. Setup emt_processors table if not exists\n CREATE TABLE IF NOT EXISTS \"emt_processors\"(\n last_processed_transaction_id XID8 NOT NULL,\n version INT NOT NULL DEFAULT 1,\n processor_id TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\n status TEXT NOT NULL DEFAULT 'stopped', \n last_processed_checkpoint TEXT NOT NULL, \n processor_instance_id TEXT DEFAULT 'emt:unknown',\n PRIMARY KEY (processor_id, partition, version)\n ) PARTITION BY LIST (partition);\n\n -- 3. Setup emt_projections table if not exists\n\n CREATE TABLE IF NOT EXISTS \"emt_projections\"(\n version INT NOT NULL DEFAULT 1, \n type VARCHAR(1) NOT NULL,\n name TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\n kind TEXT NOT NULL, \n status TEXT NOT NULL, \n definition JSONB NOT NULL DEFAULT '{}'::jsonb, \n PRIMARY KEY (name, partition, version)\n ) PARTITION BY LIST (partition);\n\n CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $fnpar$\n BEGIN \n PERFORM emt_add_table_partition('emt_messages', partition_name);\n PERFORM emt_add_table_partition('emt_streams', partition_name);\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_subscriptions' || '_' || partition_name), 'emt_subscriptions', partition_name\n );\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_processors' || '_' || partition_name), 'emt_processors', partition_name\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_projections' || '_' || partition_name), 'emt_projections', partition_name\n );\n END;\n $fnpar$ LANGUAGE plpgsql;\n\n PERFORM emt_add_partition('${SQL.plain(defaultTag)}');\n\n -- 3. Copy data from old table to new table\n INSERT INTO \"emt_processors\"\n (\n processor_id,\n version,\n partition,\n last_processed_checkpoint,\n last_processed_transaction_id,\n status,\n processor_instance_id\n )\n SELECT \n subscription_id, \n version,\n partition,\n lpad(last_processed_position::text, 19, '0'),\n last_processed_transaction_id, 'stopped', \n 'emt:unknown'\n FROM emt_subscriptions\n ON CONFLICT DO NOTHING;\n\n -- 4. Create backward-compat store_subscription_checkpoint that dual-writes\n \n CREATE OR REPLACE FUNCTION store_subscription_checkpoint(\n p_subscription_id VARCHAR(100),\n p_version BIGINT,\n p_position BIGINT,\n p_check_position BIGINT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT 'emt:default'\n ) RETURNS INT AS $fn$\n DECLARE\n current_position BIGINT;\n result INT;\n BEGIN\n -- Handle the case when p_check_position is provided\n IF p_check_position IS NOT NULL THEN\n -- Try to update if the position matches p_check_position\n UPDATE \"emt_subscriptions\"\n SET\n \"last_processed_position\" = p_position,\n \"last_processed_transaction_id\" = p_transaction_id\n WHERE \"subscription_id\" = p_subscription_id \n AND \"last_processed_position\" = p_check_position \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF FOUND THEN\n -- Dual-write to emt_processors\n UPDATE \"emt_processors\"\n SET\n \"last_processed_checkpoint\" = lpad(p_position::text, 19, '0'),\n \"last_processed_transaction_id\" = p_transaction_id\n WHERE \"processor_id\" = p_subscription_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF NOT FOUND THEN\n INSERT INTO \"emt_processors\"(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"status\", \"processor_instance_id\")\n VALUES (p_subscription_id, p_version, lpad(p_position::text, 19, '0'), p_partition, p_transaction_id, 'stopped', 'emt:unknown')\n ON CONFLICT DO NOTHING;\n END IF;\n\n RETURN 1;\n END IF;\n\n -- Retrieve the current position\n SELECT \"last_processed_position\" INTO current_position\n FROM \"emt_subscriptions\"\n WHERE \"subscription_id\" = p_subscription_id AND \"partition\" = p_partition AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSIF current_position > p_check_position THEN\n RETURN 2;\n ELSE\n RETURN 2;\n END IF;\n END IF;\n\n -- Handle the case when p_check_position is NULL: Insert if not exists\n BEGIN\n INSERT INTO \"emt_subscriptions\"(\"subscription_id\", \"version\", \"last_processed_position\", \"partition\", \"last_processed_transaction_id\")\n VALUES (p_subscription_id, p_version, p_position, p_partition, p_transaction_id);\n\n -- Dual-write to emt_processors\n INSERT INTO emt_processors(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"status\", \"processor_instance_id\")\n VALUES (p_subscription_id, p_version, lpad(p_position::text, 19, '0'), p_partition, p_transaction_id, 'stopped', 'emt:unknown')\n ON CONFLICT DO NOTHING;\n\n RETURN 1;\n EXCEPTION WHEN unique_violation THEN\n SELECT \"last_processed_position\" INTO current_position\n FROM \"emt_subscriptions\"\n WHERE \"subscription_id\" = p_subscription_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSE\n RETURN 2;\n END IF;\n END;\n END;\n $fn$ LANGUAGE plpgsql;\n\n -- 5. Replace store_processor_checkpoint with dual-write version\n CREATE OR REPLACE FUNCTION store_processor_checkpoint(\n p_processor_id TEXT,\n p_version BIGINT,\n p_position TEXT,\n p_check_position TEXT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT '${SQL.plain(defaultTag)}',\n p_processor_instance_id TEXT DEFAULT 'emt:unknown'\n ) RETURNS INT AS $fn2$\n DECLARE\n current_position TEXT;\n v_position_bigint BIGINT;\n BEGIN\n -- Convert TEXT position to BIGINT for emt_subscriptions\n v_position_bigint := p_position::BIGINT;\n\n -- Handle the case when p_check_position is provided\n IF p_check_position IS NOT NULL THEN\n -- Try to update if the position matches p_check_position\n UPDATE \"emt_processors\"\n SET\n \"last_processed_checkpoint\" = p_position,\n \"last_processed_transaction_id\" = p_transaction_id,\n \"last_updated\" = now()\n WHERE \"processor_id\" = p_processor_id \n AND \"last_processed_checkpoint\" = p_check_position \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF FOUND THEN\n -- Dual-write to emt_subscriptions\n UPDATE \"emt_subscriptions\"\n SET\n \"last_processed_position\" = v_position_bigint,\n \"last_processed_transaction_id\" = p_transaction_id\n WHERE \"subscription_id\" = p_processor_id AND \"partition\" = p_partition AND \"version\" = p_version;\n\n IF NOT FOUND THEN\n INSERT INTO \"emt_subscriptions\"(\"subscription_id\", \"version\", \"last_processed_position\", \"partition\", \"last_processed_transaction_id\")\n VALUES (p_processor_id, p_version, v_position_bigint, p_partition, p_transaction_id)\n ON CONFLICT DO NOTHING;\n END IF;\n\n RETURN 1;\n END IF;\n\n -- Retrieve the current position\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id AND \"partition\" = p_partition AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSIF current_position > p_position THEN\n RETURN 3;\n ELSE\n RETURN 2;\n END IF;\n END IF;\n\n -- Handle the case when p_check_position is NULL: Insert if not exists\n BEGIN\n INSERT INTO \"emt_processors\"(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"created_at\", \"last_updated\")\n VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());\n\n -- Dual-write to emt_subscriptions\n INSERT INTO \"emt_subscriptions\"(\"subscription_id\", \"version\", \"last_processed_position\", \"partition\", \"last_processed_transaction_id\")\n VALUES (p_processor_id, p_version, v_position_bigint, p_partition, p_transaction_id)\n ON CONFLICT DO NOTHING;\n\n RETURN 1;\n EXCEPTION WHEN unique_violation THEN\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id AND \"partition\" = p_partition;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSIF current_position > p_position THEN\n RETURN 3; -- Current ahead: another process has progressed further\n ELSE\n RETURN 2;\n END IF;\n END;\n END;\n $fn2$ LANGUAGE plpgsql;\n END IF;\nEND $$;\n`;\n\nexport const migration_0_42_0_FromSubscriptionsToProcessors: SQLMigration =\n sqlMigration(\n 'emt:postgresql:eventstore:0.42.0:from-subscriptions-to-processors',\n [migration_0_42_0_FromSubscriptionsToProcessorsSQL],\n );\n\nexport const migration_0_42_0_2_AddProcessorProjectionFunctionsSQL = SQL`\nDO $$\nBEGIN\n IF EXISTS (\n SELECT 1 FROM information_schema.tables\n WHERE table_name = 'emt_processors'\n ) AND NOT EXISTS (\n SELECT 1 FROM information_schema.columns\n WHERE table_name = 'emt_processors' AND column_name = 'created_at'\n ) THEN\n ALTER TABLE emt_processors ADD COLUMN created_at TIMESTAMPTZ NOT NULL DEFAULT now();\n END IF;\n\n IF EXISTS (\n SELECT 1 FROM information_schema.tables\n WHERE table_name = 'emt_processors'\n ) AND NOT EXISTS (\n SELECT 1 FROM information_schema.columns\n WHERE table_name = 'emt_processors' AND column_name = 'last_updated'\n ) THEN\n ALTER TABLE emt_processors ADD COLUMN last_updated TIMESTAMPTZ NOT NULL DEFAULT now();\n END IF;\n\n IF EXISTS (\n SELECT 1 FROM information_schema.tables\n WHERE table_name = 'emt_projections'\n ) AND NOT EXISTS (\n SELECT 1 FROM information_schema.columns\n WHERE table_name = 'emt_projections' AND column_name = 'created_at'\n ) THEN\n ALTER TABLE emt_projections ADD COLUMN created_at TIMESTAMPTZ NOT NULL DEFAULT now();\n END IF;\n\n IF EXISTS (\n SELECT 1 FROM information_schema.tables\n WHERE table_name = 'emt_projections'\n ) AND NOT EXISTS (\n SELECT 1 FROM information_schema.columns\n WHERE table_name = 'emt_projections' AND column_name = 'last_updated'\n ) THEN\n ALTER TABLE emt_projections ADD COLUMN last_updated TIMESTAMPTZ NOT NULL DEFAULT now();\n END IF;\nEND $$;\n\nCREATE OR REPLACE FUNCTION emt_try_acquire_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_version INT,\n p_partition TEXT DEFAULT '${SQL.plain(defaultTag)}',\n p_processor_instance_id TEXT DEFAULT 'emt:unknown',\n p_projection_name TEXT DEFAULT NULL,\n p_projection_type VARCHAR(1) DEFAULT NULL,\n p_projection_kind TEXT DEFAULT NULL,\n p_lock_timeout_seconds INT DEFAULT 300\n)\nRETURNS TABLE (acquired BOOLEAN, checkpoint TEXT)\nLANGUAGE plpgsql\nAS $emt_try_acquire_processor_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n ownership_check AS (\n INSERT INTO emt_processors (\n processor_id,\n partition,\n version,\n processor_instance_id,\n status,\n last_processed_checkpoint,\n last_processed_transaction_id,\n created_at,\n last_updated\n )\n SELECT p_processor_id, p_partition, p_version, p_processor_instance_id, 'running', '0000000000000000000', '0'::xid8, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (processor_id, partition, version) DO UPDATE\n SET processor_instance_id = p_processor_instance_id,\n status = 'running',\n last_updated = now()\n WHERE emt_processors.processor_instance_id = p_processor_instance_id\n OR emt_processors.processor_instance_id = 'emt:unknown'\n OR emt_processors.status = 'stopped'\n OR emt_processors.last_updated < now() - (p_lock_timeout_seconds || ' seconds')::interval\n RETURNING last_processed_checkpoint\n ),\n projection_status AS (\n INSERT INTO emt_projections (\n name,\n partition,\n version,\n type,\n kind,\n status,\n definition\n )\n SELECT p_projection_name, p_partition, p_version, p_projection_type, p_projection_kind, 'async_processing', '{}'::jsonb\n WHERE p_projection_name IS NOT NULL\n AND (SELECT last_processed_checkpoint FROM ownership_check) IS NOT NULL\n ON CONFLICT (name, partition, version) DO UPDATE\n SET status = 'async_processing'\n RETURNING name\n )\n SELECT\n (SELECT COUNT(*) > 0 FROM ownership_check),\n (SELECT oc.last_processed_checkpoint FROM ownership_check oc);\nEND;\n$emt_try_acquire_processor_lock$;\n\nCREATE OR REPLACE FUNCTION emt_release_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_partition TEXT,\n p_version INT,\n p_processor_instance_id TEXT DEFAULT 'emt:unknown',\n p_projection_name TEXT DEFAULT NULL\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_release_processor_lock$\nDECLARE\n v_rows_updated INT;\nBEGIN\n IF p_projection_name IS NOT NULL THEN\n UPDATE emt_projections\n SET status = 'active',\n last_updated = now()\n WHERE partition = p_partition\n AND name = p_projection_name\n AND version = p_version;\n END IF;\n\n UPDATE emt_processors\n SET status = 'stopped',\n processor_instance_id = 'emt:unknown',\n last_updated = now()\n WHERE processor_id = p_processor_id\n AND partition = p_partition\n AND version = p_version\n AND processor_instance_id = p_processor_instance_id;\n\n GET DIAGNOSTICS v_rows_updated = ROW_COUNT;\n\n PERFORM pg_advisory_unlock(p_lock_key);\n\n RETURN v_rows_updated > 0;\nEND;\n$emt_release_processor_lock$;\n\nCREATE OR REPLACE FUNCTION emt_try_acquire_projection_lock(\n p_lock_key BIGINT,\n p_partition TEXT,\n p_name TEXT,\n p_version INT\n)\nRETURNS TABLE (acquired BOOLEAN, is_active BOOLEAN)\nLANGUAGE plpgsql\nAS $emt_try_acquire_projection_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock_shared(p_lock_key) AS acquired\n ),\n status_check AS (\n SELECT status = 'active' AS is_active\n FROM emt_projections\n WHERE partition = p_partition AND name = p_name AND version = p_version\n )\n SELECT\n COALESCE((SELECT lc.acquired FROM lock_check lc), false),\n COALESCE((SELECT sc.is_active FROM status_check sc), true);\nEND;\n$emt_try_acquire_projection_lock$;\n\nCREATE OR REPLACE FUNCTION emt_register_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT,\n p_type VARCHAR(1),\n p_kind TEXT,\n p_status TEXT,\n p_definition JSONB\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_register_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n upsert_result AS (\n INSERT INTO emt_projections (\n name, partition, version, type, kind, status, definition, created_at, last_updated\n )\n SELECT p_name, p_partition, p_version, p_type, p_kind, p_status, p_definition, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (name, partition, version) DO UPDATE\n SET definition = EXCLUDED.definition,\n last_updated = now()\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM upsert_result;\n\n RETURN v_result;\nEND;\n$emt_register_projection$;\n\nCREATE OR REPLACE FUNCTION emt_activate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_activate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE emt_projections\n SET status = 'active',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_activate_projection$;\n\nCREATE OR REPLACE FUNCTION emt_deactivate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_deactivate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE emt_projections\n SET status = 'inactive',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_deactivate_projection$;\n`;\n\nexport const migration_0_42_0_2_AddProcessorProjectionFunctions: SQLMigration =\n sqlMigration(\n 'emt:postgresql:eventstore:0.42.0-2:add-processor-projection-functions',\n [migration_0_42_0_2_AddProcessorProjectionFunctionsSQL],\n );\n","import { SQL } from '@event-driven-io/dumbo';\n\nexport const schema_0_42_0 = SQL`\n CREATE TABLE IF NOT EXISTS emt_streams(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\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, partition, is_archived)\n ) PARTITION BY LIST (partition);\n \n CREATE UNIQUE INDEX IF NOT EXISTS idx_streams_unique \n ON emt_streams(stream_id, partition, is_archived) \n INCLUDE (stream_position);\n CREATE SEQUENCE IF NOT EXISTS emt_global_message_position;\n\n CREATE TABLE IF NOT EXISTS emt_messages(\n stream_position BIGINT NOT NULL,\n global_position BIGINT DEFAULT nextval('emt_global_message_position'),\n transaction_id XID8 NOT NULL,\n created TIMESTAMPTZ NOT NULL DEFAULT now(),\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n message_kind VARCHAR(1) NOT NULL DEFAULT 'E',\n stream_id TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\n message_schema_version TEXT NOT NULL,\n message_id TEXT NOT NULL,\n message_type TEXT NOT NULL,\n message_data JSONB NOT NULL,\n message_metadata JSONB NOT NULL,\n PRIMARY KEY (stream_id, stream_position, partition, is_archived)\n ) PARTITION BY LIST (partition);\n CREATE TABLE IF NOT EXISTS emt_projections(\n version INT NOT NULL DEFAULT 1,\n type VARCHAR(1) NOT NULL,\n name TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\n kind TEXT NOT NULL,\n status TEXT NOT NULL,\n definition JSONB NOT NULL DEFAULT '{}'::jsonb,\n created_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (name, partition, version)\n ) PARTITION BY LIST (partition);\n\n CREATE TABLE IF NOT EXISTS emt_processors(\n last_processed_transaction_id XID8 NOT NULL,\n version INT NOT NULL DEFAULT 1,\n processor_id TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT 'emt:default',\n status TEXT NOT NULL DEFAULT 'stopped',\n last_processed_checkpoint TEXT NOT NULL,\n processor_instance_id TEXT DEFAULT 'emt:unknown',\n created_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (processor_id, partition, version)\n ) PARTITION BY LIST (partition);\n\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_sanitize_name') THEN\n CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $emt_sanitize_name$\n BEGIN\n RETURN REGEXP_REPLACE(input_name, '[^a-zA-Z0-9_]', '_', 'g');\n END;\n $emt_sanitize_name$ LANGUAGE plpgsql;\nEND IF;\nEND $$;\n\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_add_table_partition') THEN\n \n CREATE OR REPLACE FUNCTION emt_add_table_partition(tableName TEXT, partition_name TEXT) RETURNS void AS $emt_add_table_partition$\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\n -- create default 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 $emt_add_table_partition$ LANGUAGE plpgsql;\nEND IF;\nEND $$;\n\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_add_partition') THEN\n \n CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $emt_add_partition$\n BEGIN \n PERFORM emt_add_table_partition('emt_messages', partition_name);\n PERFORM emt_add_table_partition('emt_streams', partition_name);\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_processors' || '_' || partition_name), 'emt_processors', partition_name\n );\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('emt_projections' || '_' || partition_name), 'emt_projections', partition_name\n );\n END;\n $emt_add_partition$ LANGUAGE plpgsql;\nEND IF;\nEND $$;\n\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_append_to_stream') THEN\n CREATE OR REPLACE FUNCTION emt_append_to_stream(\n v_message_ids text[],\n v_messages_data jsonb[],\n v_messages_metadata jsonb[],\n v_message_schema_versions text[],\n v_message_types text[],\n v_message_kinds 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 global_positions bigint[],\n transaction_id xid8\n ) LANGUAGE plpgsql\n AS $emt_append_to_stream$\n DECLARE\n v_next_stream_position bigint;\n v_position bigint;\n v_updated_rows int;\n v_transaction_id xid8;\n v_global_positions bigint[];\n BEGIN\n v_transaction_id := pg_current_xact_id();\n\n IF v_expected_stream_position IS NULL THEN\n SELECT COALESCE(\n (SELECT stream_position \n FROM emt_streams\n WHERE stream_id = v_stream_id \n AND partition = v_partition \n AND is_archived = FALSE\n LIMIT 1), \n 0\n ) INTO v_expected_stream_position;\n END IF;\n\n v_next_stream_position := v_expected_stream_position + array_upper(v_messages_data, 1);\n\n IF v_expected_stream_position = 0 THEN\n INSERT INTO emt_streams\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 emt_streams 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 WITH ev AS (\n SELECT row_number() OVER () + v_expected_stream_position AS stream_position, \n message_data, \n message_metadata, \n schema_version, \n message_id, \n message_type,\n message_kind\n FROM (\n SELECT *\n FROM \n unnest(v_message_ids, v_messages_data, v_messages_metadata, v_message_schema_versions, v_message_types, v_message_kinds) \n AS message(message_id, message_data, message_metadata, schema_version, message_type, message_kind)\n ) AS message\n ),\n all_messages_insert AS (\n INSERT INTO emt_messages\n (stream_id, stream_position, partition, message_data, message_metadata, message_schema_version, message_type, message_kind, message_id, transaction_id)\n SELECT \n v_stream_id, ev.stream_position, v_partition, ev.message_data, ev.message_metadata, ev.schema_version, ev.message_type, ev.message_kind, ev.message_id, v_transaction_id\n FROM ev\n RETURNING global_position\n )\n SELECT \n array_agg(global_position ORDER BY global_position) INTO v_global_positions\n FROM \n all_messages_insert;\n\n RETURN QUERY SELECT TRUE, v_next_stream_position, v_global_positions, v_transaction_id;\n END;\n $emt_append_to_stream$;\n \nEND IF;\nEND $$;\nSELECT emt_add_partition('emt:default');\nDO $$\nBEGIN\nIF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'store_processor_checkpoint') THEN\n \nCREATE OR REPLACE FUNCTION store_processor_checkpoint(\n p_processor_id TEXT,\n p_version BIGINT,\n p_position TEXT,\n p_check_position TEXT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT 'emt:default',\n p_processor_instance_id TEXT DEFAULT 'emt:unknown'\n) RETURNS INT AS $spc$\nDECLARE\n current_position TEXT;\nBEGIN\n -- Handle the case when p_check_position is provided\n IF p_check_position IS NOT NULL THEN\n -- Try to update if the position matches p_check_position\n UPDATE \"emt_processors\"\n SET\n \"last_processed_checkpoint\" = p_position,\n \"last_processed_transaction_id\" = p_transaction_id,\n \"last_updated\" = now()\n WHERE \"processor_id\" = p_processor_id\n AND \"last_processed_checkpoint\" = p_check_position\n AND \"partition\" = p_partition\n AND \"version\" = p_version;\n\n IF FOUND THEN\n RETURN 1; -- Successfully updated\n END IF;\n\n -- Retrieve the current position\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n -- Return appropriate codes based on current position\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSIF current_position > p_position THEN\n RETURN 3; -- Current ahead: another process has progressed further\n ELSE\n RETURN 2; -- Mismatch: check position doesn't match current\n END IF;\n END IF;\n\n -- Handle the case when p_check_position is NULL: Insert if not exists\n BEGIN\n INSERT INTO \"emt_processors\"(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"created_at\", \"last_updated\")\n VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());\n RETURN 1; -- Successfully inserted\n EXCEPTION WHEN unique_violation THEN\n -- If insertion failed, it means the row already exists\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSIF current_position > p_position THEN\n RETURN 3; -- Current ahead: another process has progressed further\n ELSE\n RETURN 2; -- Insertion failed, row already exists with different position\n END IF;\n END;\nEND;\n$spc$ LANGUAGE plpgsql;\n\nEND IF;\nEND $$;\n\nCREATE OR REPLACE FUNCTION emt_try_acquire_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_version INT,\n p_partition TEXT DEFAULT 'emt:default',\n p_processor_instance_id TEXT DEFAULT 'emt:unknown',\n p_projection_name TEXT DEFAULT NULL,\n p_projection_type VARCHAR(1) DEFAULT NULL,\n p_projection_kind TEXT DEFAULT NULL,\n p_lock_timeout_seconds INT DEFAULT 300\n)\nRETURNS TABLE (acquired BOOLEAN, checkpoint TEXT)\nLANGUAGE plpgsql\nAS $emt_try_acquire_processor_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n ownership_check AS (\n INSERT INTO emt_processors (\n processor_id,\n partition,\n version,\n processor_instance_id,\n status,\n last_processed_checkpoint,\n last_processed_transaction_id,\n created_at,\n last_updated\n )\n SELECT p_processor_id, p_partition, p_version, p_processor_instance_id, 'running', '0000000000000000000', '0'::xid8, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (processor_id, partition, version) DO UPDATE\n SET processor_instance_id = p_processor_instance_id,\n status = 'running',\n last_updated = now()\n WHERE emt_processors.processor_instance_id = p_processor_instance_id\n OR emt_processors.processor_instance_id = 'emt:unknown'\n OR emt_processors.status = 'stopped'\n OR emt_processors.last_updated < now() - (p_lock_timeout_seconds || ' seconds')::interval\n RETURNING last_processed_checkpoint\n ),\n projection_status AS (\n INSERT INTO emt_projections (\n name,\n partition,\n version,\n type,\n kind,\n status,\n definition\n )\n SELECT p_projection_name, p_partition, p_version, p_projection_type, p_projection_kind, 'async_processing', '{}'::jsonb\n WHERE p_projection_name IS NOT NULL\n AND (SELECT last_processed_checkpoint FROM ownership_check) IS NOT NULL\n ON CONFLICT (name, partition, version) DO UPDATE\n SET status = 'async_processing'\n RETURNING name\n )\n SELECT\n (SELECT COUNT(*) > 0 FROM ownership_check),\n (SELECT oc.last_processed_checkpoint FROM ownership_check oc);\nEND;\n$emt_try_acquire_processor_lock$;\n\nCREATE OR REPLACE FUNCTION emt_release_processor_lock(\n p_lock_key BIGINT,\n p_processor_id TEXT,\n p_partition TEXT,\n p_version INT,\n p_processor_instance_id TEXT DEFAULT 'emt:unknown',\n p_projection_name TEXT DEFAULT NULL\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_release_processor_lock$\nDECLARE\n v_rows_updated INT;\nBEGIN\n IF p_projection_name IS NOT NULL THEN\n UPDATE emt_projections\n SET status = 'active',\n last_updated = now()\n WHERE partition = p_partition\n AND name = p_projection_name\n AND version = p_version;\n END IF;\n\n UPDATE emt_processors\n SET status = 'stopped',\n processor_instance_id = 'emt:unknown',\n last_updated = now()\n WHERE processor_id = p_processor_id\n AND partition = p_partition\n AND version = p_version\n AND processor_instance_id = p_processor_instance_id;\n\n GET DIAGNOSTICS v_rows_updated = ROW_COUNT;\n\n PERFORM pg_advisory_unlock(p_lock_key);\n\n RETURN v_rows_updated > 0;\nEND;\n$emt_release_processor_lock$;\n\nCREATE OR REPLACE FUNCTION emt_try_acquire_projection_lock(\n p_lock_key BIGINT,\n p_partition TEXT,\n p_name TEXT,\n p_version INT\n)\nRETURNS TABLE (acquired BOOLEAN, is_active BOOLEAN)\nLANGUAGE plpgsql\nAS $emt_try_acquire_projection_lock$\nBEGIN\n RETURN QUERY\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock_shared(p_lock_key) AS acquired\n ),\n status_check AS (\n SELECT status = 'active' AS is_active\n FROM emt_projections\n WHERE partition = p_partition AND name = p_name AND version = p_version\n )\n SELECT\n COALESCE((SELECT lc.acquired FROM lock_check lc), false),\n COALESCE((SELECT sc.is_active FROM status_check sc), true);\nEND;\n$emt_try_acquire_projection_lock$;\n\nCREATE OR REPLACE FUNCTION emt_register_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT,\n p_type VARCHAR(1),\n p_kind TEXT,\n p_status TEXT,\n p_definition JSONB\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_register_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n upsert_result AS (\n INSERT INTO emt_projections (\n name, partition, version, type, kind, status, definition, created_at, last_updated\n )\n SELECT p_name, p_partition, p_version, p_type, p_kind, p_status, p_definition, now(), now()\n WHERE (SELECT lock_acquired FROM lock_check) = true\n ON CONFLICT (name, partition, version) DO UPDATE\n SET definition = EXCLUDED.definition,\n last_updated = now()\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM upsert_result;\n\n RETURN v_result;\nEND;\n$emt_register_projection$;\n\nCREATE OR REPLACE FUNCTION emt_activate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_activate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE emt_projections\n SET status = 'active',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_activate_projection$;\n\nCREATE OR REPLACE FUNCTION emt_deactivate_projection(\n p_lock_key BIGINT,\n p_name TEXT,\n p_partition TEXT,\n p_version INT\n)\nRETURNS BOOLEAN\nLANGUAGE plpgsql\nAS $emt_deactivate_projection$\nDECLARE\n v_result BOOLEAN;\nBEGIN\n WITH lock_check AS (\n SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired\n ),\n update_result AS (\n UPDATE emt_projections\n SET status = 'inactive',\n last_updated = now()\n WHERE name = p_name\n AND partition = p_partition\n AND version = p_version\n AND (SELECT lock_acquired FROM lock_check) = true\n RETURNING name\n )\n SELECT COUNT(*) > 0 INTO v_result FROM update_result;\n\n RETURN v_result;\nEND;\n$emt_deactivate_projection$;\n`;\n","import { single, SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport type { ProcessorCheckpoint } from '@event-driven-io/emmett';\nimport { createFunctionIfDoesNotExistSQL } from './createFunctionIfDoesNotExist';\nimport { defaultTag, processorsTable, unknownTag } from './typing';\n\nexport const storeSubscriptionCheckpointSQL = createFunctionIfDoesNotExistSQL(\n 'store_processor_checkpoint',\n SQL`\nCREATE OR REPLACE FUNCTION store_processor_checkpoint(\n p_processor_id TEXT,\n p_version BIGINT,\n p_position TEXT,\n p_check_position TEXT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT '${SQL.plain(defaultTag)}',\n p_processor_instance_id TEXT DEFAULT '${SQL.plain(unknownTag)}'\n) RETURNS INT AS $spc$\nDECLARE\n current_position TEXT;\nBEGIN\n -- Handle the case when p_check_position is provided\n IF p_check_position IS NOT NULL THEN\n -- Try to update if the position matches p_check_position\n UPDATE \"${SQL.plain(processorsTable.name)}\"\n SET\n \"last_processed_checkpoint\" = p_position,\n \"last_processed_transaction_id\" = p_transaction_id,\n \"last_updated\" = now()\n WHERE \"processor_id\" = p_processor_id\n AND \"last_processed_checkpoint\" = p_check_position\n AND \"partition\" = p_partition\n AND \"version\" = p_version;\n\n IF FOUND THEN\n RETURN 1; -- Successfully updated\n END IF;\n\n -- Retrieve the current position\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"${SQL.plain(processorsTable.name)}\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n -- Return appropriate codes based on current position\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSIF current_position > p_position THEN\n RETURN 3; -- Current ahead: another process has progressed further\n ELSE\n RETURN 2; -- Mismatch: check position doesn't match current\n END IF;\n END IF;\n\n -- Handle the case when p_check_position is NULL: Insert if not exists\n BEGIN\n INSERT INTO \"${SQL.plain(processorsTable.name)}\"(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"created_at\", \"last_updated\")\n VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());\n RETURN 1; -- Successfully inserted\n EXCEPTION WHEN unique_violation THEN\n -- If insertion failed, it means the row already exists\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"${SQL.plain(processorsTable.name)}\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0; -- Idempotent check: position already set\n ELSIF current_position > p_position THEN\n RETURN 3; -- Current ahead: another process has progressed further\n ELSE\n RETURN 2; -- Insertion failed, row already exists with different position\n END IF;\n END;\nEND;\n$spc$ LANGUAGE plpgsql;\n`,\n);\n\ntype CallStoreProcessorCheckpointParams = {\n processorId: string;\n version: number;\n position: string | null;\n checkPosition: string | null;\n partition: string;\n processorInstanceId: string;\n};\n\nexport const callStoreProcessorCheckpoint = (\n params: CallStoreProcessorCheckpointParams,\n) =>\n SQL`\n SELECT store_processor_checkpoint(\n ${params.processorId}, \n ${params.version}, \n ${params.position}, \n ${params.checkPosition}, \n pg_current_xact_id(), \n ${params.partition}, \n ${params.processorInstanceId}\n ) as result;`;\n\nexport type StoreProcessorCheckpointResult =\n | {\n success: true;\n newCheckpoint: ProcessorCheckpoint | null;\n }\n | { success: false; reason: 'IGNORED' | 'MISMATCH' | 'CURRENT_AHEAD' };\n\nexport const storeProcessorCheckpoint = async (\n execute: SQLExecutor,\n options: {\n processorId: string;\n version: number | undefined;\n newCheckpoint: ProcessorCheckpoint | null;\n lastProcessedCheckpoint: ProcessorCheckpoint | null;\n partition?: string;\n processorInstanceId?: string;\n },\n): Promise<StoreProcessorCheckpointResult> => {\n try {\n const { result } = await single(\n execute.command<{ result: 0 | 1 | 2 | 3 }>(\n callStoreProcessorCheckpoint({\n processorId: options.processorId,\n version: options.version ?? 1,\n position:\n options.newCheckpoint !== null ? options.newCheckpoint : null,\n checkPosition:\n options.lastProcessedCheckpoint !== null\n ? options.lastProcessedCheckpoint\n : null,\n partition: options.partition ?? defaultTag,\n processorInstanceId: options.processorInstanceId ?? unknownTag,\n }),\n ),\n );\n\n return result === 1\n ? { success: true, newCheckpoint: options.newCheckpoint }\n : {\n success: false,\n reason:\n result === 0\n ? 'IGNORED'\n : result === 3\n ? 'CURRENT_AHEAD'\n : 'MISMATCH',\n };\n } catch (error) {\n console.log(error);\n throw error;\n }\n};\n","import {\n dumbo,\n SQL,\n sqlMigration,\n type SQLMigration,\n} from '@event-driven-io/dumbo';\nimport {\n defaultTag,\n messagesTable,\n processorsTable,\n projectionsTable,\n streamsTable,\n} from '../../typing';\n\nexport const migration_0_43_0_cleanupLegacySubscriptionSQL = SQL`\nDO $$\nBEGIN\nIF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'emt_subscriptions') THEN\n -- Restore clean emt_add_partition (remove creation of emt_subscriptions partitions)\n CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $fnpar$\n BEGIN \n PERFORM emt_add_table_partition('${SQL.plain(messagesTable.name)}', partition_name);\n PERFORM emt_add_table_partition('${SQL.plain(streamsTable.name)}', partition_name);\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('${SQL.plain(processorsTable.name)}' || '_' || partition_name), '${SQL.plain(processorsTable.name)}', partition_name\n );\n \n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('${SQL.plain(projectionsTable.name)}' || '_' || partition_name), '${SQL.plain(projectionsTable.name)}', partition_name\n );\n END;\n $fnpar$ LANGUAGE plpgsql;\n\n -- Drop old subscriptions table if it exists\n DROP TABLE IF EXISTS emt_subscriptions CASCADE;\n\n -- Drop old function if it exists\n DROP FUNCTION IF EXISTS store_subscription_checkpoint(character varying, bigint, bigint, bigint, xid8, text);\n \n -- Restore clean store_processor_checkpoint (remove dual-write logic)\n CREATE OR REPLACE FUNCTION store_processor_checkpoint(\n p_processor_id TEXT,\n p_version BIGINT,\n p_position TEXT,\n p_check_position TEXT,\n p_transaction_id xid8,\n p_partition TEXT DEFAULT '${SQL.plain(defaultTag)}',\n p_processor_instance_id TEXT DEFAULT 'emt:unknown'\n ) RETURNS INT AS $fn$\n DECLARE\n current_position TEXT;\n BEGIN\n IF p_check_position IS NOT NULL THEN\n UPDATE \"emt_processors\"\n SET\n \"last_processed_checkpoint\" = p_position,\n \"last_processed_transaction_id\" = p_transaction_id,\n \"last_updated\" = now()\n WHERE \"processor_id\" = p_processor_id\n AND \"last_processed_checkpoint\" = p_check_position\n AND \"partition\" = p_partition \n AND \"version\" = p_version;\n\n IF FOUND THEN\n RETURN 1;\n END IF;\n\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition \n AND \"version\" = p_version ;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSIF current_position > p_position THEN\n RETURN 3;\n ELSE\n RETURN 2;\n END IF;\n END IF;\n\n BEGIN\n INSERT INTO \"emt_processors\"(\"processor_id\", \"version\", \"last_processed_checkpoint\", \"partition\", \"last_processed_transaction_id\", \"created_at\", \"last_updated\")\n VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());\n RETURN 1;\n EXCEPTION WHEN unique_violation THEN\n SELECT \"last_processed_checkpoint\" INTO current_position\n FROM \"emt_processors\"\n WHERE \"processor_id\" = p_processor_id \n AND \"partition\" = p_partition\n AND \"version\" = p_version;\n\n IF current_position = p_position THEN\n RETURN 0;\n ELSE\n RETURN 2;\n END IF;\n END;\n END;\n $fn$ LANGUAGE plpgsql;\nEND IF;\nEND $$;\n`;\n\nexport const migration_0_43_0_cleanupLegacySubscription: SQLMigration =\n sqlMigration('emt:postgresql:eventstore:0.43.0:cleanup-legacy-subscription', [\n migration_0_43_0_cleanupLegacySubscriptionSQL,\n ]);\n\nexport const cleanupLegacySubscriptionTables = async (\n connectionString: string,\n) => {\n const pool = dumbo({ connectionString });\n\n try {\n await pool.withTransaction(async ({ execute }) => {\n await execute.command(migration_0_43_0_cleanupLegacySubscriptionSQL);\n });\n } finally {\n await pool.close();\n }\n};\n","import { SQL } from '@event-driven-io/dumbo';\nimport {\n defaultTag,\n globalTag,\n messagesTable,\n processorsTable,\n projectionsTable,\n streamsTable,\n unknownTag,\n} from './typing';\n\nimport { createFunctionIfDoesNotExistSQL } from './createFunctionIfDoesNotExist';\nimport { cleanupLegacySubscriptionTables } from './migrations/0_43_0';\nexport { cleanupLegacySubscriptionTables };\n\nexport const streamsTableSQL = SQL`\n CREATE TABLE IF NOT EXISTS ${SQL.identifier(streamsTable.name)}(\n stream_id TEXT NOT NULL,\n stream_position BIGINT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${SQL.plain(defaultTag)}',\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, partition, is_archived)\n ) PARTITION BY LIST (partition);\n \n CREATE UNIQUE INDEX IF NOT EXISTS idx_streams_unique \n ON ${SQL.identifier(streamsTable.name)}(stream_id, partition, is_archived) \n INCLUDE (stream_position);`;\n\nexport const messagesTableSQL = SQL`\n CREATE SEQUENCE IF NOT EXISTS emt_global_message_position;\n\n CREATE TABLE IF NOT EXISTS ${SQL.identifier(messagesTable.name)}(\n stream_position BIGINT NOT NULL,\n global_position BIGINT DEFAULT nextval('emt_global_message_position'),\n transaction_id XID8 NOT NULL,\n created TIMESTAMPTZ NOT NULL DEFAULT now(),\n is_archived BOOLEAN NOT NULL DEFAULT FALSE,\n message_kind VARCHAR(1) NOT NULL DEFAULT 'E',\n stream_id TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${SQL.plain(defaultTag)}',\n message_schema_version TEXT NOT NULL,\n message_id TEXT NOT NULL,\n message_type TEXT NOT NULL,\n message_data JSONB NOT NULL,\n message_metadata JSONB NOT NULL,\n PRIMARY KEY (stream_id, stream_position, partition, is_archived)\n ) PARTITION BY LIST (partition);`;\n\nexport const processorsTableSQL = SQL`\n CREATE TABLE IF NOT EXISTS ${SQL.identifier(processorsTable.name)}(\n last_processed_transaction_id XID8 NOT NULL,\n version INT NOT NULL DEFAULT 1,\n processor_id TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${SQL.plain(defaultTag)}',\n status TEXT NOT NULL DEFAULT 'stopped',\n last_processed_checkpoint TEXT NOT NULL,\n processor_instance_id TEXT DEFAULT '${SQL.plain(unknownTag)}',\n created_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (processor_id, partition, version)\n ) PARTITION BY LIST (partition);\n`;\n\nexport const projectionsTableSQL = SQL`\n CREATE TABLE IF NOT EXISTS ${SQL.identifier(projectionsTable.name)}(\n version INT NOT NULL DEFAULT 1,\n type VARCHAR(1) NOT NULL,\n name TEXT NOT NULL,\n partition TEXT NOT NULL DEFAULT '${SQL.plain(defaultTag)}',\n kind TEXT NOT NULL,\n status TEXT NOT NULL,\n definition JSONB NOT NULL DEFAULT '{}'::jsonb,\n created_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),\n PRIMARY KEY (name, partition, version)\n ) PARTITION BY LIST (partition);\n`;\n\nexport const sanitizeNameSQL = createFunctionIfDoesNotExistSQL(\n 'emt_sanitize_name',\n SQL`CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $emt_sanitize_name$\n BEGIN\n RETURN REGEXP_REPLACE(input_name, '[^a-zA-Z0-9_]', '_', 'g');\n END;\n $emt_sanitize_name$ LANGUAGE plpgsql;`,\n);\n\nexport const addTablePartitions = createFunctionIfDoesNotExistSQL(\n 'emt_add_table_partition',\n SQL`\n CREATE OR REPLACE FUNCTION emt_add_table_partition(tableName TEXT, partition_name TEXT) RETURNS void AS $emt_add_table_partition$\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\n -- create default 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 $emt_add_table_partition$ LANGUAGE plpgsql;`,\n);\n\nexport const addPartitionSQL = createFunctionIfDoesNotExistSQL(\n 'emt_add_partition',\n SQL`\n CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $emt_add_partition$\n BEGIN \n PERFORM emt_add_table_partition('${SQL.plain(messagesTable.name)}', partition_name);\n PERFORM emt_add_table_partition('${SQL.plain(streamsTable.name)}', partition_name);\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('${SQL.plain(processorsTable.name)}' || '_' || partition_name), '${SQL.plain(processorsTable.name)}', partition_name\n );\n\n EXECUTE format('\n CREATE TABLE IF NOT EXISTS %I PARTITION OF %I\n FOR VALUES IN (%L);',\n emt_sanitize_name('${SQL.plain(projectionsTable.name)}' || '_' || partition_name), '${SQL.plain(projectionsTable.name)}', partition_name\n );\n END;\n $emt_add_partition$ LANGUAGE plpgsql;`,\n);\n\nexport const addModuleSQL = SQL`\n CREATE OR REPLACE FUNCTION add_module(new_module TEXT) RETURNS void AS $$\n BEGIN\n -- For ${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}'), '${SQL.plain(messagesTable.name)}', new_module, '${SQL.plain(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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}' || '_active'), emt_sanitize_name('${SQL.plain(messagesTable.name)}_' || new_module || '__' || '${SQL.plain(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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}' || '_archived'), emt_sanitize_name('${SQL.plain(messagesTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}')\n );\n \n -- For ${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}'), '${SQL.plain(streamsTable.name)}', new_module, '${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}' || '_active'), emt_sanitize_name('${SQL.plain(streamsTable.name)}_' || new_module || '__' || '${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}' || '_archived'), emt_sanitize_name('${SQL.plain(streamsTable.name)}_' || new_module || '__' || '${SQL.plain(globalTag)}')\n );\n END;\n $$ LANGUAGE plpgsql;\n `;\n\nexport const addTenantSQL = SQL`\n CREATE OR REPLACE FUNCTION add_tenant(new_module TEXT, new_tenant TEXT) RETURNS void AS $$\n BEGIN\n -- For ${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant), '${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant)\n );\n \n -- For ${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant), '${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant)\n );\n END;\n $$ LANGUAGE plpgsql;\n `;\n\nexport const addModuleForAllTenantsSQL = SQL`\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 ${SQL.plain(messagesTable.name)}\n LOOP\n -- For ${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant), '${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant)\n );\n \n -- For ${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant), '${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant)\n );\n END LOOP;\n END;\n $$ LANGUAGE plpgsql;\n `;\n\nexport const addTenantForAllModulesSQL = SQL`\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 = '${SQL.plain(messagesTable.name)}'\n LOOP\n -- For ${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant), '${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${SQL.plain(messagesTable.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('${SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant)\n );\n \n -- For ${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant), '${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${SQL.plain(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('${SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant)\n );\n END LOOP;\n END;\n $$ LANGUAGE plpgsql;\n `;\n\nexport const addDefaultPartitionSQL = SQL`SELECT emt_add_partition('${SQL.plain(defaultTag)}');`;\n","import { singleOrNull, SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport type { ProcessorCheckpoint } from '@event-driven-io/emmett';\nimport { defaultTag, processorsTable } from './typing';\n\ntype ReadProcessorCheckpointSqlResult = {\n last_processed_checkpoint: string;\n};\n\nexport type ReadProcessorCheckpointResult = {\n lastProcessedCheckpoint: ProcessorCheckpoint | null;\n};\n\nexport const readProcessorCheckpoint = async (\n execute: SQLExecutor,\n options: { processorId: string; partition?: string; version?: number },\n): Promise<ReadProcessorCheckpointResult> => {\n const result = await singleOrNull(\n execute.query<ReadProcessorCheckpointSqlResult>(\n SQL`SELECT last_processed_checkpoint\n FROM ${SQL.identifier(processorsTable.name)}\n WHERE partition = ${options?.partition ?? defaultTag} AND processor_id = ${options.processorId} AND version = ${options.version ?? 1}\n LIMIT 1`,\n ),\n );\n\n return {\n lastProcessedCheckpoint:\n result !== null\n ? (result.last_processed_checkpoint as ProcessorCheckpoint)\n : null,\n };\n};\n","import { mapRows, SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n bigIntProcessorCheckpoint,\n upcastRecordedMessage,\n type CombinedReadEventMetadata,\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 { PostgreSQLEventStoreDefaultStreamVersion } from '../postgreSQLEventStore';\nimport { defaultTag, messagesTable } from './typing';\n\ntype ReadStreamSqlResult<EventType extends Event> = {\n stream_position: string;\n message_data: EventDataOf<EventType>;\n message_metadata: EventMetaDataOf<EventType>;\n message_schema_version: string;\n message_type: EventTypeOf<EventType>;\n message_id: string;\n global_position: string;\n transaction_id: string;\n created: string;\n};\n\nexport const readStream = async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>(\n execute: SQLExecutor,\n streamId: string,\n options?: ReadStreamOptions<EventType, EventPayloadType> & {\n partition?: string;\n },\n): Promise<\n ReadStreamResult<EventType, ReadEventMetadataWithGlobalPosition>\n> => {\n const fromCondition: string = options?.from\n ? `AND stream_position >= ${options.from}`\n : '';\n\n const to = Number(\n options?.to ??\n (options?.maxCount ? (options.from ?? 0n) + options.maxCount : 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<EventPayloadType>>(\n SQL`SELECT stream_id, stream_position, global_position, message_data, message_metadata, message_schema_version, message_type, message_id\n FROM ${SQL.identifier(messagesTable.name)}\n WHERE stream_id = ${streamId} AND partition = ${options?.partition ?? defaultTag} AND is_archived = FALSE ${SQL.plain(fromCondition)} ${SQL.plain(toCondition)}\n ORDER BY stream_position ASC`,\n ),\n (row) => {\n const rawEvent = {\n type: row.message_type,\n data: row.message_data,\n metadata: row.message_metadata,\n } as unknown as EventPayloadType;\n\n const metadata: ReadEventMetadataWithGlobalPosition = {\n ...('metadata' in rawEvent ? (rawEvent.metadata ?? {}) : {}),\n messageId: row.message_id,\n streamName: streamId,\n streamPosition: BigInt(row.stream_position),\n globalPosition: BigInt(row.global_position),\n checkpoint: bigIntProcessorCheckpoint(BigInt(row.global_position)),\n };\n\n const event = {\n ...rawEvent,\n kind: 'Event',\n metadata: metadata as CombinedReadEventMetadata<\n EventPayloadType,\n ReadEventMetadataWithGlobalPosition\n >,\n };\n\n return upcastRecordedMessage(event, options?.schema?.versioning);\n },\n );\n\n return events.length > 0\n ? {\n currentStreamVersion:\n events[events.length - 1]!.metadata.streamPosition,\n events,\n streamExists: true,\n }\n : {\n currentStreamVersion: PostgreSQLEventStoreDefaultStreamVersion,\n events: [],\n streamExists: false,\n };\n};\n","import { SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport type { StreamExistsResult } from '@event-driven-io/emmett';\nimport { defaultTag, streamsTable } from './typing';\n\ntype StreamExistsSqlResult = { exists: boolean };\n\nexport type PostgresStreamExistsOptions = { partition: string };\n\nexport const streamExists = async (\n execute: SQLExecutor,\n streamId: string,\n options?: PostgresStreamExistsOptions,\n): Promise<StreamExistsResult> => {\n const queryResult = await execute.query<StreamExistsSqlResult>(\n SQL`SELECT EXISTS (\n SELECT 1\n from ${SQL.identifier(streamsTable.name)}\n WHERE stream_id = ${streamId} AND partition = ${options?.partition ?? defaultTag} AND is_archived = FALSE)\n `,\n );\n\n return queryResult.rows[0]?.exists ?? false;\n};\n","import {\n dumbo,\n runSQLMigrations,\n sqlMigration,\n type Dumbo,\n type RunSQLMigrationsResult,\n type SQL,\n type SQLMigration,\n} from '@event-driven-io/dumbo';\nimport type { PgPool, PgTransaction } from '@event-driven-io/dumbo/pg';\nimport type { JSONSerializationOptions } from '@event-driven-io/emmett';\nimport type { PostgresEventStoreOptions } from '../postgreSQLEventStore';\nimport { transactionToPostgreSQLProjectionHandlerContext } from '../projections';\nimport { appendToStreamSQL } from './appendToStream';\nimport { migration_0_38_7_and_older } from './migrations/0_38_7';\nimport {\n migration_0_42_0_2_AddProcessorProjectionFunctions,\n migration_0_42_0_FromSubscriptionsToProcessors,\n} from './migrations/0_42_0';\nimport {\n releaseProcessorLockSQL,\n tryAcquireProcessorLockSQL,\n} from './processors';\nimport {\n activateProjectionSQL,\n deactivateProjectionSQL,\n registerProjectionSQL,\n} from './projections';\nimport { storeSubscriptionCheckpointSQL } from './storeProcessorCheckpoint';\nimport {\n addDefaultPartitionSQL,\n addPartitionSQL,\n addTablePartitions,\n messagesTableSQL,\n processorsTableSQL,\n projectionsTableSQL,\n sanitizeNameSQL,\n streamsTableSQL,\n} from './tables';\nexport * from './typing';\n\nexport * from './appendToStream';\nexport * from './migrations';\nexport * from './processors';\nexport * from './projections';\nexport * from './readLastMessageGlobalPosition';\nexport * from './readMessagesBatch';\nexport * from './readProcessorCheckpoint';\nexport * from './readStream';\nexport * from './storeProcessorCheckpoint';\nexport * from './streamExists';\nexport * from './tables';\n\nexport const schemaSQL: SQL[] = [\n streamsTableSQL,\n messagesTableSQL,\n projectionsTableSQL,\n processorsTableSQL,\n sanitizeNameSQL,\n addTablePartitions,\n addPartitionSQL,\n appendToStreamSQL,\n addDefaultPartitionSQL,\n storeSubscriptionCheckpointSQL,\n tryAcquireProcessorLockSQL,\n releaseProcessorLockSQL,\n registerProjectionSQL,\n activateProjectionSQL,\n deactivateProjectionSQL,\n];\n\nexport const schemaMigration = sqlMigration(\n 'emt:postgresql:eventstore:initial',\n schemaSQL,\n);\n\nexport const eventStoreSchemaMigrations: SQLMigration[] = [\n migration_0_38_7_and_older,\n migration_0_42_0_FromSubscriptionsToProcessors,\n migration_0_42_0_2_AddProcessorProjectionFunctions,\n schemaMigration,\n];\n\nexport type CreateEventStoreSchemaOptions = {\n dryRun?: boolean | undefined;\n ignoreMigrationHashMismatch?: boolean | undefined;\n migrationTimeoutMs?: number | undefined;\n} & JSONSerializationOptions;\n\nexport type EventStoreSchemaMigrationOptions = {\n migrationOptions?: CreateEventStoreSchemaOptions;\n};\n\nexport const createEventStoreSchema = (\n connectionString: string,\n pool: PgPool,\n hooks?: PostgresEventStoreOptions['hooks'],\n options?: CreateEventStoreSchemaOptions,\n): Promise<RunSQLMigrationsResult> => {\n return pool.withTransaction(async (tx: PgTransaction) => {\n const context = await transactionToPostgreSQLProjectionHandlerContext(\n connectionString,\n pool as Dumbo,\n tx,\n );\n const nestedPool = dumbo({\n connectionString,\n connection: tx.connection,\n serialization: options?.serialization,\n });\n\n try {\n if (hooks?.onBeforeSchemaCreated) {\n await hooks.onBeforeSchemaCreated(context);\n }\n\n const result = await runSQLMigrations(\n nestedPool,\n eventStoreSchemaMigrations,\n options,\n );\n\n if (hooks?.onAfterSchemaCreated) {\n await hooks.onAfterSchemaCreated(context);\n }\n return result;\n } finally {\n await nestedPool.close();\n }\n });\n};\n","import { SQL, type SQLExecutor } from '@event-driven-io/dumbo';\nimport {\n messagesTable,\n processorsTable,\n projectionsTable,\n streamsTable,\n} from './typing';\n\nexport const truncateTables = async (\n execute: SQLExecutor,\n options?: { resetSequences?: boolean },\n): Promise<void> => {\n await execute.command(\n SQL`TRUNCATE TABLE \n ${SQL.identifier(streamsTable.name)}, \n ${SQL.identifier(messagesTable.name)}, \n ${SQL.identifier(processorsTable.name)}, \n ${SQL.identifier(projectionsTable.name)} \n CASCADE${SQL.plain(options?.resetSequences ? '; ALTER SEQUENCE emt_global_message_position RESTART WITH 1' : '')};`,\n );\n};\n","import {\n dumbo,\n fromDatabaseDriverType,\n getFormatter,\n SQL,\n type MigrationStyle,\n type RunSQLMigrationsResult,\n} from '@event-driven-io/dumbo';\nimport type {\n PgClientConnection,\n PgConnection,\n PgDriverType,\n PgPool,\n PgPoolClientConnection,\n} from '@event-driven-io/dumbo/pg';\nimport {\n assertExpectedVersionMatchesCurrent,\n downcastRecordedMessages,\n ExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResultWithGlobalPosition,\n type Event,\n type EventStore,\n type EventStoreSession,\n type EventStoreSessionFactory,\n type JSONSerializationOptions,\n type ProjectionRegistration,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n type StreamExistsResult,\n} from '@event-driven-io/emmett';\nimport type pg from 'pg';\nimport {\n postgreSQLEventStoreConsumer,\n type PostgreSQLEventStoreConsumer,\n type PostgreSQLEventStoreConsumerConfig,\n} from './consumers';\nimport {\n handleProjections,\n transactionToPostgreSQLProjectionHandlerContext,\n type PostgreSQLProjectionHandlerContext,\n} from './projections';\nimport {\n appendToStream,\n createEventStoreSchema,\n readStream,\n schemaSQL,\n streamExists,\n unknownTag,\n type AppendToStreamBeforeCommitHook,\n type CreateEventStoreSchemaOptions,\n type PostgresStreamExistsOptions,\n} from './schema';\nimport { truncateTables } from './schema/truncateTables';\n\nexport interface PostgresEventStore\n extends\n EventStore<PostgresReadEventMetadata>,\n EventStoreSessionFactory<PostgresEventStore> {\n appendToStream<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResultWithGlobalPosition>;\n consumer<ConsumerEventType extends Event = Event>(\n options?: PostgreSQLEventStoreConsumerConfig<ConsumerEventType>,\n ): PostgreSQLEventStoreConsumer<ConsumerEventType>;\n close(): Promise<void>;\n streamExists(\n streamName: string,\n options?: PostgresStreamExistsOptions,\n ): Promise<StreamExistsResult>;\n schema: {\n sql(): string;\n print(): void;\n migrate(\n options?: CreateEventStoreSchemaOptions,\n ): Promise<RunSQLMigrationsResult>;\n dangerous: {\n truncate(options?: {\n resetSequences?: boolean;\n truncateProjections?: boolean;\n }): Promise<void>;\n };\n };\n}\n\nexport type PostgresReadEventMetadata = ReadEventMetadataWithGlobalPosition;\n\nexport type PostgresReadEvent<EventType extends Event = Event> = ReadEvent<\n EventType,\n PostgresReadEventMetadata\n>;\n\ntype PostgresEventStorePooledOptions =\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n pooled: true;\n pool: pg.Pool;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n pool: pg.Pool;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n pooled: true;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n };\n\ntype PostgresEventStoreNotPooledOptions =\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n pooled: false;\n client: pg.Client;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n client: pg.Client;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n pooled: false;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n connection: PgPoolClientConnection | PgClientConnection;\n pooled?: false;\n }\n | {\n connector?: PgDriverType;\n connectionString?: string;\n database?: string;\n dumbo: PgPool;\n pooled?: false;\n };\n\nexport type PostgresEventStoreConnectionOptions =\n | PostgresEventStorePooledOptions\n | PostgresEventStoreNotPooledOptions;\n\nexport type PostgresEventStoreOptions = {\n projections?: ProjectionRegistration<\n 'inline',\n PostgresReadEventMetadata,\n PostgreSQLProjectionHandlerContext\n >[];\n schema?: { autoMigration?: MigrationStyle };\n connectionOptions?: PostgresEventStoreConnectionOptions;\n hooks?: {\n /**\n * This hook will be called **BEFORE** event store schema is created\n */\n onBeforeSchemaCreated?: (\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<void> | void;\n /**\n * This hook will be called **AFTER** event store schema was created but before transaction commits\n */\n onAfterSchemaCreated?: (\n context: PostgreSQLProjectionHandlerContext,\n ) => Promise<void> | void;\n };\n} & JSONSerializationOptions;\n\nexport const defaultPostgreSQLOptions: PostgresEventStoreOptions = {\n projections: [],\n schema: { autoMigration: 'CreateOrUpdate' },\n};\n\nexport const PostgreSQLEventStoreDefaultStreamVersion = 0n;\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 =\n 'dumbo' in poolOptions\n ? poolOptions.dumbo\n : dumbo({ ...poolOptions, serialization: options.serialization });\n let migrateSchema: Promise<RunSQLMigrationsResult> | undefined = undefined;\n\n const autoGenerateSchema =\n options.schema?.autoMigration === undefined ||\n options.schema?.autoMigration !== 'None';\n\n const inlineProjections = (options.projections ?? [])\n .filter(({ type }) => type === 'inline')\n .map(({ projection }) => projection);\n\n const migrate = async (migrationOptions?: CreateEventStoreSchemaOptions) => {\n if (!migrateSchema) {\n // TODO: Fix this cast when introducing more drivers\n migrateSchema = createEventStoreSchema(\n connectionString,\n pool as PgPool,\n {\n onBeforeSchemaCreated: async (context) => {\n if (options.hooks?.onBeforeSchemaCreated) {\n await options.hooks.onBeforeSchemaCreated(context);\n }\n },\n onAfterSchemaCreated: async (context) => {\n for (const projection of inlineProjections) {\n if (projection.init) {\n await projection.init({\n version: projection.version ?? 1,\n status: 'active',\n registrationType: 'inline',\n context: { ...context, migrationOptions },\n });\n }\n }\n if (options.hooks?.onAfterSchemaCreated) {\n await options.hooks.onAfterSchemaCreated(context);\n }\n },\n },\n migrationOptions,\n );\n }\n return migrateSchema;\n };\n\n const ensureSchemaExists = () => {\n if (!autoGenerateSchema) return Promise.resolve();\n\n return migrate();\n };\n\n const beforeCommitHook: AppendToStreamBeforeCommitHook | undefined =\n inlineProjections.length > 0\n ? async (events, { transaction }) =>\n handleProjections({\n projections: inlineProjections,\n // TODO: Add proper handling of global data\n // Currently it's not available as append doesn't return array of global position but just the last one\n events: events as ReadEvent<Event, PostgresReadEventMetadata>[],\n ...(await transactionToPostgreSQLProjectionHandlerContext(\n connectionString,\n pool,\n transaction,\n )),\n })\n : undefined;\n\n return {\n schema: {\n sql: () =>\n SQL.describe(\n schemaSQL,\n getFormatter(fromDatabaseDriverType(pool.driverType).databaseType),\n ),\n print: () =>\n console.log(\n SQL.describe(\n schemaSQL,\n getFormatter(fromDatabaseDriverType(pool.driverType).databaseType),\n ),\n ),\n migrate,\n dangerous: {\n truncate: (truncateOptions?: {\n resetSequences?: boolean;\n truncateProjections?: boolean;\n }): Promise<void> =>\n pool.withTransaction(async (transaction) => {\n await ensureSchemaExists();\n await truncateTables(transaction.execute, truncateOptions);\n\n if (truncateOptions?.truncateProjections) {\n const projectionContext =\n await transactionToPostgreSQLProjectionHandlerContext(\n connectionString,\n pool,\n transaction,\n );\n for (const projection of options?.projections ?? []) {\n if (projection.projection.truncate)\n await projection.projection.truncate(projectionContext);\n }\n }\n }),\n },\n },\n async aggregateStream<\n State,\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n PostgresReadEventMetadata,\n EventPayloadType\n >,\n ): Promise<AggregateStreamResult<State>> {\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, EventPayloadType>(\n streamName,\n read,\n );\n const currentStreamVersion = result.currentStreamVersion;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n PostgreSQLEventStoreDefaultStreamVersion,\n );\n\n for (const event of result.events) {\n if (!event) continue;\n state = evolve(state, event);\n }\n\n return {\n currentStreamVersion: currentStreamVersion,\n state,\n streamExists: result.streamExists,\n };\n },\n\n readStream: async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n readOptions?: ReadStreamOptions<EventType, EventPayloadType>,\n ): Promise<ReadStreamResult<EventType, PostgresReadEventMetadata>> => {\n await ensureSchemaExists();\n return readStream<EventType, EventPayloadType>(pool.execute, streamName, {\n ...readOptions,\n serialization: options.serialization ?? readOptions?.serialization,\n });\n },\n\n appendToStream: async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n appendOptions?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResultWithGlobalPosition> => {\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 = firstPart && rest.length > 0 ? firstPart : unknownTag;\n\n const appendResult = await appendToStream(\n // TODO: Fix this when introducing more drivers\n pool as PgPool,\n streamName,\n streamType,\n downcastRecordedMessages(events, appendOptions?.schema?.versioning),\n {\n ...(appendOptions as AppendToStreamOptions),\n beforeCommitHook,\n },\n );\n\n if (!appendResult.success)\n throw new ExpectedVersionConflictError(\n -1n, //TODO: Return actual version in case of error\n appendOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n );\n\n return {\n nextExpectedStreamVersion: appendResult.nextStreamPosition,\n lastEventGlobalPosition:\n appendResult.globalPositions[\n appendResult.globalPositions.length - 1\n ]!,\n createdNewStream:\n appendResult.nextStreamPosition >= BigInt(events.length),\n };\n },\n\n streamExists: async (\n streamName: string,\n options?: PostgresStreamExistsOptions,\n ): Promise<StreamExistsResult> => {\n await ensureSchemaExists();\n return streamExists(pool.execute, streamName, options);\n },\n\n consumer: <ConsumerEventType extends Event = Event>(\n options?: PostgreSQLEventStoreConsumerConfig<ConsumerEventType>,\n ): PostgreSQLEventStoreConsumer<ConsumerEventType> =>\n postgreSQLEventStoreConsumer<ConsumerEventType>({\n ...(options ?? {}),\n pool,\n connectionString,\n }),\n\n close: () => pool.close(),\n\n async withSession<T = unknown>(\n callback: (session: EventStoreSession<PostgresEventStore>) => Promise<T>,\n ): Promise<T> {\n return await pool.withConnection(async (connection) => {\n const storeOptions: PostgresEventStoreOptions = {\n ...options,\n connectionOptions: {\n connection: connection as PgConnection,\n },\n schema: {\n ...(options.schema ?? {}),\n autoMigration: 'None',\n },\n };\n\n const eventStore = getPostgreSQLEventStore(\n connectionString,\n storeOptions,\n );\n\n return ensureSchemaExists().then(() =>\n callback({\n eventStore,\n close: () => Promise.resolve(),\n }),\n );\n });\n },\n };\n};\n","import { dumbo, type Dumbo, type SQLExecutor } from '@event-driven-io/dumbo';\nimport type {\n PgClient,\n PgClientConnection,\n PgDriverType,\n PgPool,\n PgPoolClientConnection,\n PgTransaction,\n} from '@event-driven-io/dumbo/pg';\nimport type {\n AnyCommand,\n AnyEvent,\n AnyMessage,\n AnyRecordedMessageMetadata,\n BatchRecordedMessageHandlerWithContext,\n Checkpointer,\n Event,\n JSONSerializationOptions,\n Message,\n MessageProcessingScope,\n MessageProcessor,\n ProcessorHooks,\n ProjectorOptions,\n ReactorOptions,\n ReadEventMetadataWithGlobalPosition,\n SingleMessageHandlerResult,\n SingleRecordedMessageHandlerWithContext,\n WorkflowProcessorContext,\n WorkflowProcessorOptions,\n} from '@event-driven-io/emmett';\nimport {\n defaultProcessorPartition,\n defaultProcessorVersion,\n EmmettError,\n getCheckpoint,\n getProcessorInstanceId,\n getProjectorId,\n getWorkflowId,\n projector,\n reactor,\n unknownTag,\n workflowProcessor,\n} from '@event-driven-io/emmett';\nimport type pg from 'pg';\nimport {\n getPostgreSQLEventStore,\n type PostgresEventStore,\n} from '../postgreSQLEventStore';\nimport {\n DefaultPostgreSQLProcessorLockPolicy,\n postgreSQLProcessorLock,\n type LockAcquisitionPolicy,\n} from '../projections';\nimport {\n readProcessorCheckpoint,\n storeProcessorCheckpoint,\n type EventStoreSchemaMigrationOptions,\n} from '../schema';\nimport type { PostgreSQLEventStoreMessageBatchPullerStartFrom } from './messageBatchProcessing';\n\nexport type PostgreSQLProcessorHandlerContext = {\n partition: string;\n execute: SQLExecutor;\n connection: {\n connectionString: string;\n client: PgClient;\n transaction: PgTransaction;\n pool: Dumbo;\n messageStore: PostgresEventStore;\n };\n} &\n // TODO: Reconsider if it should be for all processors\n EventStoreSchemaMigrationOptions;\n\nexport type PostgreSQLProcessor<MessageType extends Message = AnyMessage> =\n MessageProcessor<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n >;\n\nexport type PostgreSQLProcessorEachMessageHandler<\n MessageType extends Message = Message,\n> = SingleRecordedMessageHandlerWithContext<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n>;\n\nexport type PostgreSQLProcessorEachBatchHandler<\n MessageType extends Message = Message,\n> = BatchRecordedMessageHandlerWithContext<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n>;\n\nexport type PostgreSQLProcessorStartFrom =\n | PostgreSQLEventStoreMessageBatchPullerStartFrom\n | 'CURRENT';\n\ntype PostgreSQLProcessorPooledOptions =\n | {\n connector?: PgDriverType;\n database?: string;\n pooled: true;\n pool: pg.Pool;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n pool: pg.Pool;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n pooled: true;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n };\n\ntype PostgreSQLProcessorNotPooledOptions =\n | {\n connector?: PgDriverType;\n database?: string;\n pooled: false;\n client: pg.Client;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n client: pg.Client;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n pooled: false;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n connection: PgPoolClientConnection | PgClientConnection;\n pooled?: false;\n }\n | {\n connector?: PgDriverType;\n database?: string;\n dumbo: PgPool;\n pooled?: false;\n };\n\nexport type PostgreSQLProcessorConnectionOptions = {\n connectionString: string;\n} & (PostgreSQLProcessorPooledOptions | PostgreSQLProcessorNotPooledOptions);\n\nexport type PostgreSQLCheckpointer<\n MessageType extends AnyMessage = AnyMessage,\n> = Checkpointer<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n>;\n\nexport const postgreSQLCheckpointer = <\n MessageType extends Message = Message,\n>(): PostgreSQLCheckpointer<MessageType> => ({\n read: async (options, context) => {\n const result = await readProcessorCheckpoint(context.execute, options);\n\n return { lastCheckpoint: result?.lastProcessedCheckpoint };\n },\n store: async (options, context) => {\n const newCheckpoint = getCheckpoint(options.message);\n\n const result = await storeProcessorCheckpoint(context.execute, {\n lastProcessedCheckpoint: options.lastCheckpoint,\n newCheckpoint,\n processorId: options.processorId,\n partition: options.partition,\n version: options.version,\n });\n\n return result.success\n ? { success: true, newCheckpoint: result.newCheckpoint }\n : result;\n },\n});\n\ntype PostgreSQLConnectionOptions = {\n connectionOptions?: PostgreSQLProcessorConnectionOptions;\n} & JSONSerializationOptions;\n\ntype PostgreSQLProcessorOptionsBase = PostgreSQLConnectionOptions & {\n lock?: {\n acquisitionPolicy?: LockAcquisitionPolicy;\n timeoutSeconds?: number;\n };\n partition?: string;\n};\nexport type PostgreSQLReactorOptions<\n MessageType extends Message = Message,\n MessagePayloadType extends AnyMessage = MessageType,\n> = ReactorOptions<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext,\n MessagePayloadType\n> &\n PostgreSQLProcessorOptionsBase;\n\nexport type PostgreSQLProjectorOptions<\n EventType extends AnyEvent = AnyEvent,\n EventPayloadType extends Event = EventType,\n> = ProjectorOptions<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext,\n EventPayloadType\n> &\n PostgreSQLProcessorOptionsBase &\n EventStoreSchemaMigrationOptions;\n\nexport type PostgreSQLWorkflowProcessorOptions<\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MetaDataType extends AnyRecordedMessageMetadata = AnyRecordedMessageMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n> = WorkflowProcessorOptions<\n Input,\n State,\n Output,\n MetaDataType,\n HandlerContext,\n StoredMessage\n> &\n PostgreSQLProcessorOptionsBase;\n\nconst postgreSQLProcessingScope = (options: {\n pool: Dumbo | null;\n connectionString: string | null;\n processorId: string;\n partition: string;\n}): MessageProcessingScope<PostgreSQLProcessorHandlerContext> => {\n const processorConnectionString = options.connectionString;\n\n const processorPool = options.pool;\n\n const processingScope: MessageProcessingScope<\n PostgreSQLProcessorHandlerContext\n > = async <Result = SingleMessageHandlerResult>(\n handler: (\n context: PostgreSQLProcessorHandlerContext,\n ) => Result | Promise<Result>,\n partialContext: Partial<PostgreSQLProcessorHandlerContext>,\n ) => {\n const connection = partialContext?.connection;\n const connectionString =\n processorConnectionString ?? connection?.connectionString;\n\n if (!connectionString)\n throw new EmmettError(\n `PostgreSQL processor '${options.processorId}' is missing connection string. Ensure that you passed it through options`,\n );\n\n const pool =\n (!processorConnectionString ||\n connectionString == processorConnectionString\n ? connection?.pool\n : processorPool) ?? processorPool;\n\n if (!pool)\n throw new EmmettError(\n `PostgreSQL processor '${options.processorId}' is missing connection string. Ensure that you passed it through options`,\n );\n\n return pool.withTransaction(async (transaction) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n const client = (await transaction.connection.open()) as PgClient;\n return handler({\n ...partialContext,\n partition: options.partition,\n execute: transaction.execute,\n connection: {\n connectionString,\n pool,\n client,\n transaction: transaction as PgTransaction,\n messageStore: getPostgreSQLEventStore(connectionString, {\n connectionOptions: { client },\n }),\n },\n });\n });\n };\n\n return processingScope;\n};\n\nconst getProcessorPool = (options: PostgreSQLConnectionOptions) => {\n const poolOptions = {\n ...(options.connectionOptions ? options.connectionOptions : {}),\n };\n const processorConnectionString =\n 'connectionString' in poolOptions\n ? (poolOptions.connectionString ?? null)\n : null;\n\n const processorPool =\n 'dumbo' in poolOptions\n ? (poolOptions.dumbo as PgPool)\n : processorConnectionString\n ? dumbo({\n connectionString: processorConnectionString,\n ...poolOptions,\n serialization: options.serialization,\n })\n : null;\n\n return {\n pool: processorPool,\n connectionString: processorConnectionString,\n close:\n processorPool != null && !('dumbo' in poolOptions)\n ? processorPool.close\n : undefined,\n };\n};\n\nconst wrapHooksWithProcessorLocks = <\n HandlerContext extends PostgreSQLProcessorHandlerContext,\n>(\n hooks: ProcessorHooks<HandlerContext> | undefined,\n processorLock: ReturnType<typeof postgreSQLProcessorLock>,\n): ProcessorHooks<HandlerContext> => ({\n ...(hooks ?? {}),\n onStart: async (context: HandlerContext) => {\n await processorLock.tryAcquire({ execute: context.execute });\n\n if (hooks?.onStart) await hooks.onStart(context);\n },\n onClose:\n hooks?.onClose || processorLock\n ? async (context: HandlerContext) => {\n await processorLock.release({ execute: context.execute });\n\n if (hooks?.onClose) await hooks.onClose(context);\n }\n : undefined,\n});\n\nexport const postgreSQLProjector = <\n EventType extends Event = Event,\n EventPayloadType extends Event = EventType,\n>(\n options: PostgreSQLProjectorOptions<EventType, EventPayloadType>,\n): PostgreSQLProcessor<EventType> => {\n const {\n processorId = getProjectorId({\n projectionName: options.projection.name ?? 'unknown',\n }),\n processorInstanceId = getProcessorInstanceId(processorId),\n version = defaultProcessorVersion,\n partition = defaultProcessorPartition,\n lock,\n } = options;\n\n const { pool, connectionString, close } = getProcessorPool(options);\n\n const processorLock = postgreSQLProcessorLock({\n processorId,\n version,\n partition,\n processorInstanceId,\n projection: options.projection\n ? {\n name: options.projection.name ?? unknownTag,\n kind: options.projection.kind ?? unknownTag,\n version: options.projection.version ?? version,\n handlingType: 'async' as const,\n }\n : undefined,\n lockAcquisitionPolicy:\n lock?.acquisitionPolicy ?? DefaultPostgreSQLProcessorLockPolicy,\n lockTimeoutSeconds: lock?.timeoutSeconds,\n });\n\n const hooks: ProcessorHooks<PostgreSQLProcessorHandlerContext> =\n wrapHooksWithProcessorLocks(\n {\n ...(options.hooks ?? {}),\n onInit:\n options.projection.init !== undefined || options.hooks?.onInit\n ? async (context: PostgreSQLProcessorHandlerContext) => {\n if (options.projection.init)\n await options.projection.init({\n version: options.projection.version ?? version,\n status: 'active',\n registrationType: 'async',\n context: {\n ...context,\n migrationOptions: options.migrationOptions,\n },\n });\n if (options.hooks?.onInit)\n await options.hooks.onInit({\n ...context,\n migrationOptions: options.migrationOptions,\n });\n }\n : options.hooks?.onInit,\n onClose: close\n ? async (context: PostgreSQLProcessorHandlerContext) => {\n if (options.hooks?.onClose) await options.hooks?.onClose(context);\n if (close) await close();\n }\n : options.hooks?.onClose,\n },\n processorLock,\n );\n\n const processor = projector<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext,\n EventPayloadType\n >({\n ...options,\n processorId,\n processorInstanceId,\n version,\n partition,\n hooks,\n processingScope: postgreSQLProcessingScope({\n pool,\n connectionString,\n processorId,\n partition,\n }),\n checkpoints: postgreSQLCheckpointer<EventType>(),\n });\n\n return processor;\n};\n\nexport const postgreSQLWorkflowProcessor = <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MetaDataType extends AnyRecordedMessageMetadata = AnyRecordedMessageMetadata,\n HandlerContext extends PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext = PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n>(\n options: PostgreSQLWorkflowProcessorOptions<\n Input,\n State,\n Output,\n MetaDataType,\n HandlerContext,\n StoredMessage\n >,\n): PostgreSQLProcessor<Input | Output> => {\n const {\n processorId = options.processorId ??\n getWorkflowId({\n workflowName: options.workflow.name ?? 'unknown',\n }),\n processorInstanceId = getProcessorInstanceId(processorId),\n version = defaultProcessorVersion,\n partition = defaultProcessorPartition,\n lock,\n } = options;\n\n const { pool, connectionString, close } = getProcessorPool(options);\n\n const processorLock = postgreSQLProcessorLock({\n processorId,\n version,\n partition,\n processorInstanceId,\n projection: undefined,\n lockAcquisitionPolicy:\n lock?.acquisitionPolicy ?? DefaultPostgreSQLProcessorLockPolicy,\n lockTimeoutSeconds: lock?.timeoutSeconds,\n });\n\n const hooks: ProcessorHooks<HandlerContext> = wrapHooksWithProcessorLocks(\n {\n ...(options.hooks ?? {}),\n onClose: close\n ? async (context: PostgreSQLProcessorHandlerContext) => {\n if (options.hooks?.onClose)\n await options.hooks?.onClose(context as HandlerContext);\n if (close) await close();\n }\n : options.hooks?.onClose,\n },\n processorLock,\n );\n\n return workflowProcessor({\n ...options,\n processorId,\n processorInstanceId,\n version,\n partition,\n hooks,\n processingScope: postgreSQLProcessingScope({\n pool,\n connectionString,\n processorId,\n partition,\n }) as unknown as MessageProcessingScope<HandlerContext>,\n checkpoints: postgreSQLCheckpointer<Input | Output>() as Checkpointer<\n Input | Output,\n MetaDataType,\n HandlerContext\n >,\n }) as PostgreSQLProcessor<Input | Output>;\n};\n\nexport const postgreSQLReactor = <\n MessageType extends Message = Message,\n MessagePayloadType extends AnyMessage = MessageType,\n>(\n options: PostgreSQLReactorOptions<MessageType, MessagePayloadType>,\n): PostgreSQLProcessor<MessageType> => {\n const {\n processorId = options.processorId,\n processorInstanceId = getProcessorInstanceId(processorId),\n version = defaultProcessorVersion,\n partition = defaultProcessorPartition,\n lock,\n } = options;\n\n const { pool, connectionString, close } = getProcessorPool(options);\n\n const processorLock = postgreSQLProcessorLock({\n processorId,\n version,\n partition,\n processorInstanceId,\n projection: undefined,\n lockAcquisitionPolicy:\n lock?.acquisitionPolicy ?? DefaultPostgreSQLProcessorLockPolicy,\n lockTimeoutSeconds: lock?.timeoutSeconds,\n });\n\n const hooks: ProcessorHooks<PostgreSQLProcessorHandlerContext> =\n wrapHooksWithProcessorLocks(\n {\n ...(options.hooks ?? {}),\n onClose: close\n ? async (context: PostgreSQLProcessorHandlerContext) => {\n if (options.hooks?.onClose) await options.hooks?.onClose(context);\n if (close) await close();\n }\n : options.hooks?.onClose,\n },\n processorLock,\n );\n\n return reactor({\n ...options,\n processorId,\n processorInstanceId,\n version,\n partition,\n hooks,\n processingScope: postgreSQLProcessingScope({\n pool,\n connectionString,\n processorId,\n partition,\n }),\n checkpoints: postgreSQLCheckpointer<MessageType>(),\n });\n};\n","import { dumbo, type Dumbo } from '@event-driven-io/dumbo';\nimport type {\n AnyCommand,\n JSONSerializationOptions,\n MessageProcessor,\n WorkflowProcessorContext,\n} from '@event-driven-io/emmett';\nimport {\n asyncAwaiter,\n EmmettError,\n type AnyEvent,\n type AnyMessage,\n type AnyRecordedMessageMetadata,\n type AsyncAwaiter,\n type BatchRecordedMessageHandlerWithoutContext,\n type DefaultRecord,\n type Message,\n type MessageConsumer,\n type MessageConsumerOptions,\n type ReadEventMetadataWithGlobalPosition,\n} from '@event-driven-io/emmett';\nimport { v7 as uuid } from 'uuid';\nimport {\n DefaultPostgreSQLEventStoreProcessorBatchSize,\n DefaultPostgreSQLEventStoreProcessorPullingFrequencyInMs,\n postgreSQLEventStoreMessageBatchPuller,\n zipPostgreSQLEventStoreMessageBatchPullerStartFrom,\n type PostgreSQLEventStoreMessageBatchPuller,\n} from './messageBatchProcessing';\nimport {\n postgreSQLProjector,\n postgreSQLReactor,\n postgreSQLWorkflowProcessor,\n type PostgreSQLProcessor,\n type PostgreSQLProcessorHandlerContext,\n type PostgreSQLProjectorOptions,\n type PostgreSQLReactorOptions,\n type PostgreSQLWorkflowProcessorOptions,\n} from './postgreSQLProcessor';\n\nexport type PostgreSQLEventStoreConsumerConfig<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ConsumerMessageType extends Message = any,\n> = MessageConsumerOptions<ConsumerMessageType> & {\n stopWhen?: {\n noMessagesLeft?: boolean;\n };\n pulling?: {\n batchSize?: number;\n pullingFrequencyInMs?: number;\n };\n} & JSONSerializationOptions;\n\nexport type PostgreSQLEventStoreConsumerOptions<\n ConsumerMessageType extends Message = Message,\n> = PostgreSQLEventStoreConsumerConfig<ConsumerMessageType> & {\n connectionString: string;\n pool?: Dumbo;\n};\n\nexport type PostgreSQLEventStoreConsumer<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ConsumerMessageType extends AnyMessage = any,\n> = MessageConsumer<ConsumerMessageType> &\n Readonly<{\n reactor: <MessageType extends AnyMessage = ConsumerMessageType>(\n options: PostgreSQLReactorOptions<MessageType>,\n ) => PostgreSQLProcessor<MessageType>;\n\n workflowProcessor: <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n HandlerContext extends PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext = PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n >(\n options: PostgreSQLWorkflowProcessorOptions<\n Input,\n State,\n Output,\n MetaDataType,\n HandlerContext,\n StoredMessage\n >,\n ) => PostgreSQLProcessor<Input | Output>;\n }> &\n (AnyEvent extends ConsumerMessageType\n ? Readonly<{\n projector: <\n EventType extends AnyEvent = ConsumerMessageType & AnyEvent,\n >(\n options: PostgreSQLProjectorOptions<EventType>,\n ) => PostgreSQLProcessor<EventType>;\n }>\n : object);\n\nexport const postgreSQLEventStoreConsumer = <\n ConsumerMessageType extends Message = AnyMessage,\n>(\n options: PostgreSQLEventStoreConsumerOptions<ConsumerMessageType>,\n): PostgreSQLEventStoreConsumer<ConsumerMessageType> => {\n let isRunning = false;\n let isInitialized = false;\n const { pulling } = options;\n const processors = options.processors ?? [];\n let abortController: AbortController | null = null;\n\n let start: Promise<void>;\n\n let messagePuller: PostgreSQLEventStoreMessageBatchPuller | undefined;\n\n const startedAwaiter: AsyncAwaiter<void> = asyncAwaiter<void>();\n\n const pool = options.pool\n ? options.pool\n : dumbo({\n connectionString: options.connectionString,\n serialization: options.serialization,\n });\n\n const eachBatch: BatchRecordedMessageHandlerWithoutContext<\n ConsumerMessageType,\n ReadEventMetadataWithGlobalPosition\n > = async (messagesBatch) => {\n const activeProcessors = processors.filter((s) => s.isActive);\n\n if (activeProcessors.length === 0)\n return {\n type: 'STOP',\n reason: 'No active processors',\n };\n\n const result = await Promise.allSettled(\n activeProcessors.map(async (s) => {\n // TODO: Add here filtering to only pass messages that can be handled by processor\n return await s.handle(messagesBatch, {\n connection: {\n connectionString: options.connectionString,\n pool,\n },\n });\n }),\n );\n\n return result.some(\n (r) => r.status === 'fulfilled' && r.value?.type !== 'STOP',\n )\n ? undefined\n : {\n type: 'STOP',\n };\n };\n\n const processorContext = {\n execute: pool.execute,\n connection: {\n connectionString: options.connectionString,\n pool,\n client: undefined as never,\n transaction: undefined as never,\n messageStore: undefined as never,\n },\n };\n\n const stopProcessors = () =>\n Promise.all(processors.map((p) => p.close(processorContext)));\n\n const stop = async () => {\n if (!isRunning) return;\n isRunning = false;\n if (messagePuller) {\n abortController?.abort();\n await messagePuller.stop();\n }\n await start;\n\n messagePuller = undefined;\n abortController = null;\n\n await stopProcessors();\n };\n\n const init = async (): Promise<void> => {\n if (isInitialized) return;\n\n const postgresProcessors = processors as unknown as PostgreSQLProcessor[];\n\n for (const processor of postgresProcessors) {\n if (processor.init) {\n await processor.init(processorContext);\n }\n }\n\n isInitialized = true;\n };\n\n return {\n consumerId: options.consumerId ?? uuid(),\n get isRunning() {\n return isRunning;\n },\n whenStarted: (): Promise<void> => startedAwaiter.wait,\n processors,\n init,\n reactor: <MessageType extends AnyMessage = ConsumerMessageType>(\n options: PostgreSQLReactorOptions<MessageType>,\n ): PostgreSQLProcessor<MessageType> => {\n const processor = postgreSQLReactor(options);\n\n processors.push(\n // TODO: change that\n processor as unknown as MessageProcessor<\n ConsumerMessageType,\n AnyRecordedMessageMetadata,\n DefaultRecord\n >,\n );\n\n return processor;\n },\n projector: <EventType extends AnyEvent = ConsumerMessageType & AnyEvent>(\n options: PostgreSQLProjectorOptions<EventType>,\n ): PostgreSQLProcessor<EventType> => {\n const processor = postgreSQLProjector(options);\n\n processors.push(\n // TODO: change that\n processor as unknown as MessageProcessor<\n ConsumerMessageType,\n AnyRecordedMessageMetadata,\n DefaultRecord\n >,\n );\n\n return processor;\n },\n workflowProcessor: <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n HandlerContext extends PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext = PostgreSQLProcessorHandlerContext &\n WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n >(\n options: PostgreSQLWorkflowProcessorOptions<\n Input,\n State,\n Output,\n MetaDataType,\n HandlerContext,\n StoredMessage\n >,\n ): PostgreSQLProcessor<Input | Output> => {\n const processor = postgreSQLWorkflowProcessor(options);\n\n processors.push(\n // TODO: change that\n processor as unknown as MessageProcessor<\n ConsumerMessageType,\n AnyRecordedMessageMetadata,\n DefaultRecord\n >,\n );\n\n return processor;\n },\n start: () => {\n if (isRunning) return start;\n\n startedAwaiter.reset();\n\n if (processors.length === 0) {\n const error = new EmmettError(\n 'Cannot start consumer without at least a single processor',\n );\n startedAwaiter.reject(error);\n return Promise.reject(error);\n }\n\n isRunning = true;\n abortController = new AbortController();\n\n start = (async () => {\n if (!isRunning) return;\n\n try {\n messagePuller = postgreSQLEventStoreMessageBatchPuller({\n stopWhen: options.stopWhen,\n executor: pool.execute,\n eachBatch,\n batchSize:\n pulling?.batchSize ??\n DefaultPostgreSQLEventStoreProcessorBatchSize,\n pullingFrequencyInMs:\n pulling?.pullingFrequencyInMs ??\n DefaultPostgreSQLEventStoreProcessorPullingFrequencyInMs,\n signal: abortController.signal,\n });\n\n if (!isInitialized) {\n await init();\n }\n\n const startFrom = zipPostgreSQLEventStoreMessageBatchPullerStartFrom(\n await Promise.all(\n processors.map(async (o) => {\n const result = await o.start({\n execute: pool.execute,\n connection: {\n connectionString: options.connectionString,\n pool,\n },\n });\n\n return result;\n }),\n ),\n );\n\n await messagePuller.start({\n startFrom,\n started: startedAwaiter,\n });\n } catch (error) {\n isRunning = false;\n startedAwaiter.reject(error);\n throw error;\n } finally {\n await stopProcessors();\n }\n })();\n\n return start;\n },\n stop,\n close: async () => {\n await stop();\n await pool.close();\n },\n };\n};\n","import {\n getProjectorId,\n unknownTag,\n type AnyEvent,\n type ProjectorOptions,\n type ReadEventMetadataWithGlobalPosition,\n} from '@event-driven-io/emmett';\nimport type { PostgreSQLProjectionDefinition } from '../projections';\nimport type { LockAcquisitionPolicy } from '../projections/locks';\nimport {\n postgreSQLEventStoreConsumer,\n type PostgreSQLEventStoreConsumer,\n type PostgreSQLEventStoreConsumerOptions,\n} from './postgreSQLEventStoreConsumer';\nimport type { PostgreSQLProcessorHandlerContext } from './postgreSQLProcessor';\n\nconst defaultRebuildLockPolicy: LockAcquisitionPolicy = {\n type: 'retry',\n retries: 100,\n minTimeout: 100,\n maxTimeout: 5000,\n};\n\nexport const rebuildPostgreSQLProjections = <\n EventType extends AnyEvent = AnyEvent,\n>(\n options: Omit<\n PostgreSQLEventStoreConsumerOptions<EventType>,\n 'stopWhen' | 'processors'\n > & {\n lock?: {\n acquisitionPolicy?: LockAcquisitionPolicy;\n timeoutSeconds?: number;\n };\n } & (\n | {\n projections: (\n | ProjectorOptions<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n >\n | PostgreSQLProjectionDefinition<EventType>\n )[];\n }\n | ProjectorOptions<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n >\n ),\n): PostgreSQLEventStoreConsumer<EventType> => {\n const consumer = postgreSQLEventStoreConsumer({\n ...options,\n stopWhen: { noMessagesLeft: true },\n });\n\n const lock = { acquisitionPolicy: defaultRebuildLockPolicy, ...options.lock };\n\n const projections: (Omit<\n ProjectorOptions<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n PostgreSQLProcessorHandlerContext\n >,\n 'processorId'\n > & { processorId?: string })[] =\n 'projections' in options\n ? options.projections.map((p) =>\n 'projection' in p\n ? {\n truncateOnStart: true,\n processorId: getProjectorId({\n projectionName: p.projection.name ?? unknownTag,\n }),\n ...p,\n }\n : {\n projection: p,\n processorId: getProjectorId({\n projectionName: p.name ?? unknownTag,\n }),\n truncateOnStart: true,\n },\n )\n : [options];\n\n for (const projectionDefinition of projections) {\n consumer.projector({\n ...projectionDefinition,\n truncateOnStart: projectionDefinition.truncateOnStart ?? true,\n lock,\n });\n }\n\n return consumer;\n};\n"],"mappings":"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"}