@event-driven-io/emmett-postgresql 0.43.0-beta.15 → 0.43.0-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +824 -1449
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -43
- package/dist/index.d.ts +7 -43
- package/dist/index.js +827 -1444
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -9,7 +9,7 @@ let _event_driven_io_pongo_pg = require("@event-driven-io/pongo/pg");
|
|
|
9
9
|
const emmettPrefix = "emt";
|
|
10
10
|
const globalTag = "global";
|
|
11
11
|
const defaultTag = `${"emt"}:default`;
|
|
12
|
-
const unknownTag = `${"emt"}:unknown`;
|
|
12
|
+
const unknownTag$3 = `${"emt"}:unknown`;
|
|
13
13
|
const globalNames = {
|
|
14
14
|
module: `${"emt"}:module:${globalTag}`,
|
|
15
15
|
tenant: `${"emt"}:tenant:${globalTag}`
|
|
@@ -99,36 +99,43 @@ const postgreSQLEventStoreMessageBatchPuller = ({ executor, batchSize, eachBatch
|
|
|
99
99
|
let isRunning = false;
|
|
100
100
|
let start;
|
|
101
101
|
const pullMessages = async (options) => {
|
|
102
|
-
let after;
|
|
103
102
|
try {
|
|
104
|
-
after
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
103
|
+
let after;
|
|
104
|
+
try {
|
|
105
|
+
after = options.startFrom === "BEGINNING" ? 0n : options.startFrom === "END" ? (await readLastMessageGlobalPosition(executor)).currentGlobalPosition ?? 0n : (0, _event_driven_io_emmett.parseBigIntProcessorCheckpoint)(options.startFrom.lastCheckpoint);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.log("Error occurred during reading last processor checkpoint:", error);
|
|
108
|
+
options.started?.reject(error);
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
options.started?.resolve();
|
|
112
|
+
const readMessagesOptions = {
|
|
113
|
+
after,
|
|
114
|
+
batchSize
|
|
115
|
+
};
|
|
116
|
+
let waitTime = 100;
|
|
117
|
+
while (isRunning && !signal?.aborted) {
|
|
118
|
+
const { messages, currentGlobalPosition, areMessagesLeft } = await readMessagesBatch(executor, readMessagesOptions);
|
|
119
|
+
if (messages.length > 0) {
|
|
120
|
+
const result = await eachBatch(messages);
|
|
121
|
+
if (result && result.type === "STOP") {
|
|
122
|
+
isRunning = false;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
readMessagesOptions.after = currentGlobalPosition;
|
|
127
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
128
|
+
if (stopWhen?.noMessagesLeft === true && !areMessagesLeft) {
|
|
129
|
+
console.log(`No messages left to process after reaching global position ${currentGlobalPosition}. Stopping the puller.`);
|
|
120
130
|
isRunning = false;
|
|
121
131
|
break;
|
|
122
132
|
}
|
|
133
|
+
if (!areMessagesLeft) waitTime = Math.min(waitTime * 2, 1e3);
|
|
134
|
+
else waitTime = pullingFrequencyInMs;
|
|
123
135
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
isRunning = false;
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
if (!areMessagesLeft) waitTime = Math.min(waitTime * 2, 1e3);
|
|
131
|
-
else waitTime = pullingFrequencyInMs;
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.log("Error occurred during message pulling:", error);
|
|
138
|
+
throw error;
|
|
132
139
|
}
|
|
133
140
|
};
|
|
134
141
|
return {
|
|
@@ -240,7 +247,7 @@ CREATE OR REPLACE FUNCTION emt_try_acquire_processor_lock(
|
|
|
240
247
|
p_processor_id TEXT,
|
|
241
248
|
p_version INT,
|
|
242
249
|
p_partition TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
243
|
-
p_processor_instance_id TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(unknownTag)}',
|
|
250
|
+
p_processor_instance_id TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(unknownTag$3)}',
|
|
244
251
|
p_projection_name TEXT DEFAULT NULL,
|
|
245
252
|
p_projection_type VARCHAR(1) DEFAULT NULL,
|
|
246
253
|
p_projection_kind TEXT DEFAULT NULL,
|
|
@@ -249,6 +256,9 @@ CREATE OR REPLACE FUNCTION emt_try_acquire_processor_lock(
|
|
|
249
256
|
RETURNS TABLE (acquired BOOLEAN, checkpoint TEXT)
|
|
250
257
|
LANGUAGE plpgsql
|
|
251
258
|
AS $emt_try_acquire_processor_lock$
|
|
259
|
+
DECLARE
|
|
260
|
+
current_position TEXT;
|
|
261
|
+
v_current_time TIMESTAMPTZ := clock_timestamp();
|
|
252
262
|
BEGIN
|
|
253
263
|
RETURN QUERY
|
|
254
264
|
WITH lock_check AS (
|
|
@@ -266,16 +276,16 @@ BEGIN
|
|
|
266
276
|
created_at,
|
|
267
277
|
last_updated
|
|
268
278
|
)
|
|
269
|
-
SELECT p_processor_id, p_partition, p_version, p_processor_instance_id, 'running', '${_event_driven_io_dumbo.SQL.plain(_event_driven_io_emmett.bigInt.toNormalizedString(0n))}', '0'::xid8,
|
|
279
|
+
SELECT p_processor_id, p_partition, p_version, p_processor_instance_id, 'running', '${_event_driven_io_dumbo.SQL.plain(_event_driven_io_emmett.bigInt.toNormalizedString(0n))}', '0'::xid8, v_current_time, v_current_time
|
|
270
280
|
WHERE (SELECT lock_acquired FROM lock_check) = true
|
|
271
281
|
ON CONFLICT (processor_id, partition, version) DO UPDATE
|
|
272
282
|
SET processor_instance_id = p_processor_instance_id,
|
|
273
283
|
status = 'running',
|
|
274
|
-
last_updated =
|
|
284
|
+
last_updated = v_current_time
|
|
275
285
|
WHERE ${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}.processor_instance_id = p_processor_instance_id
|
|
276
|
-
OR ${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}.processor_instance_id = '${_event_driven_io_dumbo.SQL.plain(unknownTag)}'
|
|
286
|
+
OR ${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}.processor_instance_id = '${_event_driven_io_dumbo.SQL.plain(unknownTag$3)}'
|
|
277
287
|
OR ${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}.status = 'stopped'
|
|
278
|
-
OR ${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}.last_updated <
|
|
288
|
+
OR ${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}.last_updated < v_current_time - (p_lock_timeout_seconds || ' seconds')::interval
|
|
279
289
|
RETURNING last_processed_checkpoint
|
|
280
290
|
),
|
|
281
291
|
projection_status AS (
|
|
@@ -307,7 +317,7 @@ CREATE OR REPLACE FUNCTION emt_release_processor_lock(
|
|
|
307
317
|
p_processor_id TEXT,
|
|
308
318
|
p_partition TEXT,
|
|
309
319
|
p_version INT,
|
|
310
|
-
p_processor_instance_id TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(unknownTag)}',
|
|
320
|
+
p_processor_instance_id TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(unknownTag$3)}',
|
|
311
321
|
p_projection_name TEXT DEFAULT NULL
|
|
312
322
|
)
|
|
313
323
|
RETURNS BOOLEAN
|
|
@@ -327,7 +337,7 @@ BEGIN
|
|
|
327
337
|
|
|
328
338
|
UPDATE ${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}
|
|
329
339
|
SET status = 'stopped',
|
|
330
|
-
processor_instance_id = '${_event_driven_io_dumbo.SQL.plain(unknownTag)}',
|
|
340
|
+
processor_instance_id = '${_event_driven_io_dumbo.SQL.plain(unknownTag$3)}',
|
|
331
341
|
last_updated = now()
|
|
332
342
|
WHERE processor_id = p_processor_id
|
|
333
343
|
AND partition = p_partition
|
|
@@ -380,6 +390,7 @@ const tryAcquireProcessorLock = async (execute, options) => {
|
|
|
380
390
|
projectionKind: options.projection?.kind ?? null,
|
|
381
391
|
lockTimeoutSeconds: options.lockTimeoutSeconds ?? 300
|
|
382
392
|
})));
|
|
393
|
+
console.log(`Lock acquisition attempt for processor '${options.processorId}' with processor instance '${options.processorInstanceId}' and lock '${options.lockKey}' resulted in: ${acquired}`);
|
|
383
394
|
return acquired ? {
|
|
384
395
|
acquired: true,
|
|
385
396
|
checkpoint
|
|
@@ -405,6 +416,7 @@ const releaseProcessorLock = async (execute, options) => {
|
|
|
405
416
|
processorInstanceId: options.processorInstanceId,
|
|
406
417
|
projectionName: options.projectionName ?? null
|
|
407
418
|
})));
|
|
419
|
+
console.log(`Lock for processor '${options.processorId}' with processor instance '${options.processorInstanceId}' and lock '${options.lockKey}' released: ${result}`);
|
|
408
420
|
return result;
|
|
409
421
|
};
|
|
410
422
|
|
|
@@ -416,17 +428,26 @@ const postgreSQLProcessorLock = (options) => {
|
|
|
416
428
|
const lockKey = options.lockKey ?? toProcessorLockKey(options);
|
|
417
429
|
return {
|
|
418
430
|
tryAcquire: async (context) => {
|
|
419
|
-
if (acquired)
|
|
431
|
+
if (acquired) {
|
|
432
|
+
console.log(`Lock for processor '${options.processorId}' is already acquired by this instance. Reusing the lock.`);
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
420
435
|
const result = await tryAcquireProcessorLockWithRetry(context.execute, {
|
|
421
436
|
...options,
|
|
422
437
|
lockKey
|
|
423
438
|
});
|
|
424
|
-
if (!result.acquired && options.lockAcquisitionPolicy?.type !== "skip")
|
|
439
|
+
if (!result.acquired && options.lockAcquisitionPolicy?.type !== "skip") {
|
|
440
|
+
console.log(`Failed to acquire lock for processor '${options.processorId}' with policy '${options.lockAcquisitionPolicy?.type}'.`);
|
|
441
|
+
throw new _event_driven_io_emmett.EmmettError(`Failed to acquire lock for processor '${options.processorId}'`);
|
|
442
|
+
}
|
|
425
443
|
acquired = result.acquired;
|
|
426
444
|
return acquired;
|
|
427
445
|
},
|
|
428
446
|
release: async (context) => {
|
|
429
|
-
if (!acquired)
|
|
447
|
+
if (!acquired) {
|
|
448
|
+
console.log(`Lock for processor '${options.processorId}' is not acquired by this instance. Skipping release.`);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
430
451
|
const { projection, ...releaseOptions } = options;
|
|
431
452
|
await releaseProcessorLock(context.execute, {
|
|
432
453
|
...releaseOptions,
|
|
@@ -1217,156 +1238,118 @@ const appendEventsRaw = (execute, streamId, streamType, messages, options) => (0
|
|
|
1217
1238
|
})));
|
|
1218
1239
|
|
|
1219
1240
|
//#endregion
|
|
1220
|
-
//#region src/eventStore/schema/
|
|
1221
|
-
const
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
END IF;
|
|
1232
|
-
|
|
1233
|
-
IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_module_for_all_tenants') THEN
|
|
1234
|
-
DROP FUNCTION add_module_for_all_tenants(TEXT);
|
|
1235
|
-
END IF;
|
|
1236
|
-
|
|
1237
|
-
IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'add_tenant_for_all_modules') THEN
|
|
1238
|
-
DROP FUNCTION add_tenant_for_all_modules(TEXT);
|
|
1239
|
-
END IF;
|
|
1240
|
-
END $$;
|
|
1241
|
-
`;
|
|
1242
|
-
const dropOldAppendToSQLWithoutGlobalPositions = _event_driven_io_dumbo.SQL`
|
|
1243
|
-
DO $$
|
|
1244
|
-
DECLARE
|
|
1245
|
-
v_current_return_type text;
|
|
1246
|
-
BEGIN
|
|
1247
|
-
-- Get the current return type definition as text
|
|
1248
|
-
SELECT pg_get_function_result(p.oid)
|
|
1249
|
-
INTO v_current_return_type
|
|
1250
|
-
FROM pg_proc p
|
|
1251
|
-
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
1252
|
-
WHERE n.nspname = current_schema() -- or specify your schema
|
|
1253
|
-
AND p.proname = 'emt_append_to_stream'
|
|
1254
|
-
AND p.pronargs = 10; -- number of arguments
|
|
1255
|
-
|
|
1256
|
-
-- Check if it contains the old column name
|
|
1257
|
-
IF v_current_return_type IS NOT NULL AND
|
|
1258
|
-
v_current_return_type LIKE '%last_global_position%' AND
|
|
1259
|
-
v_current_return_type NOT LIKE '%global_positions%' THEN
|
|
1260
|
-
DROP FUNCTION emt_append_to_stream(text[], jsonb[], jsonb[], text[], text[], text[], text, text, bigint, text);
|
|
1261
|
-
RAISE NOTICE 'Old version of function dropped. Return type was: %', v_current_return_type;
|
|
1262
|
-
END IF;
|
|
1263
|
-
END $$;
|
|
1264
|
-
`;
|
|
1265
|
-
const migrationFromEventsToMessagesSQL = _event_driven_io_dumbo.SQL`
|
|
1266
|
-
DO $$
|
|
1241
|
+
//#region src/eventStore/schema/storeProcessorCheckpoint.ts
|
|
1242
|
+
const storeSubscriptionCheckpointSQL = createFunctionIfDoesNotExistSQL("store_processor_checkpoint", _event_driven_io_dumbo.SQL`
|
|
1243
|
+
CREATE OR REPLACE FUNCTION store_processor_checkpoint(
|
|
1244
|
+
p_processor_id TEXT,
|
|
1245
|
+
p_version BIGINT,
|
|
1246
|
+
p_position TEXT,
|
|
1247
|
+
p_check_position TEXT,
|
|
1248
|
+
p_transaction_id xid8,
|
|
1249
|
+
p_partition TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
1250
|
+
p_processor_instance_id TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(unknownTag$3)}'
|
|
1251
|
+
) RETURNS INT AS $spc$
|
|
1267
1252
|
DECLARE
|
|
1268
|
-
|
|
1253
|
+
current_position TEXT;
|
|
1269
1254
|
BEGIN
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
END LOOP;
|
|
1255
|
+
-- Handle the case when p_check_position is provided
|
|
1256
|
+
IF p_check_position IS NOT NULL THEN
|
|
1257
|
+
-- Try to update if the position matches p_check_position
|
|
1258
|
+
UPDATE "${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}"
|
|
1259
|
+
SET
|
|
1260
|
+
"last_processed_checkpoint" = p_position,
|
|
1261
|
+
"last_processed_transaction_id" = p_transaction_id,
|
|
1262
|
+
"last_updated" = now()
|
|
1263
|
+
WHERE "processor_id" = p_processor_id
|
|
1264
|
+
AND "last_processed_checkpoint" = p_check_position
|
|
1265
|
+
AND "partition" = p_partition
|
|
1266
|
+
AND "version" = p_version;
|
|
1283
1267
|
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
-- Rename columns
|
|
1288
|
-
ALTER TABLE emt_messages
|
|
1289
|
-
RENAME COLUMN event_data TO message_data;
|
|
1290
|
-
ALTER TABLE emt_messages
|
|
1291
|
-
RENAME COLUMN event_metadata TO message_metadata;
|
|
1292
|
-
ALTER TABLE emt_messages
|
|
1293
|
-
RENAME COLUMN event_schema_version TO message_schema_version;
|
|
1294
|
-
ALTER TABLE emt_messages
|
|
1295
|
-
RENAME COLUMN event_type TO message_type;
|
|
1296
|
-
ALTER TABLE emt_messages
|
|
1297
|
-
RENAME COLUMN event_id TO message_id;
|
|
1298
|
-
ALTER TABLE emt_messages
|
|
1299
|
-
ADD COLUMN message_kind CHAR(1) NOT NULL DEFAULT 'E';
|
|
1268
|
+
IF FOUND THEN
|
|
1269
|
+
RETURN 1; -- Successfully updated
|
|
1270
|
+
END IF;
|
|
1300
1271
|
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
ALTER COLUMN global_position
|
|
1308
|
-
SET DEFAULT nextval('emt_global_message_position');
|
|
1309
|
-
END IF;
|
|
1310
|
-
END IF;
|
|
1311
|
-
END $$;`;
|
|
1312
|
-
const migration_0_38_7_and_older = (0, _event_driven_io_dumbo.sqlMigration)("emt:postgresql:eventstore:0.38.7:migrate-events-to-messages", [
|
|
1313
|
-
dropFutureConceptModuleAndTenantFunctions,
|
|
1314
|
-
dropOldAppendToSQLWithoutGlobalPositions,
|
|
1315
|
-
migrationFromEventsToMessagesSQL
|
|
1316
|
-
]);
|
|
1272
|
+
-- Retrieve the current position
|
|
1273
|
+
SELECT "last_processed_checkpoint" INTO current_position
|
|
1274
|
+
FROM "${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}"
|
|
1275
|
+
WHERE "processor_id" = p_processor_id
|
|
1276
|
+
AND "partition" = p_partition
|
|
1277
|
+
AND "version" = p_version;
|
|
1317
1278
|
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
-- Rename all partitions first
|
|
1328
|
-
FOR partition_record IN
|
|
1329
|
-
SELECT tablename
|
|
1330
|
-
FROM pg_tables
|
|
1331
|
-
WHERE tablename LIKE 'emt_events_%'
|
|
1332
|
-
ORDER BY tablename DESC -- to handle child partitions first
|
|
1333
|
-
LOOP
|
|
1334
|
-
EXECUTE format('ALTER TABLE %I RENAME TO %I',
|
|
1335
|
-
partition_record.tablename,
|
|
1336
|
-
REPLACE(partition_record.tablename, 'events', 'messages'));
|
|
1337
|
-
END LOOP;
|
|
1279
|
+
-- Return appropriate codes based on current position
|
|
1280
|
+
IF current_position = p_position THEN
|
|
1281
|
+
RETURN 0; -- Idempotent check: position already set
|
|
1282
|
+
ELSIF current_position > p_position THEN
|
|
1283
|
+
RETURN 3; -- Current ahead: another process has progressed further
|
|
1284
|
+
ELSE
|
|
1285
|
+
RETURN 2; -- Mismatch: check position doesn't match current
|
|
1286
|
+
END IF;
|
|
1287
|
+
END IF;
|
|
1338
1288
|
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
ALTER TABLE emt_messages
|
|
1352
|
-
RENAME COLUMN event_id TO message_id;
|
|
1353
|
-
ALTER TABLE emt_messages
|
|
1354
|
-
ADD COLUMN message_kind CHAR(1) NOT NULL DEFAULT 'E';
|
|
1289
|
+
-- Handle the case when p_check_position is NULL: Insert if not exists
|
|
1290
|
+
BEGIN
|
|
1291
|
+
INSERT INTO "${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}"("processor_id", "version", "last_processed_checkpoint", "partition", "last_processed_transaction_id", "created_at", "last_updated")
|
|
1292
|
+
VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());
|
|
1293
|
+
RETURN 1; -- Successfully inserted
|
|
1294
|
+
EXCEPTION WHEN unique_violation THEN
|
|
1295
|
+
-- If insertion failed, it means the row already exists
|
|
1296
|
+
SELECT "last_processed_checkpoint" INTO current_position
|
|
1297
|
+
FROM "${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}"
|
|
1298
|
+
WHERE "processor_id" = p_processor_id
|
|
1299
|
+
AND "partition" = p_partition
|
|
1300
|
+
AND "version" = p_version;
|
|
1355
1301
|
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1302
|
+
IF current_position = p_position THEN
|
|
1303
|
+
RETURN 0; -- Idempotent check: position already set
|
|
1304
|
+
ELSIF current_position > p_position THEN
|
|
1305
|
+
RETURN 3; -- Current ahead: another process has progressed further
|
|
1306
|
+
ELSE
|
|
1307
|
+
RETURN 2; -- Insertion failed, row already exists with different position
|
|
1308
|
+
END IF;
|
|
1309
|
+
END;
|
|
1310
|
+
END;
|
|
1311
|
+
$spc$ LANGUAGE plpgsql;
|
|
1312
|
+
`);
|
|
1313
|
+
const callStoreProcessorCheckpoint = (params) => _event_driven_io_dumbo.SQL`
|
|
1314
|
+
SELECT store_processor_checkpoint(
|
|
1315
|
+
${params.processorId},
|
|
1316
|
+
${params.version},
|
|
1317
|
+
${params.position},
|
|
1318
|
+
${params.checkPosition},
|
|
1319
|
+
pg_current_xact_id(),
|
|
1320
|
+
${params.partition},
|
|
1321
|
+
${params.processorInstanceId}
|
|
1322
|
+
) as result;`;
|
|
1323
|
+
const storeProcessorCheckpoint = async (execute, options) => {
|
|
1324
|
+
try {
|
|
1325
|
+
const { result } = await (0, _event_driven_io_dumbo.single)(execute.command(callStoreProcessorCheckpoint({
|
|
1326
|
+
processorId: options.processorId,
|
|
1327
|
+
version: options.version ?? 1,
|
|
1328
|
+
position: options.newCheckpoint !== null ? options.newCheckpoint : null,
|
|
1329
|
+
checkPosition: options.lastProcessedCheckpoint !== null ? options.lastProcessedCheckpoint : null,
|
|
1330
|
+
partition: options.partition ?? defaultTag,
|
|
1331
|
+
processorInstanceId: options.processorInstanceId ?? unknownTag$3
|
|
1332
|
+
})));
|
|
1333
|
+
return result === 1 ? {
|
|
1334
|
+
success: true,
|
|
1335
|
+
newCheckpoint: options.newCheckpoint
|
|
1336
|
+
} : {
|
|
1337
|
+
success: false,
|
|
1338
|
+
reason: result === 0 ? "IGNORED" : result === 3 ? "CURRENT_AHEAD" : "MISMATCH"
|
|
1339
|
+
};
|
|
1340
|
+
} catch (error) {
|
|
1341
|
+
console.log(error);
|
|
1342
|
+
throw error;
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
|
|
1346
|
+
//#endregion
|
|
1347
|
+
//#region src/eventStore/schema/tables.ts
|
|
1348
|
+
const streamsTableSQL = _event_driven_io_dumbo.SQL`
|
|
1349
|
+
CREATE TABLE IF NOT EXISTS ${_event_driven_io_dumbo.SQL.identifier(streamsTable.name)}(
|
|
1367
1350
|
stream_id TEXT NOT NULL,
|
|
1368
1351
|
stream_position BIGINT NOT NULL,
|
|
1369
|
-
partition TEXT NOT NULL DEFAULT '
|
|
1352
|
+
partition TEXT NOT NULL DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
1370
1353
|
stream_type TEXT NOT NULL,
|
|
1371
1354
|
stream_metadata JSONB NOT NULL,
|
|
1372
1355
|
is_archived BOOLEAN NOT NULL DEFAULT FALSE,
|
|
@@ -1374,40 +1357,62 @@ END $$;CREATE TABLE IF NOT EXISTS emt_streams(
|
|
|
1374
1357
|
) PARTITION BY LIST (partition);
|
|
1375
1358
|
|
|
1376
1359
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_streams_unique
|
|
1377
|
-
ON
|
|
1378
|
-
INCLUDE (stream_position)
|
|
1360
|
+
ON ${_event_driven_io_dumbo.SQL.identifier(streamsTable.name)}(stream_id, partition, is_archived)
|
|
1361
|
+
INCLUDE (stream_position);`;
|
|
1362
|
+
const messagesTableSQL = _event_driven_io_dumbo.SQL`
|
|
1379
1363
|
CREATE SEQUENCE IF NOT EXISTS emt_global_message_position;
|
|
1380
1364
|
|
|
1381
|
-
CREATE TABLE IF NOT EXISTS
|
|
1382
|
-
stream_id TEXT NOT NULL,
|
|
1365
|
+
CREATE TABLE IF NOT EXISTS ${_event_driven_io_dumbo.SQL.identifier(messagesTable.name)}(
|
|
1383
1366
|
stream_position BIGINT NOT NULL,
|
|
1384
|
-
partition TEXT NOT NULL DEFAULT 'global',
|
|
1385
|
-
message_kind CHAR(1) NOT NULL DEFAULT 'E',
|
|
1386
|
-
message_data JSONB NOT NULL,
|
|
1387
|
-
message_metadata JSONB NOT NULL,
|
|
1388
|
-
message_schema_version TEXT NOT NULL,
|
|
1389
|
-
message_type TEXT NOT NULL,
|
|
1390
|
-
message_id TEXT NOT NULL,
|
|
1391
|
-
is_archived BOOLEAN NOT NULL DEFAULT FALSE,
|
|
1392
1367
|
global_position BIGINT DEFAULT nextval('emt_global_message_position'),
|
|
1393
1368
|
transaction_id XID8 NOT NULL,
|
|
1394
1369
|
created TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
1370
|
+
is_archived BOOLEAN NOT NULL DEFAULT FALSE,
|
|
1371
|
+
message_kind VARCHAR(1) NOT NULL DEFAULT 'E',
|
|
1372
|
+
stream_id TEXT NOT NULL,
|
|
1373
|
+
partition TEXT NOT NULL DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
1374
|
+
message_schema_version TEXT NOT NULL,
|
|
1375
|
+
message_id TEXT NOT NULL,
|
|
1376
|
+
message_type TEXT NOT NULL,
|
|
1377
|
+
message_data JSONB NOT NULL,
|
|
1378
|
+
message_metadata JSONB NOT NULL,
|
|
1395
1379
|
PRIMARY KEY (stream_id, stream_position, partition, is_archived)
|
|
1380
|
+
) PARTITION BY LIST (partition);`;
|
|
1381
|
+
const processorsTableSQL = _event_driven_io_dumbo.SQL`
|
|
1382
|
+
CREATE TABLE IF NOT EXISTS ${_event_driven_io_dumbo.SQL.identifier(processorsTable.name)}(
|
|
1383
|
+
last_processed_transaction_id XID8 NOT NULL,
|
|
1384
|
+
version INT NOT NULL DEFAULT 1,
|
|
1385
|
+
processor_id TEXT NOT NULL,
|
|
1386
|
+
partition TEXT NOT NULL DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
1387
|
+
status TEXT NOT NULL DEFAULT 'stopped',
|
|
1388
|
+
last_processed_checkpoint TEXT NOT NULL,
|
|
1389
|
+
processor_instance_id TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(unknownTag$3)}',
|
|
1390
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
1391
|
+
last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
1392
|
+
PRIMARY KEY (processor_id, partition, version)
|
|
1396
1393
|
) PARTITION BY LIST (partition);
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1394
|
+
`;
|
|
1395
|
+
const projectionsTableSQL = _event_driven_io_dumbo.SQL`
|
|
1396
|
+
CREATE TABLE IF NOT EXISTS ${_event_driven_io_dumbo.SQL.identifier(projectionsTable.name)}(
|
|
1397
|
+
version INT NOT NULL DEFAULT 1,
|
|
1398
|
+
type VARCHAR(1) NOT NULL,
|
|
1399
|
+
name TEXT NOT NULL,
|
|
1400
|
+
partition TEXT NOT NULL DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
1401
|
+
kind TEXT NOT NULL,
|
|
1402
|
+
status TEXT NOT NULL,
|
|
1403
|
+
definition JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
1404
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
1405
|
+
last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
1406
|
+
PRIMARY KEY (name, partition, version)
|
|
1404
1407
|
) PARTITION BY LIST (partition);
|
|
1405
|
-
|
|
1408
|
+
`;
|
|
1409
|
+
const sanitizeNameSQL = createFunctionIfDoesNotExistSQL("emt_sanitize_name", _event_driven_io_dumbo.SQL`CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $emt_sanitize_name$
|
|
1406
1410
|
BEGIN
|
|
1407
1411
|
RETURN REGEXP_REPLACE(input_name, '[^a-zA-Z0-9_]', '_', 'g');
|
|
1408
1412
|
END;
|
|
1409
|
-
|
|
1410
|
-
|
|
1413
|
+
$emt_sanitize_name$ LANGUAGE plpgsql;`);
|
|
1414
|
+
const addTablePartitions = createFunctionIfDoesNotExistSQL("emt_add_table_partition", _event_driven_io_dumbo.SQL`
|
|
1415
|
+
CREATE OR REPLACE FUNCTION emt_add_table_partition(tableName TEXT, partition_name TEXT) RETURNS void AS $emt_add_table_partition$
|
|
1411
1416
|
DECLARE
|
|
1412
1417
|
v_main_partiton_name TEXT;
|
|
1413
1418
|
v_active_partiton_name TEXT;
|
|
@@ -1437,20 +1442,215 @@ CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $$
|
|
|
1437
1442
|
v_archived_partiton_name, v_main_partiton_name
|
|
1438
1443
|
);
|
|
1439
1444
|
END;
|
|
1440
|
-
|
|
1441
|
-
|
|
1445
|
+
$emt_add_table_partition$ LANGUAGE plpgsql;`);
|
|
1446
|
+
const addPartitionSQL = createFunctionIfDoesNotExistSQL("emt_add_partition", _event_driven_io_dumbo.SQL`
|
|
1447
|
+
CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $emt_add_partition$
|
|
1442
1448
|
BEGIN
|
|
1443
|
-
PERFORM emt_add_table_partition('
|
|
1444
|
-
PERFORM emt_add_table_partition('
|
|
1449
|
+
PERFORM emt_add_table_partition('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}', partition_name);
|
|
1450
|
+
PERFORM emt_add_table_partition('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}', partition_name);
|
|
1451
|
+
|
|
1452
|
+
EXECUTE format('
|
|
1453
|
+
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
1454
|
+
FOR VALUES IN (%L);',
|
|
1455
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}' || '_' || partition_name), '${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}', partition_name
|
|
1456
|
+
);
|
|
1445
1457
|
|
|
1446
1458
|
EXECUTE format('
|
|
1447
1459
|
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
1448
1460
|
FOR VALUES IN (%L);',
|
|
1449
|
-
emt_sanitize_name('
|
|
1461
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(projectionsTable.name)}' || '_' || partition_name), '${_event_driven_io_dumbo.SQL.plain(projectionsTable.name)}', partition_name
|
|
1450
1462
|
);
|
|
1451
1463
|
END;
|
|
1452
|
-
|
|
1464
|
+
$emt_add_partition$ LANGUAGE plpgsql;`);
|
|
1465
|
+
const addModuleSQL = _event_driven_io_dumbo.SQL`
|
|
1466
|
+
CREATE OR REPLACE FUNCTION add_module(new_module TEXT) RETURNS void AS $$
|
|
1467
|
+
BEGIN
|
|
1468
|
+
-- For ${_event_driven_io_dumbo.SQL.plain(messagesTable.name)} table
|
|
1469
|
+
EXECUTE format('
|
|
1470
|
+
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
1471
|
+
FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',
|
|
1472
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}'), '${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}', new_module, '${_event_driven_io_dumbo.SQL.plain(globalTag)}'
|
|
1473
|
+
);
|
|
1474
|
+
|
|
1475
|
+
EXECUTE format('
|
|
1476
|
+
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
1477
|
+
FOR VALUES IN (FALSE);',
|
|
1478
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}' || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}')
|
|
1479
|
+
);
|
|
1480
|
+
|
|
1481
|
+
EXECUTE format('
|
|
1482
|
+
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
1483
|
+
FOR VALUES IN (TRUE);',
|
|
1484
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}' || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}')
|
|
1485
|
+
);
|
|
1486
|
+
|
|
1487
|
+
-- For ${_event_driven_io_dumbo.SQL.plain(streamsTable.name)} table
|
|
1488
|
+
EXECUTE format('
|
|
1489
|
+
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
1490
|
+
FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',
|
|
1491
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}'), '${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}', new_module, '${_event_driven_io_dumbo.SQL.plain(globalTag)}'
|
|
1492
|
+
);
|
|
1493
|
+
|
|
1494
|
+
EXECUTE format('
|
|
1495
|
+
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
1496
|
+
FOR VALUES IN (FALSE);',
|
|
1497
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}' || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}')
|
|
1498
|
+
);
|
|
1499
|
+
|
|
1500
|
+
EXECUTE format('
|
|
1501
|
+
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
1502
|
+
FOR VALUES IN (TRUE);',
|
|
1503
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}' || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}')
|
|
1504
|
+
);
|
|
1505
|
+
END;
|
|
1506
|
+
$$ LANGUAGE plpgsql;
|
|
1507
|
+
`;
|
|
1508
|
+
const addTenantSQL = _event_driven_io_dumbo.SQL`
|
|
1509
|
+
CREATE OR REPLACE FUNCTION add_tenant(new_module TEXT, new_tenant TEXT) RETURNS void AS $$
|
|
1510
|
+
BEGIN
|
|
1511
|
+
-- For ${_event_driven_io_dumbo.SQL.plain(messagesTable.name)} table
|
|
1512
|
+
EXECUTE format('
|
|
1513
|
+
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
1514
|
+
FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
|
|
1515
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant), '${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}', new_module, new_tenant
|
|
1516
|
+
);
|
|
1517
|
+
|
|
1518
|
+
EXECUTE format('
|
|
1519
|
+
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
1520
|
+
FOR VALUES IN (FALSE);',
|
|
1521
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant)
|
|
1522
|
+
);
|
|
1523
|
+
|
|
1524
|
+
EXECUTE format('
|
|
1525
|
+
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
1526
|
+
FOR VALUES IN (TRUE);',
|
|
1527
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant)
|
|
1528
|
+
);
|
|
1529
|
+
|
|
1530
|
+
-- For ${_event_driven_io_dumbo.SQL.plain(streamsTable.name)} table
|
|
1531
|
+
EXECUTE format('
|
|
1532
|
+
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
1533
|
+
FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
|
|
1534
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant), '${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}', new_module, new_tenant
|
|
1535
|
+
);
|
|
1536
|
+
|
|
1537
|
+
EXECUTE format('
|
|
1538
|
+
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
1539
|
+
FOR VALUES IN (FALSE);',
|
|
1540
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant)
|
|
1541
|
+
);
|
|
1542
|
+
|
|
1543
|
+
EXECUTE format('
|
|
1544
|
+
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
1545
|
+
FOR VALUES IN (TRUE);',
|
|
1546
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant)
|
|
1547
|
+
);
|
|
1548
|
+
END;
|
|
1549
|
+
$$ LANGUAGE plpgsql;
|
|
1550
|
+
`;
|
|
1551
|
+
const addModuleForAllTenantsSQL = _event_driven_io_dumbo.SQL`
|
|
1552
|
+
CREATE OR REPLACE FUNCTION add_module_for_all_tenants(new_module TEXT) RETURNS void AS $$
|
|
1553
|
+
DECLARE
|
|
1554
|
+
tenant_record RECORD;
|
|
1555
|
+
BEGIN
|
|
1556
|
+
PERFORM add_module(new_module);
|
|
1557
|
+
|
|
1558
|
+
FOR tenant_record IN SELECT DISTINCT tenant FROM ${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}
|
|
1559
|
+
LOOP
|
|
1560
|
+
-- For ${_event_driven_io_dumbo.SQL.plain(messagesTable.name)} table
|
|
1561
|
+
EXECUTE format('
|
|
1562
|
+
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
1563
|
+
FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
|
|
1564
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant), '${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}', new_module, tenant_record.tenant
|
|
1565
|
+
);
|
|
1566
|
+
|
|
1567
|
+
EXECUTE format('
|
|
1568
|
+
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
1569
|
+
FOR VALUES IN (FALSE);',
|
|
1570
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant)
|
|
1571
|
+
);
|
|
1572
|
+
|
|
1573
|
+
EXECUTE format('
|
|
1574
|
+
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
1575
|
+
FOR VALUES IN (TRUE);',
|
|
1576
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant)
|
|
1577
|
+
);
|
|
1578
|
+
|
|
1579
|
+
-- For ${_event_driven_io_dumbo.SQL.plain(streamsTable.name)} table
|
|
1580
|
+
EXECUTE format('
|
|
1581
|
+
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
1582
|
+
FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
|
|
1583
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant), '${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}', new_module, tenant_record.tenant
|
|
1584
|
+
);
|
|
1585
|
+
|
|
1586
|
+
EXECUTE format('
|
|
1587
|
+
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
1588
|
+
FOR VALUES IN (FALSE);',
|
|
1589
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant)
|
|
1590
|
+
);
|
|
1591
|
+
|
|
1592
|
+
EXECUTE format('
|
|
1593
|
+
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
1594
|
+
FOR VALUES IN (TRUE);',
|
|
1595
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant)
|
|
1596
|
+
);
|
|
1597
|
+
END LOOP;
|
|
1598
|
+
END;
|
|
1599
|
+
$$ LANGUAGE plpgsql;
|
|
1600
|
+
`;
|
|
1601
|
+
const addTenantForAllModulesSQL = _event_driven_io_dumbo.SQL`
|
|
1602
|
+
CREATE OR REPLACE FUNCTION add_tenant_for_all_modules(new_tenant TEXT) RETURNS void AS $$
|
|
1603
|
+
DECLARE
|
|
1604
|
+
module_record RECORD;
|
|
1605
|
+
BEGIN
|
|
1606
|
+
FOR module_record IN SELECT DISTINCT partitionname FROM pg_partman.part_config WHERE parent_table = '${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}'
|
|
1607
|
+
LOOP
|
|
1608
|
+
-- For ${_event_driven_io_dumbo.SQL.plain(messagesTable.name)} table
|
|
1609
|
+
EXECUTE format('
|
|
1610
|
+
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
1611
|
+
FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
|
|
1612
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant), '${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}', module_record.partitionname, new_tenant
|
|
1613
|
+
);
|
|
1614
|
+
|
|
1615
|
+
EXECUTE format('
|
|
1616
|
+
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
1617
|
+
FOR VALUES IN (FALSE);',
|
|
1618
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant)
|
|
1619
|
+
);
|
|
1620
|
+
|
|
1621
|
+
EXECUTE format('
|
|
1622
|
+
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
1623
|
+
FOR VALUES IN (TRUE);',
|
|
1624
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || module_record.partitionname || '__' || new_tenant)
|
|
1625
|
+
);
|
|
1626
|
+
|
|
1627
|
+
-- For ${_event_driven_io_dumbo.SQL.plain(streamsTable.name)} table
|
|
1628
|
+
EXECUTE format('
|
|
1629
|
+
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
1630
|
+
FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
|
|
1631
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant), '${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}', module_record.partitionname, new_tenant
|
|
1632
|
+
);
|
|
1633
|
+
|
|
1634
|
+
EXECUTE format('
|
|
1635
|
+
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
1636
|
+
FOR VALUES IN (FALSE);',
|
|
1637
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant)
|
|
1638
|
+
);
|
|
1639
|
+
|
|
1640
|
+
EXECUTE format('
|
|
1641
|
+
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
1642
|
+
FOR VALUES IN (TRUE);',
|
|
1643
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || module_record.partitionname || '__' || new_tenant)
|
|
1644
|
+
);
|
|
1645
|
+
END LOOP;
|
|
1646
|
+
END;
|
|
1647
|
+
$$ LANGUAGE plpgsql;
|
|
1648
|
+
`;
|
|
1649
|
+
const addDefaultPartitionSQL = _event_driven_io_dumbo.SQL`SELECT emt_add_partition('${_event_driven_io_dumbo.SQL.plain(defaultTag)}');`;
|
|
1453
1650
|
|
|
1651
|
+
//#endregion
|
|
1652
|
+
//#region src/eventStore/schema/migrations/0_38_7/0_38_7.migration.ts
|
|
1653
|
+
const dropFutureConceptModuleAndTenantFunctions = _event_driven_io_dumbo.SQL`
|
|
1454
1654
|
DO $$
|
|
1455
1655
|
BEGIN
|
|
1456
1656
|
-- Check and drop functions related to future concept of modules and tenants
|
|
@@ -1470,9 +1670,9 @@ CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $$
|
|
|
1470
1670
|
DROP FUNCTION add_tenant_for_all_modules(TEXT);
|
|
1471
1671
|
END IF;
|
|
1472
1672
|
END $$;
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
DO $$
|
|
1673
|
+
`;
|
|
1674
|
+
const dropOldAppendToSQLWithoutGlobalPositions = _event_driven_io_dumbo.SQL`
|
|
1675
|
+
DO $$
|
|
1476
1676
|
DECLARE
|
|
1477
1677
|
v_current_return_type text;
|
|
1478
1678
|
BEGIN
|
|
@@ -1491,158 +1691,156 @@ CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $$
|
|
|
1491
1691
|
v_current_return_type NOT LIKE '%global_positions%' THEN
|
|
1492
1692
|
DROP FUNCTION emt_append_to_stream(text[], jsonb[], jsonb[], text[], text[], text[], text, text, bigint, text);
|
|
1493
1693
|
RAISE NOTICE 'Old version of function dropped. Return type was: %', v_current_return_type;
|
|
1494
|
-
END IF;
|
|
1495
|
-
END $$;
|
|
1496
|
-
CREATE OR REPLACE FUNCTION emt_append_to_stream(
|
|
1497
|
-
v_message_ids text[],
|
|
1498
|
-
v_messages_data jsonb[],
|
|
1499
|
-
v_messages_metadata jsonb[],
|
|
1500
|
-
v_message_schema_versions text[],
|
|
1501
|
-
v_message_types text[],
|
|
1502
|
-
v_message_kinds text[],
|
|
1503
|
-
v_stream_id text,
|
|
1504
|
-
v_stream_type text,
|
|
1505
|
-
v_expected_stream_position bigint DEFAULT NULL,
|
|
1506
|
-
v_partition text DEFAULT emt_sanitize_name('default_partition')
|
|
1507
|
-
) RETURNS TABLE (
|
|
1508
|
-
success boolean,
|
|
1509
|
-
next_stream_position bigint,
|
|
1510
|
-
global_positions bigint[],
|
|
1511
|
-
transaction_id xid8
|
|
1512
|
-
) LANGUAGE plpgsql
|
|
1513
|
-
AS $$
|
|
1514
|
-
DECLARE
|
|
1515
|
-
v_next_stream_position bigint;
|
|
1516
|
-
v_position bigint;
|
|
1517
|
-
v_updated_rows int;
|
|
1518
|
-
v_transaction_id xid8;
|
|
1519
|
-
v_global_positions bigint[];
|
|
1520
|
-
BEGIN
|
|
1521
|
-
v_transaction_id := pg_current_xact_id();
|
|
1522
|
-
|
|
1523
|
-
IF v_expected_stream_position IS NULL THEN
|
|
1524
|
-
SELECT COALESCE(
|
|
1525
|
-
(SELECT stream_position
|
|
1526
|
-
FROM emt_streams
|
|
1527
|
-
WHERE stream_id = v_stream_id
|
|
1528
|
-
AND partition = v_partition
|
|
1529
|
-
AND is_archived = FALSE
|
|
1530
|
-
LIMIT 1),
|
|
1531
|
-
0
|
|
1532
|
-
) INTO v_expected_stream_position;
|
|
1533
|
-
END IF;
|
|
1534
|
-
|
|
1535
|
-
v_next_stream_position := v_expected_stream_position + array_upper(v_messages_data, 1);
|
|
1536
|
-
|
|
1537
|
-
IF v_expected_stream_position = 0 THEN
|
|
1538
|
-
INSERT INTO emt_streams
|
|
1539
|
-
(stream_id, stream_position, partition, stream_type, stream_metadata, is_archived)
|
|
1540
|
-
VALUES
|
|
1541
|
-
(v_stream_id, v_next_stream_position, v_partition, v_stream_type, '{}', FALSE);
|
|
1542
|
-
ELSE
|
|
1543
|
-
UPDATE emt_streams as s
|
|
1544
|
-
SET stream_position = v_next_stream_position
|
|
1545
|
-
WHERE stream_id = v_stream_id AND stream_position = v_expected_stream_position AND partition = v_partition AND is_archived = FALSE;
|
|
1546
|
-
|
|
1547
|
-
get diagnostics v_updated_rows = row_count;
|
|
1548
1694
|
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1695
|
+
CREATE OR REPLACE FUNCTION emt_append_to_stream(
|
|
1696
|
+
v_message_ids text[],
|
|
1697
|
+
v_messages_data jsonb[],
|
|
1698
|
+
v_messages_metadata jsonb[],
|
|
1699
|
+
v_message_schema_versions text[],
|
|
1700
|
+
v_message_types text[],
|
|
1701
|
+
v_message_kinds text[],
|
|
1702
|
+
v_stream_id text,
|
|
1703
|
+
v_stream_type text,
|
|
1704
|
+
v_expected_stream_position bigint DEFAULT NULL,
|
|
1705
|
+
v_partition text DEFAULT emt_sanitize_name('default_partition')
|
|
1706
|
+
) RETURNS TABLE (
|
|
1707
|
+
success boolean,
|
|
1708
|
+
next_stream_position bigint,
|
|
1709
|
+
global_positions bigint[],
|
|
1710
|
+
transaction_id xid8
|
|
1711
|
+
) LANGUAGE plpgsql
|
|
1712
|
+
AS $emt_append_to_stream$
|
|
1713
|
+
DECLARE
|
|
1714
|
+
v_next_stream_position bigint;
|
|
1715
|
+
v_position bigint;
|
|
1716
|
+
v_updated_rows int;
|
|
1717
|
+
v_transaction_id xid8;
|
|
1718
|
+
v_global_positions bigint[];
|
|
1719
|
+
BEGIN
|
|
1720
|
+
v_transaction_id := pg_current_xact_id();
|
|
1721
|
+
|
|
1722
|
+
IF v_expected_stream_position IS NULL THEN
|
|
1723
|
+
SELECT COALESCE(
|
|
1724
|
+
(SELECT stream_position
|
|
1725
|
+
FROM emt_streams
|
|
1726
|
+
WHERE stream_id = v_stream_id
|
|
1727
|
+
AND partition = v_partition
|
|
1728
|
+
AND is_archived = FALSE
|
|
1729
|
+
LIMIT 1),
|
|
1730
|
+
0
|
|
1731
|
+
) INTO v_expected_stream_position;
|
|
1732
|
+
END IF;
|
|
1733
|
+
|
|
1734
|
+
v_next_stream_position := v_expected_stream_position + array_upper(v_messages_data, 1);
|
|
1735
|
+
|
|
1736
|
+
IF v_expected_stream_position = 0 THEN
|
|
1737
|
+
INSERT INTO emt_streams
|
|
1738
|
+
(stream_id, stream_position, partition, stream_type, stream_metadata, is_archived)
|
|
1739
|
+
VALUES
|
|
1740
|
+
(v_stream_id, v_next_stream_position, v_partition, v_stream_type, '{}', FALSE);
|
|
1741
|
+
ELSE
|
|
1742
|
+
UPDATE emt_streams as s
|
|
1743
|
+
SET stream_position = v_next_stream_position
|
|
1744
|
+
WHERE stream_id = v_stream_id AND stream_position = v_expected_stream_position AND partition = v_partition AND is_archived = FALSE;
|
|
1745
|
+
|
|
1746
|
+
get diagnostics v_updated_rows = row_count;
|
|
1747
|
+
|
|
1748
|
+
IF v_updated_rows = 0 THEN
|
|
1749
|
+
RETURN QUERY SELECT FALSE, NULL::bigint, NULL::bigint[], NULL::xid8;
|
|
1750
|
+
RETURN;
|
|
1751
|
+
END IF;
|
|
1752
|
+
END IF;
|
|
1753
|
+
|
|
1754
|
+
WITH ev AS (
|
|
1755
|
+
SELECT row_number() OVER () + v_expected_stream_position AS stream_position,
|
|
1756
|
+
message_data,
|
|
1757
|
+
message_metadata,
|
|
1758
|
+
schema_version,
|
|
1759
|
+
message_id,
|
|
1760
|
+
message_type,
|
|
1761
|
+
message_kind
|
|
1762
|
+
FROM (
|
|
1763
|
+
SELECT *
|
|
1764
|
+
FROM
|
|
1765
|
+
unnest(v_message_ids, v_messages_data, v_messages_metadata, v_message_schema_versions, v_message_types, v_message_kinds)
|
|
1766
|
+
AS message(message_id, message_data, message_metadata, schema_version, message_type, message_kind)
|
|
1767
|
+
) AS message
|
|
1768
|
+
),
|
|
1769
|
+
all_messages_insert AS (
|
|
1770
|
+
INSERT INTO emt_messages
|
|
1771
|
+
(stream_id, stream_position, partition, message_data, message_metadata, message_schema_version, message_type, message_kind, message_id, transaction_id)
|
|
1772
|
+
SELECT
|
|
1773
|
+
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
|
|
1774
|
+
FROM ev
|
|
1775
|
+
RETURNING global_position
|
|
1776
|
+
)
|
|
1777
|
+
SELECT
|
|
1778
|
+
array_agg(global_position ORDER BY global_position) INTO v_global_positions
|
|
1779
|
+
FROM
|
|
1780
|
+
all_messages_insert;
|
|
1781
|
+
|
|
1782
|
+
RETURN QUERY SELECT TRUE, v_next_stream_position, v_global_positions, v_transaction_id;
|
|
1783
|
+
END;
|
|
1784
|
+
$emt_append_to_stream$;
|
|
1553
1785
|
END IF;
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
message_metadata,
|
|
1559
|
-
schema_version,
|
|
1560
|
-
message_id,
|
|
1561
|
-
message_type,
|
|
1562
|
-
message_kind
|
|
1563
|
-
FROM (
|
|
1564
|
-
SELECT *
|
|
1565
|
-
FROM
|
|
1566
|
-
unnest(v_message_ids, v_messages_data, v_messages_metadata, v_message_schema_versions, v_message_types, v_message_kinds)
|
|
1567
|
-
AS message(message_id, message_data, message_metadata, schema_version, message_type, message_kind)
|
|
1568
|
-
) AS message
|
|
1569
|
-
),
|
|
1570
|
-
all_messages_insert AS (
|
|
1571
|
-
INSERT INTO emt_messages
|
|
1572
|
-
(stream_id, stream_position, partition, message_data, message_metadata, message_schema_version, message_type, message_kind, message_id, transaction_id)
|
|
1573
|
-
SELECT
|
|
1574
|
-
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
|
|
1575
|
-
FROM ev
|
|
1576
|
-
RETURNING global_position
|
|
1577
|
-
)
|
|
1578
|
-
SELECT
|
|
1579
|
-
array_agg(global_position ORDER BY global_position) INTO v_global_positions
|
|
1580
|
-
FROM
|
|
1581
|
-
all_messages_insert;
|
|
1582
|
-
|
|
1583
|
-
RETURN QUERY SELECT TRUE, v_next_stream_position, v_global_positions, v_transaction_id;
|
|
1584
|
-
END;
|
|
1585
|
-
$$;
|
|
1586
|
-
SELECT emt_add_partition('emt:default');
|
|
1587
|
-
CREATE OR REPLACE FUNCTION store_subscription_checkpoint(
|
|
1588
|
-
p_subscription_id VARCHAR(100),
|
|
1589
|
-
p_version BIGINT,
|
|
1590
|
-
p_position BIGINT,
|
|
1591
|
-
p_check_position BIGINT,
|
|
1592
|
-
p_transaction_id xid8,
|
|
1593
|
-
p_partition TEXT DEFAULT 'emt:default'
|
|
1594
|
-
) RETURNS INT AS $$
|
|
1786
|
+
END $$;
|
|
1787
|
+
`;
|
|
1788
|
+
const migrationFromEventsToMessagesSQL = _event_driven_io_dumbo.SQL`
|
|
1789
|
+
DO $$
|
|
1595
1790
|
DECLARE
|
|
1596
|
-
|
|
1791
|
+
partition_record RECORD;
|
|
1597
1792
|
BEGIN
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
-- Retrieve the current position
|
|
1612
|
-
SELECT "last_processed_position" INTO current_position
|
|
1613
|
-
FROM "emt_subscriptions"
|
|
1614
|
-
WHERE "subscription_id" = p_subscription_id AND "partition" = p_partition;
|
|
1793
|
+
-- Rename the main table and its columns if it exists
|
|
1794
|
+
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'emt_events') THEN
|
|
1795
|
+
-- Rename all partitions first
|
|
1796
|
+
FOR partition_record IN
|
|
1797
|
+
SELECT tablename
|
|
1798
|
+
FROM pg_tables
|
|
1799
|
+
WHERE tablename LIKE 'emt_events_%'
|
|
1800
|
+
ORDER BY tablename DESC -- to handle child partitions first
|
|
1801
|
+
LOOP
|
|
1802
|
+
EXECUTE format('ALTER TABLE %I RENAME TO %I',
|
|
1803
|
+
partition_record.tablename,
|
|
1804
|
+
REPLACE(partition_record.tablename, 'events', 'messages'));
|
|
1805
|
+
END LOOP;
|
|
1615
1806
|
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1807
|
+
-- Rename the main table
|
|
1808
|
+
ALTER TABLE emt_events RENAME TO emt_messages;
|
|
1809
|
+
|
|
1810
|
+
-- Rename columns
|
|
1811
|
+
ALTER TABLE emt_messages
|
|
1812
|
+
RENAME COLUMN event_data TO message_data;
|
|
1813
|
+
ALTER TABLE emt_messages
|
|
1814
|
+
RENAME COLUMN event_metadata TO message_metadata;
|
|
1815
|
+
ALTER TABLE emt_messages
|
|
1816
|
+
RENAME COLUMN event_schema_version TO message_schema_version;
|
|
1817
|
+
ALTER TABLE emt_messages
|
|
1818
|
+
RENAME COLUMN event_type TO message_type;
|
|
1819
|
+
ALTER TABLE emt_messages
|
|
1820
|
+
RENAME COLUMN event_id TO message_id;
|
|
1821
|
+
ALTER TABLE emt_messages
|
|
1822
|
+
ADD COLUMN message_kind CHAR(1) NOT NULL DEFAULT 'E';
|
|
1625
1823
|
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1824
|
+
-- Rename sequence if it exists
|
|
1825
|
+
IF EXISTS (SELECT 1 FROM pg_sequences WHERE sequencename = 'emt_global_event_position') THEN
|
|
1826
|
+
ALTER SEQUENCE emt_global_event_position
|
|
1827
|
+
RENAME TO emt_global_message_position;
|
|
1828
|
+
|
|
1829
|
+
ALTER TABLE emt_messages
|
|
1830
|
+
ALTER COLUMN global_position
|
|
1831
|
+
SET DEFAULT nextval('emt_global_message_position');
|
|
1832
|
+
END IF;
|
|
1833
|
+
END IF;
|
|
1834
|
+
END $$;`;
|
|
1835
|
+
const migration_0_38_7_and_older = (0, _event_driven_io_dumbo.sqlMigration)("emt:postgresql:eventstore:0.38.7:migrate-events-to-messages:with_append_to_stream_update", [
|
|
1836
|
+
dropFutureConceptModuleAndTenantFunctions,
|
|
1837
|
+
dropOldAppendToSQLWithoutGlobalPositions,
|
|
1838
|
+
migrationFromEventsToMessagesSQL
|
|
1839
|
+
]);
|
|
1636
1840
|
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
RETURN 2; -- Insertion failed, row already exists with different position
|
|
1641
|
-
END IF;
|
|
1642
|
-
END;
|
|
1643
|
-
END;
|
|
1644
|
-
$$ LANGUAGE plpgsql;
|
|
1645
|
-
`;
|
|
1841
|
+
//#endregion
|
|
1842
|
+
//#region src/eventStore/schema/migrations/0_38_7/index.ts
|
|
1843
|
+
const migrations_0_38_7 = [migration_0_38_7_and_older];
|
|
1646
1844
|
|
|
1647
1845
|
//#endregion
|
|
1648
1846
|
//#region src/eventStore/schema/migrations/0_42_0/0_42_0.migration.ts
|
|
@@ -2177,1064 +2375,216 @@ END;
|
|
|
2177
2375
|
$emt_deactivate_projection$;
|
|
2178
2376
|
`;
|
|
2179
2377
|
const migration_0_42_0_2_AddProcessorProjectionFunctions = (0, _event_driven_io_dumbo.sqlMigration)("emt:postgresql:eventstore:0.42.0-2:add-processor-projection-functions", [migration_0_42_0_2_AddProcessorProjectionFunctionsSQL]);
|
|
2378
|
+
const migration_0_42_0_3_FixProcessorLockTimeoutSQL = _event_driven_io_dumbo.SQL`
|
|
2379
|
+
CREATE OR REPLACE FUNCTION emt_try_acquire_processor_lock(
|
|
2380
|
+
p_lock_key BIGINT,
|
|
2381
|
+
p_processor_id TEXT,
|
|
2382
|
+
p_version INT,
|
|
2383
|
+
p_partition TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
2384
|
+
p_processor_instance_id TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(unknownTag$3)}',
|
|
2385
|
+
p_projection_name TEXT DEFAULT NULL,
|
|
2386
|
+
p_projection_type VARCHAR(1) DEFAULT NULL,
|
|
2387
|
+
p_projection_kind TEXT DEFAULT NULL,
|
|
2388
|
+
p_lock_timeout_seconds INT DEFAULT 300
|
|
2389
|
+
)
|
|
2390
|
+
RETURNS TABLE (acquired BOOLEAN, checkpoint TEXT)
|
|
2391
|
+
LANGUAGE plpgsql
|
|
2392
|
+
AS $emt_try_acquire_processor_lock$
|
|
2393
|
+
DECLARE
|
|
2394
|
+
current_position TEXT;
|
|
2395
|
+
v_current_time TIMESTAMPTZ := clock_timestamp();
|
|
2396
|
+
BEGIN
|
|
2397
|
+
RETURN QUERY
|
|
2398
|
+
WITH lock_check AS (
|
|
2399
|
+
SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired
|
|
2400
|
+
),
|
|
2401
|
+
ownership_check AS (
|
|
2402
|
+
INSERT INTO emt_processors (
|
|
2403
|
+
processor_id,
|
|
2404
|
+
partition,
|
|
2405
|
+
version,
|
|
2406
|
+
processor_instance_id,
|
|
2407
|
+
status,
|
|
2408
|
+
last_processed_checkpoint,
|
|
2409
|
+
last_processed_transaction_id,
|
|
2410
|
+
created_at,
|
|
2411
|
+
last_updated
|
|
2412
|
+
)
|
|
2413
|
+
SELECT p_processor_id, p_partition, p_version, p_processor_instance_id, 'running', '0000000000000000000', '0'::xid8, v_current_time, v_current_time
|
|
2414
|
+
WHERE (SELECT lock_acquired FROM lock_check) = true
|
|
2415
|
+
ON CONFLICT (processor_id, partition, version) DO UPDATE
|
|
2416
|
+
SET processor_instance_id = p_processor_instance_id,
|
|
2417
|
+
status = 'running',
|
|
2418
|
+
last_updated = v_current_time
|
|
2419
|
+
WHERE emt_processors.processor_instance_id = p_processor_instance_id
|
|
2420
|
+
OR emt_processors.processor_instance_id = 'emt:unknown'
|
|
2421
|
+
OR emt_processors.status = 'stopped'
|
|
2422
|
+
OR emt_processors.last_updated < v_current_time - (p_lock_timeout_seconds || ' seconds')::interval
|
|
2423
|
+
RETURNING last_processed_checkpoint
|
|
2424
|
+
),
|
|
2425
|
+
projection_status AS (
|
|
2426
|
+
INSERT INTO emt_projections (
|
|
2427
|
+
name,
|
|
2428
|
+
partition,
|
|
2429
|
+
version,
|
|
2430
|
+
type,
|
|
2431
|
+
kind,
|
|
2432
|
+
status,
|
|
2433
|
+
definition
|
|
2434
|
+
)
|
|
2435
|
+
SELECT p_projection_name, p_partition, p_version, p_projection_type, p_projection_kind, 'async_processing', '{}'::jsonb
|
|
2436
|
+
WHERE p_projection_name IS NOT NULL
|
|
2437
|
+
AND (SELECT last_processed_checkpoint FROM ownership_check) IS NOT NULL
|
|
2438
|
+
ON CONFLICT (name, partition, version) DO UPDATE
|
|
2439
|
+
SET status = 'async_processing'
|
|
2440
|
+
RETURNING name
|
|
2441
|
+
)
|
|
2442
|
+
SELECT
|
|
2443
|
+
(SELECT COUNT(*) > 0 FROM ownership_check),
|
|
2444
|
+
(SELECT oc.last_processed_checkpoint FROM ownership_check oc);
|
|
2445
|
+
END;
|
|
2446
|
+
$emt_try_acquire_processor_lock$;
|
|
2447
|
+
`;
|
|
2448
|
+
const migration_0_42_0_3_FixProcessorLockTimeout = (0, _event_driven_io_dumbo.sqlMigration)("emt:postgresql:eventstore:0.42.0-3:fix-processor-lock-timeout", [migration_0_42_0_3_FixProcessorLockTimeoutSQL]);
|
|
2180
2449
|
|
|
2181
2450
|
//#endregion
|
|
2182
|
-
//#region src/eventStore/schema/migrations/0_42_0/
|
|
2183
|
-
const
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
stream_type TEXT NOT NULL,
|
|
2189
|
-
stream_metadata JSONB NOT NULL,
|
|
2190
|
-
is_archived BOOLEAN NOT NULL DEFAULT FALSE,
|
|
2191
|
-
PRIMARY KEY (stream_id, partition, is_archived)
|
|
2192
|
-
) PARTITION BY LIST (partition);
|
|
2193
|
-
|
|
2194
|
-
CREATE UNIQUE INDEX IF NOT EXISTS idx_streams_unique
|
|
2195
|
-
ON emt_streams(stream_id, partition, is_archived)
|
|
2196
|
-
INCLUDE (stream_position);
|
|
2197
|
-
CREATE SEQUENCE IF NOT EXISTS emt_global_message_position;
|
|
2451
|
+
//#region src/eventStore/schema/migrations/0_42_0/index.ts
|
|
2452
|
+
const migrations_0_42_0 = [
|
|
2453
|
+
migration_0_42_0_FromSubscriptionsToProcessors,
|
|
2454
|
+
migration_0_42_0_2_AddProcessorProjectionFunctions,
|
|
2455
|
+
migration_0_42_0_3_FixProcessorLockTimeout
|
|
2456
|
+
];
|
|
2198
2457
|
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
message_data JSONB NOT NULL,
|
|
2212
|
-
message_metadata JSONB NOT NULL,
|
|
2213
|
-
PRIMARY KEY (stream_id, stream_position, partition, is_archived)
|
|
2214
|
-
) PARTITION BY LIST (partition);
|
|
2215
|
-
CREATE TABLE IF NOT EXISTS emt_projections(
|
|
2216
|
-
version INT NOT NULL DEFAULT 1,
|
|
2217
|
-
type VARCHAR(1) NOT NULL,
|
|
2218
|
-
name TEXT NOT NULL,
|
|
2219
|
-
partition TEXT NOT NULL DEFAULT 'emt:default',
|
|
2220
|
-
kind TEXT NOT NULL,
|
|
2221
|
-
status TEXT NOT NULL,
|
|
2222
|
-
definition JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
2223
|
-
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
2224
|
-
last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
2225
|
-
PRIMARY KEY (name, partition, version)
|
|
2226
|
-
) PARTITION BY LIST (partition);
|
|
2227
|
-
|
|
2228
|
-
CREATE TABLE IF NOT EXISTS emt_processors(
|
|
2229
|
-
last_processed_transaction_id XID8 NOT NULL,
|
|
2230
|
-
version INT NOT NULL DEFAULT 1,
|
|
2231
|
-
processor_id TEXT NOT NULL,
|
|
2232
|
-
partition TEXT NOT NULL DEFAULT 'emt:default',
|
|
2233
|
-
status TEXT NOT NULL DEFAULT 'stopped',
|
|
2234
|
-
last_processed_checkpoint TEXT NOT NULL,
|
|
2235
|
-
processor_instance_id TEXT DEFAULT 'emt:unknown',
|
|
2236
|
-
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
2237
|
-
last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
2238
|
-
PRIMARY KEY (processor_id, partition, version)
|
|
2239
|
-
) PARTITION BY LIST (partition);
|
|
2240
|
-
|
|
2241
|
-
DO $$
|
|
2242
|
-
BEGIN
|
|
2243
|
-
IF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_sanitize_name') THEN
|
|
2244
|
-
CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $emt_sanitize_name$
|
|
2245
|
-
BEGIN
|
|
2246
|
-
RETURN REGEXP_REPLACE(input_name, '[^a-zA-Z0-9_]', '_', 'g');
|
|
2247
|
-
END;
|
|
2248
|
-
$emt_sanitize_name$ LANGUAGE plpgsql;
|
|
2249
|
-
END IF;
|
|
2250
|
-
END $$;
|
|
2251
|
-
|
|
2252
|
-
DO $$
|
|
2253
|
-
BEGIN
|
|
2254
|
-
IF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_add_table_partition') THEN
|
|
2255
|
-
|
|
2256
|
-
CREATE OR REPLACE FUNCTION emt_add_table_partition(tableName TEXT, partition_name TEXT) RETURNS void AS $emt_add_table_partition$
|
|
2257
|
-
DECLARE
|
|
2258
|
-
v_main_partiton_name TEXT;
|
|
2259
|
-
v_active_partiton_name TEXT;
|
|
2260
|
-
v_archived_partiton_name TEXT;
|
|
2261
|
-
BEGIN
|
|
2262
|
-
v_main_partiton_name := emt_sanitize_name(tableName || '_' || partition_name);
|
|
2263
|
-
v_active_partiton_name := emt_sanitize_name(v_main_partiton_name || '_active');
|
|
2264
|
-
v_archived_partiton_name := emt_sanitize_name(v_main_partiton_name || '_archived');
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
-- create default partition
|
|
2268
|
-
EXECUTE format('
|
|
2269
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
2270
|
-
FOR VALUES IN (%L) PARTITION BY LIST (is_archived);',
|
|
2271
|
-
v_main_partiton_name, tableName, partition_name
|
|
2272
|
-
);
|
|
2273
|
-
|
|
2274
|
-
EXECUTE format('
|
|
2275
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
2276
|
-
FOR VALUES IN (FALSE);',
|
|
2277
|
-
v_active_partiton_name, v_main_partiton_name
|
|
2278
|
-
);
|
|
2279
|
-
|
|
2280
|
-
EXECUTE format('
|
|
2281
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
2282
|
-
FOR VALUES IN (TRUE);',
|
|
2283
|
-
v_archived_partiton_name, v_main_partiton_name
|
|
2284
|
-
);
|
|
2285
|
-
END;
|
|
2286
|
-
$emt_add_table_partition$ LANGUAGE plpgsql;
|
|
2287
|
-
END IF;
|
|
2288
|
-
END $$;
|
|
2289
|
-
|
|
2290
|
-
DO $$
|
|
2291
|
-
BEGIN
|
|
2292
|
-
IF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_add_partition') THEN
|
|
2293
|
-
|
|
2294
|
-
CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $emt_add_partition$
|
|
2295
|
-
BEGIN
|
|
2296
|
-
PERFORM emt_add_table_partition('emt_messages', partition_name);
|
|
2297
|
-
PERFORM emt_add_table_partition('emt_streams', partition_name);
|
|
2298
|
-
|
|
2299
|
-
EXECUTE format('
|
|
2300
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
2301
|
-
FOR VALUES IN (%L);',
|
|
2302
|
-
emt_sanitize_name('emt_processors' || '_' || partition_name), 'emt_processors', partition_name
|
|
2303
|
-
);
|
|
2304
|
-
|
|
2305
|
-
EXECUTE format('
|
|
2306
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
2307
|
-
FOR VALUES IN (%L);',
|
|
2308
|
-
emt_sanitize_name('emt_projections' || '_' || partition_name), 'emt_projections', partition_name
|
|
2309
|
-
);
|
|
2310
|
-
END;
|
|
2311
|
-
$emt_add_partition$ LANGUAGE plpgsql;
|
|
2312
|
-
END IF;
|
|
2313
|
-
END $$;
|
|
2314
|
-
|
|
2315
|
-
DO $$
|
|
2316
|
-
BEGIN
|
|
2317
|
-
IF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'emt_append_to_stream') THEN
|
|
2318
|
-
CREATE OR REPLACE FUNCTION emt_append_to_stream(
|
|
2319
|
-
v_message_ids text[],
|
|
2320
|
-
v_messages_data jsonb[],
|
|
2321
|
-
v_messages_metadata jsonb[],
|
|
2322
|
-
v_message_schema_versions text[],
|
|
2323
|
-
v_message_types text[],
|
|
2324
|
-
v_message_kinds text[],
|
|
2325
|
-
v_stream_id text,
|
|
2326
|
-
v_stream_type text,
|
|
2327
|
-
v_expected_stream_position bigint DEFAULT NULL,
|
|
2328
|
-
v_partition text DEFAULT emt_sanitize_name('default_partition')
|
|
2329
|
-
) RETURNS TABLE (
|
|
2330
|
-
success boolean,
|
|
2331
|
-
next_stream_position bigint,
|
|
2332
|
-
global_positions bigint[],
|
|
2333
|
-
transaction_id xid8
|
|
2334
|
-
) LANGUAGE plpgsql
|
|
2335
|
-
AS $emt_append_to_stream$
|
|
2336
|
-
DECLARE
|
|
2337
|
-
v_next_stream_position bigint;
|
|
2338
|
-
v_position bigint;
|
|
2339
|
-
v_updated_rows int;
|
|
2340
|
-
v_transaction_id xid8;
|
|
2341
|
-
v_global_positions bigint[];
|
|
2342
|
-
BEGIN
|
|
2343
|
-
v_transaction_id := pg_current_xact_id();
|
|
2344
|
-
|
|
2345
|
-
IF v_expected_stream_position IS NULL THEN
|
|
2346
|
-
SELECT COALESCE(
|
|
2347
|
-
(SELECT stream_position
|
|
2348
|
-
FROM emt_streams
|
|
2349
|
-
WHERE stream_id = v_stream_id
|
|
2350
|
-
AND partition = v_partition
|
|
2351
|
-
AND is_archived = FALSE
|
|
2352
|
-
LIMIT 1),
|
|
2353
|
-
0
|
|
2354
|
-
) INTO v_expected_stream_position;
|
|
2355
|
-
END IF;
|
|
2356
|
-
|
|
2357
|
-
v_next_stream_position := v_expected_stream_position + array_upper(v_messages_data, 1);
|
|
2358
|
-
|
|
2359
|
-
IF v_expected_stream_position = 0 THEN
|
|
2360
|
-
INSERT INTO emt_streams
|
|
2361
|
-
(stream_id, stream_position, partition, stream_type, stream_metadata, is_archived)
|
|
2362
|
-
VALUES
|
|
2363
|
-
(v_stream_id, v_next_stream_position, v_partition, v_stream_type, '{}', FALSE);
|
|
2364
|
-
ELSE
|
|
2365
|
-
UPDATE emt_streams as s
|
|
2366
|
-
SET stream_position = v_next_stream_position
|
|
2367
|
-
WHERE stream_id = v_stream_id AND stream_position = v_expected_stream_position AND partition = v_partition AND is_archived = FALSE;
|
|
2368
|
-
|
|
2369
|
-
get diagnostics v_updated_rows = row_count;
|
|
2370
|
-
|
|
2371
|
-
IF v_updated_rows = 0 THEN
|
|
2372
|
-
RETURN QUERY SELECT FALSE, NULL::bigint, NULL::bigint[], NULL::xid8;
|
|
2373
|
-
RETURN;
|
|
2374
|
-
END IF;
|
|
2375
|
-
END IF;
|
|
2376
|
-
|
|
2377
|
-
WITH ev AS (
|
|
2378
|
-
SELECT row_number() OVER () + v_expected_stream_position AS stream_position,
|
|
2379
|
-
message_data,
|
|
2380
|
-
message_metadata,
|
|
2381
|
-
schema_version,
|
|
2382
|
-
message_id,
|
|
2383
|
-
message_type,
|
|
2384
|
-
message_kind
|
|
2385
|
-
FROM (
|
|
2386
|
-
SELECT *
|
|
2387
|
-
FROM
|
|
2388
|
-
unnest(v_message_ids, v_messages_data, v_messages_metadata, v_message_schema_versions, v_message_types, v_message_kinds)
|
|
2389
|
-
AS message(message_id, message_data, message_metadata, schema_version, message_type, message_kind)
|
|
2390
|
-
) AS message
|
|
2391
|
-
),
|
|
2392
|
-
all_messages_insert AS (
|
|
2393
|
-
INSERT INTO emt_messages
|
|
2394
|
-
(stream_id, stream_position, partition, message_data, message_metadata, message_schema_version, message_type, message_kind, message_id, transaction_id)
|
|
2395
|
-
SELECT
|
|
2396
|
-
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
|
|
2397
|
-
FROM ev
|
|
2398
|
-
RETURNING global_position
|
|
2399
|
-
)
|
|
2400
|
-
SELECT
|
|
2401
|
-
array_agg(global_position ORDER BY global_position) INTO v_global_positions
|
|
2402
|
-
FROM
|
|
2403
|
-
all_messages_insert;
|
|
2404
|
-
|
|
2405
|
-
RETURN QUERY SELECT TRUE, v_next_stream_position, v_global_positions, v_transaction_id;
|
|
2406
|
-
END;
|
|
2407
|
-
$emt_append_to_stream$;
|
|
2408
|
-
|
|
2409
|
-
END IF;
|
|
2410
|
-
END $$;
|
|
2411
|
-
SELECT emt_add_partition('emt:default');
|
|
2412
|
-
DO $$
|
|
2413
|
-
BEGIN
|
|
2414
|
-
IF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'store_processor_checkpoint') THEN
|
|
2415
|
-
|
|
2416
|
-
CREATE OR REPLACE FUNCTION store_processor_checkpoint(
|
|
2417
|
-
p_processor_id TEXT,
|
|
2418
|
-
p_version BIGINT,
|
|
2419
|
-
p_position TEXT,
|
|
2420
|
-
p_check_position TEXT,
|
|
2421
|
-
p_transaction_id xid8,
|
|
2422
|
-
p_partition TEXT DEFAULT 'emt:default',
|
|
2423
|
-
p_processor_instance_id TEXT DEFAULT 'emt:unknown'
|
|
2424
|
-
) RETURNS INT AS $spc$
|
|
2425
|
-
DECLARE
|
|
2426
|
-
current_position TEXT;
|
|
2427
|
-
BEGIN
|
|
2428
|
-
-- Handle the case when p_check_position is provided
|
|
2429
|
-
IF p_check_position IS NOT NULL THEN
|
|
2430
|
-
-- Try to update if the position matches p_check_position
|
|
2431
|
-
UPDATE "emt_processors"
|
|
2432
|
-
SET
|
|
2433
|
-
"last_processed_checkpoint" = p_position,
|
|
2434
|
-
"last_processed_transaction_id" = p_transaction_id,
|
|
2435
|
-
"last_updated" = now()
|
|
2436
|
-
WHERE "processor_id" = p_processor_id
|
|
2437
|
-
AND "last_processed_checkpoint" = p_check_position
|
|
2438
|
-
AND "partition" = p_partition
|
|
2439
|
-
AND "version" = p_version;
|
|
2440
|
-
|
|
2441
|
-
IF FOUND THEN
|
|
2442
|
-
RETURN 1; -- Successfully updated
|
|
2443
|
-
END IF;
|
|
2444
|
-
|
|
2445
|
-
-- Retrieve the current position
|
|
2446
|
-
SELECT "last_processed_checkpoint" INTO current_position
|
|
2447
|
-
FROM "emt_processors"
|
|
2448
|
-
WHERE "processor_id" = p_processor_id
|
|
2449
|
-
AND "partition" = p_partition
|
|
2450
|
-
AND "version" = p_version;
|
|
2451
|
-
|
|
2452
|
-
-- Return appropriate codes based on current position
|
|
2453
|
-
IF current_position = p_position THEN
|
|
2454
|
-
RETURN 0; -- Idempotent check: position already set
|
|
2455
|
-
ELSIF current_position > p_position THEN
|
|
2456
|
-
RETURN 3; -- Current ahead: another process has progressed further
|
|
2457
|
-
ELSE
|
|
2458
|
-
RETURN 2; -- Mismatch: check position doesn't match current
|
|
2459
|
-
END IF;
|
|
2460
|
-
END IF;
|
|
2461
|
-
|
|
2462
|
-
-- Handle the case when p_check_position is NULL: Insert if not exists
|
|
2463
|
-
BEGIN
|
|
2464
|
-
INSERT INTO "emt_processors"("processor_id", "version", "last_processed_checkpoint", "partition", "last_processed_transaction_id", "created_at", "last_updated")
|
|
2465
|
-
VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());
|
|
2466
|
-
RETURN 1; -- Successfully inserted
|
|
2467
|
-
EXCEPTION WHEN unique_violation THEN
|
|
2468
|
-
-- If insertion failed, it means the row already exists
|
|
2469
|
-
SELECT "last_processed_checkpoint" INTO current_position
|
|
2470
|
-
FROM "emt_processors"
|
|
2471
|
-
WHERE "processor_id" = p_processor_id
|
|
2472
|
-
AND "partition" = p_partition
|
|
2473
|
-
AND "version" = p_version;
|
|
2474
|
-
|
|
2475
|
-
IF current_position = p_position THEN
|
|
2476
|
-
RETURN 0; -- Idempotent check: position already set
|
|
2477
|
-
ELSIF current_position > p_position THEN
|
|
2478
|
-
RETURN 3; -- Current ahead: another process has progressed further
|
|
2479
|
-
ELSE
|
|
2480
|
-
RETURN 2; -- Insertion failed, row already exists with different position
|
|
2481
|
-
END IF;
|
|
2482
|
-
END;
|
|
2483
|
-
END;
|
|
2484
|
-
$spc$ LANGUAGE plpgsql;
|
|
2485
|
-
|
|
2486
|
-
END IF;
|
|
2487
|
-
END $$;
|
|
2488
|
-
|
|
2489
|
-
CREATE OR REPLACE FUNCTION emt_try_acquire_processor_lock(
|
|
2490
|
-
p_lock_key BIGINT,
|
|
2491
|
-
p_processor_id TEXT,
|
|
2492
|
-
p_version INT,
|
|
2493
|
-
p_partition TEXT DEFAULT 'emt:default',
|
|
2494
|
-
p_processor_instance_id TEXT DEFAULT 'emt:unknown',
|
|
2495
|
-
p_projection_name TEXT DEFAULT NULL,
|
|
2496
|
-
p_projection_type VARCHAR(1) DEFAULT NULL,
|
|
2497
|
-
p_projection_kind TEXT DEFAULT NULL,
|
|
2498
|
-
p_lock_timeout_seconds INT DEFAULT 300
|
|
2499
|
-
)
|
|
2500
|
-
RETURNS TABLE (acquired BOOLEAN, checkpoint TEXT)
|
|
2501
|
-
LANGUAGE plpgsql
|
|
2502
|
-
AS $emt_try_acquire_processor_lock$
|
|
2503
|
-
BEGIN
|
|
2504
|
-
RETURN QUERY
|
|
2505
|
-
WITH lock_check AS (
|
|
2506
|
-
SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired
|
|
2507
|
-
),
|
|
2508
|
-
ownership_check AS (
|
|
2509
|
-
INSERT INTO emt_processors (
|
|
2510
|
-
processor_id,
|
|
2511
|
-
partition,
|
|
2512
|
-
version,
|
|
2513
|
-
processor_instance_id,
|
|
2514
|
-
status,
|
|
2515
|
-
last_processed_checkpoint,
|
|
2516
|
-
last_processed_transaction_id,
|
|
2517
|
-
created_at,
|
|
2518
|
-
last_updated
|
|
2519
|
-
)
|
|
2520
|
-
SELECT p_processor_id, p_partition, p_version, p_processor_instance_id, 'running', '0000000000000000000', '0'::xid8, now(), now()
|
|
2521
|
-
WHERE (SELECT lock_acquired FROM lock_check) = true
|
|
2522
|
-
ON CONFLICT (processor_id, partition, version) DO UPDATE
|
|
2523
|
-
SET processor_instance_id = p_processor_instance_id,
|
|
2524
|
-
status = 'running',
|
|
2525
|
-
last_updated = now()
|
|
2526
|
-
WHERE emt_processors.processor_instance_id = p_processor_instance_id
|
|
2527
|
-
OR emt_processors.processor_instance_id = 'emt:unknown'
|
|
2528
|
-
OR emt_processors.status = 'stopped'
|
|
2529
|
-
OR emt_processors.last_updated < now() - (p_lock_timeout_seconds || ' seconds')::interval
|
|
2530
|
-
RETURNING last_processed_checkpoint
|
|
2531
|
-
),
|
|
2532
|
-
projection_status AS (
|
|
2533
|
-
INSERT INTO emt_projections (
|
|
2534
|
-
name,
|
|
2535
|
-
partition,
|
|
2536
|
-
version,
|
|
2537
|
-
type,
|
|
2538
|
-
kind,
|
|
2539
|
-
status,
|
|
2540
|
-
definition
|
|
2541
|
-
)
|
|
2542
|
-
SELECT p_projection_name, p_partition, p_version, p_projection_type, p_projection_kind, 'async_processing', '{}'::jsonb
|
|
2543
|
-
WHERE p_projection_name IS NOT NULL
|
|
2544
|
-
AND (SELECT last_processed_checkpoint FROM ownership_check) IS NOT NULL
|
|
2545
|
-
ON CONFLICT (name, partition, version) DO UPDATE
|
|
2546
|
-
SET status = 'async_processing'
|
|
2547
|
-
RETURNING name
|
|
2548
|
-
)
|
|
2549
|
-
SELECT
|
|
2550
|
-
(SELECT COUNT(*) > 0 FROM ownership_check),
|
|
2551
|
-
(SELECT oc.last_processed_checkpoint FROM ownership_check oc);
|
|
2552
|
-
END;
|
|
2553
|
-
$emt_try_acquire_processor_lock$;
|
|
2554
|
-
|
|
2555
|
-
CREATE OR REPLACE FUNCTION emt_release_processor_lock(
|
|
2556
|
-
p_lock_key BIGINT,
|
|
2557
|
-
p_processor_id TEXT,
|
|
2558
|
-
p_partition TEXT,
|
|
2559
|
-
p_version INT,
|
|
2560
|
-
p_processor_instance_id TEXT DEFAULT 'emt:unknown',
|
|
2561
|
-
p_projection_name TEXT DEFAULT NULL
|
|
2562
|
-
)
|
|
2563
|
-
RETURNS BOOLEAN
|
|
2564
|
-
LANGUAGE plpgsql
|
|
2565
|
-
AS $emt_release_processor_lock$
|
|
2566
|
-
DECLARE
|
|
2567
|
-
v_rows_updated INT;
|
|
2568
|
-
BEGIN
|
|
2569
|
-
IF p_projection_name IS NOT NULL THEN
|
|
2570
|
-
UPDATE emt_projections
|
|
2571
|
-
SET status = 'active',
|
|
2572
|
-
last_updated = now()
|
|
2573
|
-
WHERE partition = p_partition
|
|
2574
|
-
AND name = p_projection_name
|
|
2575
|
-
AND version = p_version;
|
|
2576
|
-
END IF;
|
|
2577
|
-
|
|
2578
|
-
UPDATE emt_processors
|
|
2579
|
-
SET status = 'stopped',
|
|
2580
|
-
processor_instance_id = 'emt:unknown',
|
|
2581
|
-
last_updated = now()
|
|
2582
|
-
WHERE processor_id = p_processor_id
|
|
2583
|
-
AND partition = p_partition
|
|
2584
|
-
AND version = p_version
|
|
2585
|
-
AND processor_instance_id = p_processor_instance_id;
|
|
2586
|
-
|
|
2587
|
-
GET DIAGNOSTICS v_rows_updated = ROW_COUNT;
|
|
2588
|
-
|
|
2589
|
-
PERFORM pg_advisory_unlock(p_lock_key);
|
|
2590
|
-
|
|
2591
|
-
RETURN v_rows_updated > 0;
|
|
2592
|
-
END;
|
|
2593
|
-
$emt_release_processor_lock$;
|
|
2594
|
-
|
|
2595
|
-
CREATE OR REPLACE FUNCTION emt_try_acquire_projection_lock(
|
|
2596
|
-
p_lock_key BIGINT,
|
|
2597
|
-
p_partition TEXT,
|
|
2598
|
-
p_name TEXT,
|
|
2599
|
-
p_version INT
|
|
2600
|
-
)
|
|
2601
|
-
RETURNS TABLE (acquired BOOLEAN, is_active BOOLEAN)
|
|
2602
|
-
LANGUAGE plpgsql
|
|
2603
|
-
AS $emt_try_acquire_projection_lock$
|
|
2604
|
-
BEGIN
|
|
2605
|
-
RETURN QUERY
|
|
2606
|
-
WITH lock_check AS (
|
|
2607
|
-
SELECT pg_try_advisory_xact_lock_shared(p_lock_key) AS acquired
|
|
2608
|
-
),
|
|
2609
|
-
status_check AS (
|
|
2610
|
-
SELECT status = 'active' AS is_active
|
|
2611
|
-
FROM emt_projections
|
|
2612
|
-
WHERE partition = p_partition AND name = p_name AND version = p_version
|
|
2613
|
-
)
|
|
2614
|
-
SELECT
|
|
2615
|
-
COALESCE((SELECT lc.acquired FROM lock_check lc), false),
|
|
2616
|
-
COALESCE((SELECT sc.is_active FROM status_check sc), true);
|
|
2617
|
-
END;
|
|
2618
|
-
$emt_try_acquire_projection_lock$;
|
|
2619
|
-
|
|
2620
|
-
CREATE OR REPLACE FUNCTION emt_register_projection(
|
|
2621
|
-
p_lock_key BIGINT,
|
|
2622
|
-
p_name TEXT,
|
|
2623
|
-
p_partition TEXT,
|
|
2624
|
-
p_version INT,
|
|
2625
|
-
p_type VARCHAR(1),
|
|
2626
|
-
p_kind TEXT,
|
|
2627
|
-
p_status TEXT,
|
|
2628
|
-
p_definition JSONB
|
|
2629
|
-
)
|
|
2630
|
-
RETURNS BOOLEAN
|
|
2631
|
-
LANGUAGE plpgsql
|
|
2632
|
-
AS $emt_register_projection$
|
|
2633
|
-
DECLARE
|
|
2634
|
-
v_result BOOLEAN;
|
|
2635
|
-
BEGIN
|
|
2636
|
-
WITH lock_check AS (
|
|
2637
|
-
SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired
|
|
2638
|
-
),
|
|
2639
|
-
upsert_result AS (
|
|
2640
|
-
INSERT INTO emt_projections (
|
|
2641
|
-
name, partition, version, type, kind, status, definition, created_at, last_updated
|
|
2642
|
-
)
|
|
2643
|
-
SELECT p_name, p_partition, p_version, p_type, p_kind, p_status, p_definition, now(), now()
|
|
2644
|
-
WHERE (SELECT lock_acquired FROM lock_check) = true
|
|
2645
|
-
ON CONFLICT (name, partition, version) DO UPDATE
|
|
2646
|
-
SET definition = EXCLUDED.definition,
|
|
2647
|
-
last_updated = now()
|
|
2648
|
-
RETURNING name
|
|
2649
|
-
)
|
|
2650
|
-
SELECT COUNT(*) > 0 INTO v_result FROM upsert_result;
|
|
2651
|
-
|
|
2652
|
-
RETURN v_result;
|
|
2653
|
-
END;
|
|
2654
|
-
$emt_register_projection$;
|
|
2655
|
-
|
|
2656
|
-
CREATE OR REPLACE FUNCTION emt_activate_projection(
|
|
2657
|
-
p_lock_key BIGINT,
|
|
2658
|
-
p_name TEXT,
|
|
2659
|
-
p_partition TEXT,
|
|
2660
|
-
p_version INT
|
|
2661
|
-
)
|
|
2662
|
-
RETURNS BOOLEAN
|
|
2663
|
-
LANGUAGE plpgsql
|
|
2664
|
-
AS $emt_activate_projection$
|
|
2665
|
-
DECLARE
|
|
2666
|
-
v_result BOOLEAN;
|
|
2667
|
-
BEGIN
|
|
2668
|
-
WITH lock_check AS (
|
|
2669
|
-
SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired
|
|
2670
|
-
),
|
|
2671
|
-
update_result AS (
|
|
2672
|
-
UPDATE emt_projections
|
|
2673
|
-
SET status = 'active',
|
|
2674
|
-
last_updated = now()
|
|
2675
|
-
WHERE name = p_name
|
|
2676
|
-
AND partition = p_partition
|
|
2677
|
-
AND version = p_version
|
|
2678
|
-
AND (SELECT lock_acquired FROM lock_check) = true
|
|
2679
|
-
RETURNING name
|
|
2680
|
-
)
|
|
2681
|
-
SELECT COUNT(*) > 0 INTO v_result FROM update_result;
|
|
2682
|
-
|
|
2683
|
-
RETURN v_result;
|
|
2684
|
-
END;
|
|
2685
|
-
$emt_activate_projection$;
|
|
2686
|
-
|
|
2687
|
-
CREATE OR REPLACE FUNCTION emt_deactivate_projection(
|
|
2688
|
-
p_lock_key BIGINT,
|
|
2689
|
-
p_name TEXT,
|
|
2690
|
-
p_partition TEXT,
|
|
2691
|
-
p_version INT
|
|
2692
|
-
)
|
|
2693
|
-
RETURNS BOOLEAN
|
|
2694
|
-
LANGUAGE plpgsql
|
|
2695
|
-
AS $emt_deactivate_projection$
|
|
2696
|
-
DECLARE
|
|
2697
|
-
v_result BOOLEAN;
|
|
2698
|
-
BEGIN
|
|
2699
|
-
WITH lock_check AS (
|
|
2700
|
-
SELECT pg_try_advisory_xact_lock(p_lock_key) AS lock_acquired
|
|
2701
|
-
),
|
|
2702
|
-
update_result AS (
|
|
2703
|
-
UPDATE emt_projections
|
|
2704
|
-
SET status = 'inactive',
|
|
2705
|
-
last_updated = now()
|
|
2706
|
-
WHERE name = p_name
|
|
2707
|
-
AND partition = p_partition
|
|
2708
|
-
AND version = p_version
|
|
2709
|
-
AND (SELECT lock_acquired FROM lock_check) = true
|
|
2710
|
-
RETURNING name
|
|
2711
|
-
)
|
|
2712
|
-
SELECT COUNT(*) > 0 INTO v_result FROM update_result;
|
|
2713
|
-
|
|
2714
|
-
RETURN v_result;
|
|
2715
|
-
END;
|
|
2716
|
-
$emt_deactivate_projection$;
|
|
2717
|
-
`;
|
|
2718
|
-
|
|
2719
|
-
//#endregion
|
|
2720
|
-
//#region src/eventStore/schema/storeProcessorCheckpoint.ts
|
|
2721
|
-
const storeSubscriptionCheckpointSQL = createFunctionIfDoesNotExistSQL("store_processor_checkpoint", _event_driven_io_dumbo.SQL`
|
|
2722
|
-
CREATE OR REPLACE FUNCTION store_processor_checkpoint(
|
|
2723
|
-
p_processor_id TEXT,
|
|
2724
|
-
p_version BIGINT,
|
|
2725
|
-
p_position TEXT,
|
|
2726
|
-
p_check_position TEXT,
|
|
2727
|
-
p_transaction_id xid8,
|
|
2728
|
-
p_partition TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
2729
|
-
p_processor_instance_id TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(unknownTag)}'
|
|
2730
|
-
) RETURNS INT AS $spc$
|
|
2731
|
-
DECLARE
|
|
2732
|
-
current_position TEXT;
|
|
2733
|
-
BEGIN
|
|
2734
|
-
-- Handle the case when p_check_position is provided
|
|
2735
|
-
IF p_check_position IS NOT NULL THEN
|
|
2736
|
-
-- Try to update if the position matches p_check_position
|
|
2737
|
-
UPDATE "${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}"
|
|
2738
|
-
SET
|
|
2739
|
-
"last_processed_checkpoint" = p_position,
|
|
2740
|
-
"last_processed_transaction_id" = p_transaction_id,
|
|
2741
|
-
"last_updated" = now()
|
|
2742
|
-
WHERE "processor_id" = p_processor_id
|
|
2743
|
-
AND "last_processed_checkpoint" = p_check_position
|
|
2744
|
-
AND "partition" = p_partition
|
|
2745
|
-
AND "version" = p_version;
|
|
2746
|
-
|
|
2747
|
-
IF FOUND THEN
|
|
2748
|
-
RETURN 1; -- Successfully updated
|
|
2749
|
-
END IF;
|
|
2750
|
-
|
|
2751
|
-
-- Retrieve the current position
|
|
2752
|
-
SELECT "last_processed_checkpoint" INTO current_position
|
|
2753
|
-
FROM "${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}"
|
|
2754
|
-
WHERE "processor_id" = p_processor_id
|
|
2755
|
-
AND "partition" = p_partition
|
|
2756
|
-
AND "version" = p_version;
|
|
2757
|
-
|
|
2758
|
-
-- Return appropriate codes based on current position
|
|
2759
|
-
IF current_position = p_position THEN
|
|
2760
|
-
RETURN 0; -- Idempotent check: position already set
|
|
2761
|
-
ELSIF current_position > p_position THEN
|
|
2762
|
-
RETURN 3; -- Current ahead: another process has progressed further
|
|
2763
|
-
ELSE
|
|
2764
|
-
RETURN 2; -- Mismatch: check position doesn't match current
|
|
2765
|
-
END IF;
|
|
2766
|
-
END IF;
|
|
2767
|
-
|
|
2768
|
-
-- Handle the case when p_check_position is NULL: Insert if not exists
|
|
2769
|
-
BEGIN
|
|
2770
|
-
INSERT INTO "${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}"("processor_id", "version", "last_processed_checkpoint", "partition", "last_processed_transaction_id", "created_at", "last_updated")
|
|
2771
|
-
VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());
|
|
2772
|
-
RETURN 1; -- Successfully inserted
|
|
2773
|
-
EXCEPTION WHEN unique_violation THEN
|
|
2774
|
-
-- If insertion failed, it means the row already exists
|
|
2775
|
-
SELECT "last_processed_checkpoint" INTO current_position
|
|
2776
|
-
FROM "${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}"
|
|
2777
|
-
WHERE "processor_id" = p_processor_id
|
|
2778
|
-
AND "partition" = p_partition
|
|
2779
|
-
AND "version" = p_version;
|
|
2780
|
-
|
|
2781
|
-
IF current_position = p_position THEN
|
|
2782
|
-
RETURN 0; -- Idempotent check: position already set
|
|
2783
|
-
ELSIF current_position > p_position THEN
|
|
2784
|
-
RETURN 3; -- Current ahead: another process has progressed further
|
|
2785
|
-
ELSE
|
|
2786
|
-
RETURN 2; -- Insertion failed, row already exists with different position
|
|
2787
|
-
END IF;
|
|
2788
|
-
END;
|
|
2789
|
-
END;
|
|
2790
|
-
$spc$ LANGUAGE plpgsql;
|
|
2791
|
-
`);
|
|
2792
|
-
const callStoreProcessorCheckpoint = (params) => _event_driven_io_dumbo.SQL`
|
|
2793
|
-
SELECT store_processor_checkpoint(
|
|
2794
|
-
${params.processorId},
|
|
2795
|
-
${params.version},
|
|
2796
|
-
${params.position},
|
|
2797
|
-
${params.checkPosition},
|
|
2798
|
-
pg_current_xact_id(),
|
|
2799
|
-
${params.partition},
|
|
2800
|
-
${params.processorInstanceId}
|
|
2801
|
-
) as result;`;
|
|
2802
|
-
const storeProcessorCheckpoint = async (execute, options) => {
|
|
2803
|
-
try {
|
|
2804
|
-
const { result } = await (0, _event_driven_io_dumbo.single)(execute.command(callStoreProcessorCheckpoint({
|
|
2805
|
-
processorId: options.processorId,
|
|
2806
|
-
version: options.version ?? 1,
|
|
2807
|
-
position: options.newCheckpoint !== null ? options.newCheckpoint : null,
|
|
2808
|
-
checkPosition: options.lastProcessedCheckpoint !== null ? options.lastProcessedCheckpoint : null,
|
|
2809
|
-
partition: options.partition ?? defaultTag,
|
|
2810
|
-
processorInstanceId: options.processorInstanceId ?? unknownTag
|
|
2811
|
-
})));
|
|
2812
|
-
return result === 1 ? {
|
|
2813
|
-
success: true,
|
|
2814
|
-
newCheckpoint: options.newCheckpoint
|
|
2815
|
-
} : {
|
|
2816
|
-
success: false,
|
|
2817
|
-
reason: result === 0 ? "IGNORED" : result === 3 ? "CURRENT_AHEAD" : "MISMATCH"
|
|
2818
|
-
};
|
|
2819
|
-
} catch (error) {
|
|
2820
|
-
console.log(error);
|
|
2821
|
-
throw error;
|
|
2822
|
-
}
|
|
2823
|
-
};
|
|
2824
|
-
|
|
2825
|
-
//#endregion
|
|
2826
|
-
//#region src/eventStore/schema/migrations/0_43_0/index.ts
|
|
2827
|
-
const migration_0_43_0_cleanupLegacySubscriptionSQL = _event_driven_io_dumbo.SQL`
|
|
2828
|
-
DO $$
|
|
2829
|
-
BEGIN
|
|
2830
|
-
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'emt_subscriptions') THEN
|
|
2831
|
-
-- Restore clean emt_add_partition (remove creation of emt_subscriptions partitions)
|
|
2832
|
-
CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $fnpar$
|
|
2833
|
-
BEGIN
|
|
2834
|
-
PERFORM emt_add_table_partition('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}', partition_name);
|
|
2835
|
-
PERFORM emt_add_table_partition('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}', partition_name);
|
|
2836
|
-
|
|
2837
|
-
EXECUTE format('
|
|
2838
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
2839
|
-
FOR VALUES IN (%L);',
|
|
2840
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}' || '_' || partition_name), '${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}', partition_name
|
|
2841
|
-
);
|
|
2842
|
-
|
|
2843
|
-
EXECUTE format('
|
|
2844
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
2845
|
-
FOR VALUES IN (%L);',
|
|
2846
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(projectionsTable.name)}' || '_' || partition_name), '${_event_driven_io_dumbo.SQL.plain(projectionsTable.name)}', partition_name
|
|
2847
|
-
);
|
|
2848
|
-
END;
|
|
2849
|
-
$fnpar$ LANGUAGE plpgsql;
|
|
2850
|
-
|
|
2851
|
-
-- Drop old subscriptions table if it exists
|
|
2852
|
-
DROP TABLE IF EXISTS emt_subscriptions CASCADE;
|
|
2853
|
-
|
|
2854
|
-
-- Drop old function if it exists
|
|
2855
|
-
DROP FUNCTION IF EXISTS store_subscription_checkpoint(character varying, bigint, bigint, bigint, xid8, text);
|
|
2856
|
-
|
|
2857
|
-
-- Restore clean store_processor_checkpoint (remove dual-write logic)
|
|
2858
|
-
CREATE OR REPLACE FUNCTION store_processor_checkpoint(
|
|
2859
|
-
p_processor_id TEXT,
|
|
2860
|
-
p_version BIGINT,
|
|
2861
|
-
p_position TEXT,
|
|
2862
|
-
p_check_position TEXT,
|
|
2863
|
-
p_transaction_id xid8,
|
|
2864
|
-
p_partition TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
2865
|
-
p_processor_instance_id TEXT DEFAULT 'emt:unknown'
|
|
2866
|
-
) RETURNS INT AS $fn$
|
|
2867
|
-
DECLARE
|
|
2868
|
-
current_position TEXT;
|
|
2869
|
-
BEGIN
|
|
2870
|
-
IF p_check_position IS NOT NULL THEN
|
|
2871
|
-
UPDATE "emt_processors"
|
|
2872
|
-
SET
|
|
2873
|
-
"last_processed_checkpoint" = p_position,
|
|
2874
|
-
"last_processed_transaction_id" = p_transaction_id,
|
|
2875
|
-
"last_updated" = now()
|
|
2876
|
-
WHERE "processor_id" = p_processor_id
|
|
2877
|
-
AND "last_processed_checkpoint" = p_check_position
|
|
2878
|
-
AND "partition" = p_partition
|
|
2879
|
-
AND "version" = p_version;
|
|
2880
|
-
|
|
2881
|
-
IF FOUND THEN
|
|
2882
|
-
RETURN 1;
|
|
2883
|
-
END IF;
|
|
2884
|
-
|
|
2885
|
-
SELECT "last_processed_checkpoint" INTO current_position
|
|
2886
|
-
FROM "emt_processors"
|
|
2887
|
-
WHERE "processor_id" = p_processor_id
|
|
2888
|
-
AND "partition" = p_partition
|
|
2889
|
-
AND "version" = p_version ;
|
|
2890
|
-
|
|
2891
|
-
IF current_position = p_position THEN
|
|
2892
|
-
RETURN 0;
|
|
2893
|
-
ELSIF current_position > p_position THEN
|
|
2894
|
-
RETURN 3;
|
|
2895
|
-
ELSE
|
|
2896
|
-
RETURN 2;
|
|
2897
|
-
END IF;
|
|
2898
|
-
END IF;
|
|
2899
|
-
|
|
2900
|
-
BEGIN
|
|
2901
|
-
INSERT INTO "emt_processors"("processor_id", "version", "last_processed_checkpoint", "partition", "last_processed_transaction_id", "created_at", "last_updated")
|
|
2902
|
-
VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());
|
|
2903
|
-
RETURN 1;
|
|
2904
|
-
EXCEPTION WHEN unique_violation THEN
|
|
2905
|
-
SELECT "last_processed_checkpoint" INTO current_position
|
|
2906
|
-
FROM "emt_processors"
|
|
2907
|
-
WHERE "processor_id" = p_processor_id
|
|
2908
|
-
AND "partition" = p_partition
|
|
2909
|
-
AND "version" = p_version;
|
|
2910
|
-
|
|
2911
|
-
IF current_position = p_position THEN
|
|
2912
|
-
RETURN 0;
|
|
2913
|
-
ELSE
|
|
2914
|
-
RETURN 2;
|
|
2915
|
-
END IF;
|
|
2916
|
-
END;
|
|
2917
|
-
END;
|
|
2918
|
-
$fn$ LANGUAGE plpgsql;
|
|
2919
|
-
END IF;
|
|
2920
|
-
END $$;
|
|
2921
|
-
`;
|
|
2922
|
-
const migration_0_43_0_cleanupLegacySubscription = (0, _event_driven_io_dumbo.sqlMigration)("emt:postgresql:eventstore:0.43.0:cleanup-legacy-subscription", [migration_0_43_0_cleanupLegacySubscriptionSQL]);
|
|
2923
|
-
const cleanupLegacySubscriptionTables = async (connectionString) => {
|
|
2924
|
-
const pool = (0, _event_driven_io_dumbo.dumbo)({ connectionString });
|
|
2925
|
-
try {
|
|
2926
|
-
await pool.withTransaction(async ({ execute }) => {
|
|
2927
|
-
await execute.command(migration_0_43_0_cleanupLegacySubscriptionSQL);
|
|
2928
|
-
});
|
|
2929
|
-
} finally {
|
|
2930
|
-
await pool.close();
|
|
2931
|
-
}
|
|
2932
|
-
};
|
|
2933
|
-
|
|
2934
|
-
//#endregion
|
|
2935
|
-
//#region src/eventStore/schema/tables.ts
|
|
2936
|
-
const streamsTableSQL = _event_driven_io_dumbo.SQL`
|
|
2937
|
-
CREATE TABLE IF NOT EXISTS ${_event_driven_io_dumbo.SQL.identifier(streamsTable.name)}(
|
|
2938
|
-
stream_id TEXT NOT NULL,
|
|
2939
|
-
stream_position BIGINT NOT NULL,
|
|
2940
|
-
partition TEXT NOT NULL DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
2941
|
-
stream_type TEXT NOT NULL,
|
|
2942
|
-
stream_metadata JSONB NOT NULL,
|
|
2943
|
-
is_archived BOOLEAN NOT NULL DEFAULT FALSE,
|
|
2944
|
-
PRIMARY KEY (stream_id, partition, is_archived)
|
|
2945
|
-
) PARTITION BY LIST (partition);
|
|
2946
|
-
|
|
2947
|
-
CREATE UNIQUE INDEX IF NOT EXISTS idx_streams_unique
|
|
2948
|
-
ON ${_event_driven_io_dumbo.SQL.identifier(streamsTable.name)}(stream_id, partition, is_archived)
|
|
2949
|
-
INCLUDE (stream_position);`;
|
|
2950
|
-
const messagesTableSQL = _event_driven_io_dumbo.SQL`
|
|
2951
|
-
CREATE SEQUENCE IF NOT EXISTS emt_global_message_position;
|
|
2952
|
-
|
|
2953
|
-
CREATE TABLE IF NOT EXISTS ${_event_driven_io_dumbo.SQL.identifier(messagesTable.name)}(
|
|
2954
|
-
stream_position BIGINT NOT NULL,
|
|
2955
|
-
global_position BIGINT DEFAULT nextval('emt_global_message_position'),
|
|
2956
|
-
transaction_id XID8 NOT NULL,
|
|
2957
|
-
created TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
2958
|
-
is_archived BOOLEAN NOT NULL DEFAULT FALSE,
|
|
2959
|
-
message_kind VARCHAR(1) NOT NULL DEFAULT 'E',
|
|
2960
|
-
stream_id TEXT NOT NULL,
|
|
2961
|
-
partition TEXT NOT NULL DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
2962
|
-
message_schema_version TEXT NOT NULL,
|
|
2963
|
-
message_id TEXT NOT NULL,
|
|
2964
|
-
message_type TEXT NOT NULL,
|
|
2965
|
-
message_data JSONB NOT NULL,
|
|
2966
|
-
message_metadata JSONB NOT NULL,
|
|
2967
|
-
PRIMARY KEY (stream_id, stream_position, partition, is_archived)
|
|
2968
|
-
) PARTITION BY LIST (partition);`;
|
|
2969
|
-
const processorsTableSQL = _event_driven_io_dumbo.SQL`
|
|
2970
|
-
CREATE TABLE IF NOT EXISTS ${_event_driven_io_dumbo.SQL.identifier(processorsTable.name)}(
|
|
2971
|
-
last_processed_transaction_id XID8 NOT NULL,
|
|
2972
|
-
version INT NOT NULL DEFAULT 1,
|
|
2973
|
-
processor_id TEXT NOT NULL,
|
|
2974
|
-
partition TEXT NOT NULL DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
2975
|
-
status TEXT NOT NULL DEFAULT 'stopped',
|
|
2976
|
-
last_processed_checkpoint TEXT NOT NULL,
|
|
2977
|
-
processor_instance_id TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(unknownTag)}',
|
|
2978
|
-
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
2979
|
-
last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
2980
|
-
PRIMARY KEY (processor_id, partition, version)
|
|
2981
|
-
) PARTITION BY LIST (partition);
|
|
2982
|
-
`;
|
|
2983
|
-
const projectionsTableSQL = _event_driven_io_dumbo.SQL`
|
|
2984
|
-
CREATE TABLE IF NOT EXISTS ${_event_driven_io_dumbo.SQL.identifier(projectionsTable.name)}(
|
|
2985
|
-
version INT NOT NULL DEFAULT 1,
|
|
2986
|
-
type VARCHAR(1) NOT NULL,
|
|
2987
|
-
name TEXT NOT NULL,
|
|
2988
|
-
partition TEXT NOT NULL DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
2989
|
-
kind TEXT NOT NULL,
|
|
2990
|
-
status TEXT NOT NULL,
|
|
2991
|
-
definition JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
2992
|
-
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
2993
|
-
last_updated TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
2994
|
-
PRIMARY KEY (name, partition, version)
|
|
2995
|
-
) PARTITION BY LIST (partition);
|
|
2996
|
-
`;
|
|
2997
|
-
const sanitizeNameSQL = createFunctionIfDoesNotExistSQL("emt_sanitize_name", _event_driven_io_dumbo.SQL`CREATE OR REPLACE FUNCTION emt_sanitize_name(input_name TEXT) RETURNS TEXT AS $emt_sanitize_name$
|
|
2998
|
-
BEGIN
|
|
2999
|
-
RETURN REGEXP_REPLACE(input_name, '[^a-zA-Z0-9_]', '_', 'g');
|
|
3000
|
-
END;
|
|
3001
|
-
$emt_sanitize_name$ LANGUAGE plpgsql;`);
|
|
3002
|
-
const addTablePartitions = createFunctionIfDoesNotExistSQL("emt_add_table_partition", _event_driven_io_dumbo.SQL`
|
|
3003
|
-
CREATE OR REPLACE FUNCTION emt_add_table_partition(tableName TEXT, partition_name TEXT) RETURNS void AS $emt_add_table_partition$
|
|
3004
|
-
DECLARE
|
|
3005
|
-
v_main_partiton_name TEXT;
|
|
3006
|
-
v_active_partiton_name TEXT;
|
|
3007
|
-
v_archived_partiton_name TEXT;
|
|
3008
|
-
BEGIN
|
|
3009
|
-
v_main_partiton_name := emt_sanitize_name(tableName || '_' || partition_name);
|
|
3010
|
-
v_active_partiton_name := emt_sanitize_name(v_main_partiton_name || '_active');
|
|
3011
|
-
v_archived_partiton_name := emt_sanitize_name(v_main_partiton_name || '_archived');
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
-- create default partition
|
|
3015
|
-
EXECUTE format('
|
|
3016
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
3017
|
-
FOR VALUES IN (%L) PARTITION BY LIST (is_archived);',
|
|
3018
|
-
v_main_partiton_name, tableName, partition_name
|
|
3019
|
-
);
|
|
3020
|
-
|
|
3021
|
-
EXECUTE format('
|
|
3022
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
3023
|
-
FOR VALUES IN (FALSE);',
|
|
3024
|
-
v_active_partiton_name, v_main_partiton_name
|
|
3025
|
-
);
|
|
3026
|
-
|
|
3027
|
-
EXECUTE format('
|
|
3028
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
3029
|
-
FOR VALUES IN (TRUE);',
|
|
3030
|
-
v_archived_partiton_name, v_main_partiton_name
|
|
3031
|
-
);
|
|
3032
|
-
END;
|
|
3033
|
-
$emt_add_table_partition$ LANGUAGE plpgsql;`);
|
|
3034
|
-
const addPartitionSQL = createFunctionIfDoesNotExistSQL("emt_add_partition", _event_driven_io_dumbo.SQL`
|
|
3035
|
-
CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $emt_add_partition$
|
|
3036
|
-
BEGIN
|
|
3037
|
-
PERFORM emt_add_table_partition('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}', partition_name);
|
|
3038
|
-
PERFORM emt_add_table_partition('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}', partition_name);
|
|
3039
|
-
|
|
3040
|
-
EXECUTE format('
|
|
3041
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
3042
|
-
FOR VALUES IN (%L);',
|
|
3043
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}' || '_' || partition_name), '${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}', partition_name
|
|
3044
|
-
);
|
|
3045
|
-
|
|
3046
|
-
EXECUTE format('
|
|
3047
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
3048
|
-
FOR VALUES IN (%L);',
|
|
3049
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(projectionsTable.name)}' || '_' || partition_name), '${_event_driven_io_dumbo.SQL.plain(projectionsTable.name)}', partition_name
|
|
3050
|
-
);
|
|
3051
|
-
END;
|
|
3052
|
-
$emt_add_partition$ LANGUAGE plpgsql;`);
|
|
3053
|
-
const addModuleSQL = _event_driven_io_dumbo.SQL`
|
|
3054
|
-
CREATE OR REPLACE FUNCTION add_module(new_module TEXT) RETURNS void AS $$
|
|
3055
|
-
BEGIN
|
|
3056
|
-
-- For ${_event_driven_io_dumbo.SQL.plain(messagesTable.name)} table
|
|
3057
|
-
EXECUTE format('
|
|
3058
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
3059
|
-
FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',
|
|
3060
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}'), '${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}', new_module, '${_event_driven_io_dumbo.SQL.plain(globalTag)}'
|
|
3061
|
-
);
|
|
3062
|
-
|
|
3063
|
-
EXECUTE format('
|
|
3064
|
-
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
3065
|
-
FOR VALUES IN (FALSE);',
|
|
3066
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}' || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}')
|
|
3067
|
-
);
|
|
3068
|
-
|
|
3069
|
-
EXECUTE format('
|
|
3070
|
-
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
3071
|
-
FOR VALUES IN (TRUE);',
|
|
3072
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}' || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}')
|
|
3073
|
-
);
|
|
3074
|
-
|
|
3075
|
-
-- For ${_event_driven_io_dumbo.SQL.plain(streamsTable.name)} table
|
|
3076
|
-
EXECUTE format('
|
|
3077
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
3078
|
-
FOR VALUES IN (emt_sanitize_name(%L || ''__'' || %L)) PARTITION BY LIST (is_archived);',
|
|
3079
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}'), '${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}', new_module, '${_event_driven_io_dumbo.SQL.plain(globalTag)}'
|
|
3080
|
-
);
|
|
3081
|
-
|
|
3082
|
-
EXECUTE format('
|
|
3083
|
-
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
3084
|
-
FOR VALUES IN (FALSE);',
|
|
3085
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}' || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}')
|
|
3086
|
-
);
|
|
3087
|
-
|
|
3088
|
-
EXECUTE format('
|
|
3089
|
-
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
3090
|
-
FOR VALUES IN (TRUE);',
|
|
3091
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}' || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || '${_event_driven_io_dumbo.SQL.plain(globalTag)}')
|
|
3092
|
-
);
|
|
3093
|
-
END;
|
|
3094
|
-
$$ LANGUAGE plpgsql;
|
|
3095
|
-
`;
|
|
3096
|
-
const addTenantSQL = _event_driven_io_dumbo.SQL`
|
|
3097
|
-
CREATE OR REPLACE FUNCTION add_tenant(new_module TEXT, new_tenant TEXT) RETURNS void AS $$
|
|
3098
|
-
BEGIN
|
|
3099
|
-
-- For ${_event_driven_io_dumbo.SQL.plain(messagesTable.name)} table
|
|
3100
|
-
EXECUTE format('
|
|
3101
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
3102
|
-
FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
|
|
3103
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant), '${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}', new_module, new_tenant
|
|
3104
|
-
);
|
|
3105
|
-
|
|
3106
|
-
EXECUTE format('
|
|
3107
|
-
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
3108
|
-
FOR VALUES IN (FALSE);',
|
|
3109
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant)
|
|
3110
|
-
);
|
|
3111
|
-
|
|
3112
|
-
EXECUTE format('
|
|
3113
|
-
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
3114
|
-
FOR VALUES IN (TRUE);',
|
|
3115
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || new_tenant)
|
|
3116
|
-
);
|
|
3117
|
-
|
|
3118
|
-
-- For ${_event_driven_io_dumbo.SQL.plain(streamsTable.name)} table
|
|
2458
|
+
//#endregion
|
|
2459
|
+
//#region src/eventStore/schema/migrations/0_43_0/0_43_0.migration.ts
|
|
2460
|
+
const migration_0_43_0_cleanupLegacySubscriptionSQL = _event_driven_io_dumbo.SQL`
|
|
2461
|
+
DO $$
|
|
2462
|
+
BEGIN
|
|
2463
|
+
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'emt_subscriptions') THEN
|
|
2464
|
+
-- Restore clean emt_add_partition (remove creation of emt_subscriptions partitions)
|
|
2465
|
+
CREATE OR REPLACE FUNCTION emt_add_partition(partition_name TEXT) RETURNS void AS $fnpar$
|
|
2466
|
+
BEGIN
|
|
2467
|
+
PERFORM emt_add_table_partition('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}', partition_name);
|
|
2468
|
+
PERFORM emt_add_table_partition('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}', partition_name);
|
|
2469
|
+
|
|
3119
2470
|
EXECUTE format('
|
|
3120
2471
|
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
3121
|
-
FOR VALUES IN (
|
|
3122
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(
|
|
3123
|
-
);
|
|
3124
|
-
|
|
3125
|
-
EXECUTE format('
|
|
3126
|
-
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
3127
|
-
FOR VALUES IN (FALSE);',
|
|
3128
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || new_tenant)
|
|
2472
|
+
FOR VALUES IN (%L);',
|
|
2473
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}' || '_' || partition_name), '${_event_driven_io_dumbo.SQL.plain(processorsTable.name)}', partition_name
|
|
3129
2474
|
);
|
|
3130
|
-
|
|
2475
|
+
|
|
3131
2476
|
EXECUTE format('
|
|
3132
|
-
CREATE TABLE IF NOT EXISTS %
|
|
3133
|
-
FOR VALUES IN (
|
|
3134
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(
|
|
2477
|
+
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
2478
|
+
FOR VALUES IN (%L);',
|
|
2479
|
+
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(projectionsTable.name)}' || '_' || partition_name), '${_event_driven_io_dumbo.SQL.plain(projectionsTable.name)}', partition_name
|
|
3135
2480
|
);
|
|
3136
2481
|
END;
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
EXECUTE format('
|
|
3156
|
-
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
3157
|
-
FOR VALUES IN (FALSE);',
|
|
3158
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant)
|
|
3159
|
-
);
|
|
3160
|
-
|
|
3161
|
-
EXECUTE format('
|
|
3162
|
-
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
3163
|
-
FOR VALUES IN (TRUE);',
|
|
3164
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(messagesTable.name)}_' || new_module || '__' || tenant_record.tenant)
|
|
3165
|
-
);
|
|
3166
|
-
|
|
3167
|
-
-- For ${_event_driven_io_dumbo.SQL.plain(streamsTable.name)} table
|
|
3168
|
-
EXECUTE format('
|
|
3169
|
-
CREATE TABLE IF NOT EXISTS %I PARTITION OF %I
|
|
3170
|
-
FOR VALUES IN (emt_sanitize_name(''%s__%s'')) PARTITION BY LIST (is_archived);',
|
|
3171
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant), '${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}', new_module, tenant_record.tenant
|
|
3172
|
-
);
|
|
3173
|
-
|
|
3174
|
-
EXECUTE format('
|
|
3175
|
-
CREATE TABLE IF NOT EXISTS %I_active PARTITION OF %I
|
|
3176
|
-
FOR VALUES IN (FALSE);',
|
|
3177
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant || '_active'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant)
|
|
3178
|
-
);
|
|
3179
|
-
|
|
3180
|
-
EXECUTE format('
|
|
3181
|
-
CREATE TABLE IF NOT EXISTS %I_archived PARTITION OF %I
|
|
3182
|
-
FOR VALUES IN (TRUE);',
|
|
3183
|
-
emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant || '_archived'), emt_sanitize_name('${_event_driven_io_dumbo.SQL.plain(streamsTable.name)}_' || new_module || '__' || tenant_record.tenant)
|
|
3184
|
-
);
|
|
3185
|
-
END LOOP;
|
|
3186
|
-
END;
|
|
3187
|
-
$$ LANGUAGE plpgsql;
|
|
3188
|
-
`;
|
|
3189
|
-
const addTenantForAllModulesSQL = _event_driven_io_dumbo.SQL`
|
|
3190
|
-
CREATE OR REPLACE FUNCTION add_tenant_for_all_modules(new_tenant TEXT) RETURNS void AS $$
|
|
2482
|
+
$fnpar$ LANGUAGE plpgsql;
|
|
2483
|
+
|
|
2484
|
+
-- Drop old subscriptions table if it exists
|
|
2485
|
+
DROP TABLE IF EXISTS emt_subscriptions CASCADE;
|
|
2486
|
+
|
|
2487
|
+
-- Drop old function if it exists
|
|
2488
|
+
DROP FUNCTION IF EXISTS store_subscription_checkpoint(character varying, bigint, bigint, bigint, xid8, text);
|
|
2489
|
+
|
|
2490
|
+
-- Restore clean store_processor_checkpoint (remove dual-write logic)
|
|
2491
|
+
CREATE OR REPLACE FUNCTION store_processor_checkpoint(
|
|
2492
|
+
p_processor_id TEXT,
|
|
2493
|
+
p_version BIGINT,
|
|
2494
|
+
p_position TEXT,
|
|
2495
|
+
p_check_position TEXT,
|
|
2496
|
+
p_transaction_id xid8,
|
|
2497
|
+
p_partition TEXT DEFAULT '${_event_driven_io_dumbo.SQL.plain(defaultTag)}',
|
|
2498
|
+
p_processor_instance_id TEXT DEFAULT 'emt:unknown'
|
|
2499
|
+
) RETURNS INT AS $fn$
|
|
3191
2500
|
DECLARE
|
|
3192
|
-
|
|
2501
|
+
current_position TEXT;
|
|
3193
2502
|
BEGIN
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
2503
|
+
IF p_check_position IS NOT NULL THEN
|
|
2504
|
+
UPDATE "emt_processors"
|
|
2505
|
+
SET
|
|
2506
|
+
"last_processed_checkpoint" = p_position,
|
|
2507
|
+
"last_processed_transaction_id" = p_transaction_id,
|
|
2508
|
+
"last_updated" = now()
|
|
2509
|
+
WHERE "processor_id" = p_processor_id
|
|
2510
|
+
AND "last_processed_checkpoint" = p_check_position
|
|
2511
|
+
AND "partition" = p_partition
|
|
2512
|
+
AND "version" = p_version;
|
|
2513
|
+
|
|
2514
|
+
IF FOUND THEN
|
|
2515
|
+
RETURN 1;
|
|
2516
|
+
END IF;
|
|
2517
|
+
|
|
2518
|
+
SELECT "last_processed_checkpoint" INTO current_position
|
|
2519
|
+
FROM "emt_processors"
|
|
2520
|
+
WHERE "processor_id" = p_processor_id
|
|
2521
|
+
AND "partition" = p_partition
|
|
2522
|
+
AND "version" = p_version ;
|
|
2523
|
+
|
|
2524
|
+
IF current_position = p_position THEN
|
|
2525
|
+
RETURN 0;
|
|
2526
|
+
ELSIF current_position > p_position THEN
|
|
2527
|
+
RETURN 3;
|
|
2528
|
+
ELSE
|
|
2529
|
+
RETURN 2;
|
|
2530
|
+
END IF;
|
|
2531
|
+
END IF;
|
|
2532
|
+
|
|
2533
|
+
BEGIN
|
|
2534
|
+
INSERT INTO "emt_processors"("processor_id", "version", "last_processed_checkpoint", "partition", "last_processed_transaction_id", "created_at", "last_updated")
|
|
2535
|
+
VALUES (p_processor_id, p_version, p_position, p_partition, p_transaction_id, now(), now());
|
|
2536
|
+
RETURN 1;
|
|
2537
|
+
EXCEPTION WHEN unique_violation THEN
|
|
2538
|
+
SELECT "last_processed_checkpoint" INTO current_position
|
|
2539
|
+
FROM "emt_processors"
|
|
2540
|
+
WHERE "processor_id" = p_processor_id
|
|
2541
|
+
AND "partition" = p_partition
|
|
2542
|
+
AND "version" = p_version;
|
|
2543
|
+
|
|
2544
|
+
IF current_position = p_position THEN
|
|
2545
|
+
RETURN 0;
|
|
2546
|
+
ELSE
|
|
2547
|
+
RETURN 2;
|
|
2548
|
+
END IF;
|
|
2549
|
+
END;
|
|
3234
2550
|
END;
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
2551
|
+
$fn$ LANGUAGE plpgsql;
|
|
2552
|
+
END IF;
|
|
2553
|
+
END $$;
|
|
2554
|
+
`;
|
|
2555
|
+
const migration_0_43_0_cleanupLegacySubscription = (0, _event_driven_io_dumbo.sqlMigration)("emt:postgresql:eventstore:0.43.0:cleanup-legacy-subscription", [migration_0_43_0_cleanupLegacySubscriptionSQL]);
|
|
2556
|
+
|
|
2557
|
+
//#endregion
|
|
2558
|
+
//#region src/eventStore/schema/migrations/0_43_0/index.ts
|
|
2559
|
+
const migrations_0_43_0 = [migration_0_43_0_cleanupLegacySubscription];
|
|
2560
|
+
|
|
2561
|
+
//#endregion
|
|
2562
|
+
//#region src/eventStore/schema/migrations/index.ts
|
|
2563
|
+
const schemaSQL$1 = [
|
|
2564
|
+
streamsTableSQL,
|
|
2565
|
+
messagesTableSQL,
|
|
2566
|
+
projectionsTableSQL,
|
|
2567
|
+
processorsTableSQL,
|
|
2568
|
+
sanitizeNameSQL,
|
|
2569
|
+
addTablePartitions,
|
|
2570
|
+
addPartitionSQL,
|
|
2571
|
+
appendToStreamSQL,
|
|
2572
|
+
addDefaultPartitionSQL,
|
|
2573
|
+
storeSubscriptionCheckpointSQL,
|
|
2574
|
+
tryAcquireProcessorLockSQL,
|
|
2575
|
+
releaseProcessorLockSQL,
|
|
2576
|
+
registerProjectionSQL,
|
|
2577
|
+
activateProjectionSQL,
|
|
2578
|
+
deactivateProjectionSQL
|
|
2579
|
+
];
|
|
2580
|
+
const currentPostgreSQLEventStoreSchemaVersion = "0.43.0";
|
|
2581
|
+
const schemaMigration$1 = (0, _event_driven_io_dumbo.sqlMigration)("emt:postgresql:eventstore:initial", schemaSQL$1);
|
|
2582
|
+
const pastEventStoreSchemaMigrations = [
|
|
2583
|
+
...migrations_0_38_7,
|
|
2584
|
+
...migrations_0_42_0,
|
|
2585
|
+
...migrations_0_43_0
|
|
2586
|
+
];
|
|
2587
|
+
const eventStoreSchemaMigrations = [...pastEventStoreSchemaMigrations, schemaMigration$1];
|
|
3238
2588
|
|
|
3239
2589
|
//#endregion
|
|
3240
2590
|
//#region src/eventStore/schema/readProcessorCheckpoint.ts
|
|
@@ -3316,12 +2666,6 @@ const schemaSQL = [
|
|
|
3316
2666
|
deactivateProjectionSQL
|
|
3317
2667
|
];
|
|
3318
2668
|
const schemaMigration = (0, _event_driven_io_dumbo.sqlMigration)("emt:postgresql:eventstore:initial", schemaSQL);
|
|
3319
|
-
const eventStoreSchemaMigrations = [
|
|
3320
|
-
migration_0_38_7_and_older,
|
|
3321
|
-
migration_0_42_0_FromSubscriptionsToProcessors,
|
|
3322
|
-
migration_0_42_0_2_AddProcessorProjectionFunctions,
|
|
3323
|
-
schemaMigration
|
|
3324
|
-
];
|
|
3325
2669
|
const createEventStoreSchema = (connectionString, pool, hooks, options) => {
|
|
3326
2670
|
return pool.withTransaction(async (tx) => {
|
|
3327
2671
|
const context = await transactionToPostgreSQLProjectionHandlerContext(connectionString, pool, tx);
|
|
@@ -3372,24 +2716,32 @@ const getPostgreSQLEventStore = (connectionString, options = defaultPostgreSQLOp
|
|
|
3372
2716
|
const autoGenerateSchema = options.schema?.autoMigration === void 0 || options.schema?.autoMigration !== "None";
|
|
3373
2717
|
const inlineProjections = (options.projections ?? []).filter(({ type }) => type === "inline").map(({ projection }) => projection);
|
|
3374
2718
|
const migrate = async (migrationOptions) => {
|
|
3375
|
-
if (!migrateSchema)
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
2719
|
+
if (!migrateSchema) {
|
|
2720
|
+
migrateSchema = createEventStoreSchema(connectionString, pool, {
|
|
2721
|
+
onBeforeSchemaCreated: async (context) => {
|
|
2722
|
+
if (options.hooks?.onBeforeSchemaCreated) await options.hooks.onBeforeSchemaCreated(context);
|
|
2723
|
+
},
|
|
2724
|
+
onAfterSchemaCreated: async (context) => {
|
|
2725
|
+
for (const projection of inlineProjections) if (projection.init) await projection.init({
|
|
2726
|
+
version: projection.version ?? 1,
|
|
2727
|
+
status: "active",
|
|
2728
|
+
registrationType: "inline",
|
|
2729
|
+
context: {
|
|
2730
|
+
...context,
|
|
2731
|
+
migrationOptions
|
|
2732
|
+
}
|
|
2733
|
+
});
|
|
2734
|
+
if (options.hooks?.onAfterSchemaCreated) await options.hooks.onAfterSchemaCreated(context);
|
|
2735
|
+
}
|
|
2736
|
+
}, migrationOptions);
|
|
2737
|
+
return migrateSchema;
|
|
2738
|
+
}
|
|
2739
|
+
const result = await migrateSchema;
|
|
2740
|
+
if (migrationOptions?.dryRun) migrateSchema = void 0;
|
|
2741
|
+
return {
|
|
2742
|
+
applied: [],
|
|
2743
|
+
skipped: result.applied.concat(result.skipped)
|
|
2744
|
+
};
|
|
3393
2745
|
};
|
|
3394
2746
|
const ensureSchemaExists = () => {
|
|
3395
2747
|
if (!autoGenerateSchema) return Promise.resolve();
|
|
@@ -3441,7 +2793,7 @@ const getPostgreSQLEventStore = (connectionString, options = defaultPostgreSQLOp
|
|
|
3441
2793
|
appendToStream: async (streamName, events, appendOptions) => {
|
|
3442
2794
|
await ensureSchemaExists();
|
|
3443
2795
|
const [firstPart, ...rest] = streamName.split("-");
|
|
3444
|
-
const appendResult = await appendToStream(pool, streamName, firstPart && rest.length > 0 ? firstPart : unknownTag, (0, _event_driven_io_emmett.downcastRecordedMessages)(events, appendOptions?.schema?.versioning), {
|
|
2796
|
+
const appendResult = await appendToStream(pool, streamName, firstPart && rest.length > 0 ? firstPart : _event_driven_io_emmett.unknownTag, (0, _event_driven_io_emmett.downcastRecordedMessages)(events, appendOptions?.schema?.versioning), {
|
|
3445
2797
|
...appendOptions,
|
|
3446
2798
|
beforeCommitHook
|
|
3447
2799
|
});
|
|
@@ -3702,10 +3054,15 @@ const postgreSQLEventStoreConsumer = (options) => {
|
|
|
3702
3054
|
reason: "No active processors"
|
|
3703
3055
|
};
|
|
3704
3056
|
return (await Promise.allSettled(activeProcessors.map(async (s) => {
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3057
|
+
try {
|
|
3058
|
+
return await s.handle(messagesBatch, { connection: {
|
|
3059
|
+
connectionString: options.connectionString,
|
|
3060
|
+
pool
|
|
3061
|
+
} });
|
|
3062
|
+
} catch (error) {
|
|
3063
|
+
console.log(`Error during message batch processing for processor: ${s.id}`, error);
|
|
3064
|
+
throw error;
|
|
3065
|
+
}
|
|
3709
3066
|
}))).some((r) => r.status === "fulfilled" && r.value?.type !== "STOP") ? void 0 : { type: "STOP" };
|
|
3710
3067
|
};
|
|
3711
3068
|
const processorContext = {
|
|
@@ -3726,7 +3083,11 @@ const postgreSQLEventStoreConsumer = (options) => {
|
|
|
3726
3083
|
abortController?.abort();
|
|
3727
3084
|
await messagePuller.stop();
|
|
3728
3085
|
}
|
|
3729
|
-
|
|
3086
|
+
try {
|
|
3087
|
+
await start;
|
|
3088
|
+
} catch (error) {
|
|
3089
|
+
console.log("Error during consumer stop:", error);
|
|
3090
|
+
}
|
|
3730
3091
|
messagePuller = void 0;
|
|
3731
3092
|
abortController = null;
|
|
3732
3093
|
await stopProcessors();
|
|
@@ -3734,7 +3095,16 @@ const postgreSQLEventStoreConsumer = (options) => {
|
|
|
3734
3095
|
const init = async () => {
|
|
3735
3096
|
if (isInitialized) return;
|
|
3736
3097
|
const postgresProcessors = processors;
|
|
3737
|
-
for (const processor of postgresProcessors) if (processor.init)
|
|
3098
|
+
for (const processor of postgresProcessors) if (processor.init) try {
|
|
3099
|
+
await processor.init(processorContext);
|
|
3100
|
+
} catch (error) {
|
|
3101
|
+
console.log(`Error during processor initialization for processor: ${processor.id}. Stopping it.`, error);
|
|
3102
|
+
await processor.close(processorContext).catch((closeError) => {
|
|
3103
|
+
console.log(`Error during processor cleanup after failed initialization for processor: ${processor.id}`, closeError);
|
|
3104
|
+
});
|
|
3105
|
+
console.log(`Processor ${processor.id} stopped successfully after failed initialization.`);
|
|
3106
|
+
throw error;
|
|
3107
|
+
}
|
|
3738
3108
|
isInitialized = true;
|
|
3739
3109
|
};
|
|
3740
3110
|
return {
|
|
@@ -3761,9 +3131,13 @@ const postgreSQLEventStoreConsumer = (options) => {
|
|
|
3761
3131
|
return processor;
|
|
3762
3132
|
},
|
|
3763
3133
|
start: () => {
|
|
3764
|
-
if (isRunning)
|
|
3134
|
+
if (isRunning) {
|
|
3135
|
+
console.log("Consumer is already running. Returning the existing start promise.");
|
|
3136
|
+
return start;
|
|
3137
|
+
}
|
|
3765
3138
|
startedAwaiter.reset();
|
|
3766
3139
|
if (processors.length === 0) {
|
|
3140
|
+
console.log("Cannot start consumer without at least a single processor");
|
|
3767
3141
|
const error = new _event_driven_io_emmett.EmmettError("Cannot start consumer without at least a single processor");
|
|
3768
3142
|
startedAwaiter.reject(error);
|
|
3769
3143
|
return Promise.reject(error);
|
|
@@ -3781,16 +3155,25 @@ const postgreSQLEventStoreConsumer = (options) => {
|
|
|
3781
3155
|
pullingFrequencyInMs: pulling?.pullingFrequencyInMs ?? 50,
|
|
3782
3156
|
signal: abortController.signal
|
|
3783
3157
|
});
|
|
3784
|
-
if (!isInitialized)
|
|
3158
|
+
if (!isInitialized) {
|
|
3159
|
+
console.log("Initializing consumer before starting message pulling.");
|
|
3160
|
+
await init();
|
|
3161
|
+
}
|
|
3785
3162
|
const startFrom = zipPostgreSQLEventStoreMessageBatchPullerStartFrom(await Promise.all(processors.map(async (o) => {
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3163
|
+
try {
|
|
3164
|
+
return await o.start({
|
|
3165
|
+
execute: pool.execute,
|
|
3166
|
+
connection: {
|
|
3167
|
+
connectionString: options.connectionString,
|
|
3168
|
+
pool
|
|
3169
|
+
}
|
|
3170
|
+
});
|
|
3171
|
+
} catch (error) {
|
|
3172
|
+
console.log(`Error during processor start position retrieval for processor: ${o.id}. Stopping it.`, error);
|
|
3173
|
+
throw error;
|
|
3174
|
+
}
|
|
3793
3175
|
})));
|
|
3176
|
+
console.log(`Starting message pulling with start position: ${_event_driven_io_dumbo.JSONSerializer.serialize(startFrom)}. Waiting for messages...`);
|
|
3794
3177
|
await messagePuller.start({
|
|
3795
3178
|
startFrom,
|
|
3796
3179
|
started: startedAwaiter
|
|
@@ -3873,30 +3256,26 @@ exports.callReleaseProcessorLock = callReleaseProcessorLock;
|
|
|
3873
3256
|
exports.callStoreProcessorCheckpoint = callStoreProcessorCheckpoint;
|
|
3874
3257
|
exports.callTryAcquireProcessorLock = callTryAcquireProcessorLock;
|
|
3875
3258
|
exports.callTryAcquireProjectionLock = callTryAcquireProjectionLock;
|
|
3876
|
-
exports.cleanupLegacySubscriptionTables = cleanupLegacySubscriptionTables;
|
|
3877
3259
|
exports.createEventStoreSchema = createEventStoreSchema;
|
|
3260
|
+
exports.currentPostgreSQLEventStoreSchemaVersion = currentPostgreSQLEventStoreSchemaVersion;
|
|
3878
3261
|
exports.deactivateProjection = deactivateProjection;
|
|
3879
3262
|
exports.deactivateProjectionSQL = deactivateProjectionSQL;
|
|
3880
3263
|
exports.defaultPostgreSQLOptions = defaultPostgreSQLOptions;
|
|
3881
|
-
exports.defaultTag = defaultTag;
|
|
3882
3264
|
exports.documentDoesNotExist = documentDoesNotExist;
|
|
3883
3265
|
exports.documentExists = documentExists;
|
|
3884
3266
|
exports.documentMatchingExists = documentMatchingExists;
|
|
3885
3267
|
exports.documentsAreTheSame = documentsAreTheSame;
|
|
3886
3268
|
exports.documentsMatchingHaveCount = documentsMatchingHaveCount;
|
|
3887
|
-
exports.emmettPrefix = emmettPrefix;
|
|
3888
3269
|
exports.eventInStream = eventInStream;
|
|
3889
3270
|
exports.eventStoreSchemaMigrations = eventStoreSchemaMigrations;
|
|
3890
3271
|
exports.eventsInStream = eventsInStream;
|
|
3891
3272
|
exports.expectPongoDocuments = expectPongoDocuments;
|
|
3892
3273
|
exports.expectSQL = expectSQL;
|
|
3893
3274
|
exports.getPostgreSQLEventStore = getPostgreSQLEventStore;
|
|
3894
|
-
exports.globalNames = globalNames;
|
|
3895
|
-
exports.globalTag = globalTag;
|
|
3896
3275
|
exports.handleProjections = handleProjections;
|
|
3897
|
-
exports.messagesTable = messagesTable;
|
|
3898
3276
|
exports.messagesTableSQL = messagesTableSQL;
|
|
3899
3277
|
exports.newEventsInStream = newEventsInStream;
|
|
3278
|
+
exports.pastEventStoreSchemaMigrations = pastEventStoreSchemaMigrations;
|
|
3900
3279
|
exports.pongoMultiStreamProjection = pongoMultiStreamProjection;
|
|
3901
3280
|
exports.pongoProjection = pongoProjection;
|
|
3902
3281
|
exports.pongoSingleStreamProjection = pongoSingleStreamProjection;
|
|
@@ -3911,9 +3290,7 @@ exports.postgreSQLRawBatchSQLProjection = postgreSQLRawBatchSQLProjection;
|
|
|
3911
3290
|
exports.postgreSQLRawSQLProjection = postgreSQLRawSQLProjection;
|
|
3912
3291
|
exports.postgreSQLReactor = postgreSQLReactor;
|
|
3913
3292
|
exports.postgreSQLWorkflowProcessor = postgreSQLWorkflowProcessor;
|
|
3914
|
-
exports.processorsTable = processorsTable;
|
|
3915
3293
|
exports.processorsTableSQL = processorsTableSQL;
|
|
3916
|
-
exports.projectionsTable = projectionsTable;
|
|
3917
3294
|
exports.projectionsTableSQL = projectionsTableSQL;
|
|
3918
3295
|
exports.readLastMessageGlobalPosition = readLastMessageGlobalPosition;
|
|
3919
3296
|
exports.readMessagesBatch = readMessagesBatch;
|
|
@@ -3930,13 +3307,11 @@ exports.schemaSQL = schemaSQL;
|
|
|
3930
3307
|
exports.storeProcessorCheckpoint = storeProcessorCheckpoint;
|
|
3931
3308
|
exports.storeSubscriptionCheckpointSQL = storeSubscriptionCheckpointSQL;
|
|
3932
3309
|
exports.streamExists = streamExists;
|
|
3933
|
-
exports.streamsTable = streamsTable;
|
|
3934
3310
|
exports.streamsTableSQL = streamsTableSQL;
|
|
3935
3311
|
exports.toProcessorLockKey = toProcessorLockKey;
|
|
3936
3312
|
exports.toProjectionLockKey = toProjectionLockKey;
|
|
3937
3313
|
exports.transactionToPostgreSQLProjectionHandlerContext = transactionToPostgreSQLProjectionHandlerContext;
|
|
3938
3314
|
exports.tryAcquireProcessorLockSQL = tryAcquireProcessorLockSQL;
|
|
3939
3315
|
exports.tryAcquireProjectionLockSQL = tryAcquireProjectionLockSQL;
|
|
3940
|
-
exports.unknownTag = unknownTag;
|
|
3941
3316
|
exports.zipPostgreSQLEventStoreMessageBatchPullerStartFrom = zipPostgreSQLEventStoreMessageBatchPullerStartFrom;
|
|
3942
3317
|
//# sourceMappingURL=index.cjs.map
|