@hotmeshio/hotmesh 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/modules/enums.d.ts +110 -0
- package/build/modules/enums.js +134 -0
- package/build/modules/errors.d.ts +124 -0
- package/build/modules/errors.js +191 -0
- package/build/modules/key.d.ts +66 -0
- package/build/modules/key.js +190 -0
- package/build/modules/storage.d.ts +3 -0
- package/build/modules/storage.js +5 -0
- package/build/modules/utils.d.ts +119 -0
- package/build/modules/utils.js +374 -0
- package/build/package.json +1 -1
- package/build/services/activities/activity.d.ts +104 -0
- package/build/services/activities/activity.js +549 -0
- package/build/services/activities/await.d.ts +12 -0
- package/build/services/activities/await.js +114 -0
- package/build/services/activities/cycle.d.ts +19 -0
- package/build/services/activities/cycle.js +112 -0
- package/build/services/activities/hook.d.ts +27 -0
- package/build/services/activities/hook.js +168 -0
- package/build/services/activities/index.d.ts +19 -0
- package/build/services/activities/index.js +20 -0
- package/build/services/activities/interrupt.d.ts +16 -0
- package/build/services/activities/interrupt.js +158 -0
- package/build/services/activities/signal.d.ts +20 -0
- package/build/services/activities/signal.js +134 -0
- package/build/services/activities/trigger.d.ts +37 -0
- package/build/services/activities/trigger.js +246 -0
- package/build/services/activities/worker.d.ts +12 -0
- package/build/services/activities/worker.js +106 -0
- package/build/services/collator/index.d.ts +111 -0
- package/build/services/collator/index.js +293 -0
- package/build/services/compiler/deployer.d.ts +40 -0
- package/build/services/compiler/deployer.js +488 -0
- package/build/services/compiler/index.d.ts +32 -0
- package/build/services/compiler/index.js +112 -0
- package/build/services/compiler/validator.d.ts +34 -0
- package/build/services/compiler/validator.js +147 -0
- package/build/services/connector/factory.d.ts +22 -0
- package/build/services/connector/factory.js +99 -0
- package/build/services/connector/index.d.ts +30 -0
- package/build/services/connector/index.js +54 -0
- package/build/services/connector/providers/ioredis.d.ts +9 -0
- package/build/services/connector/providers/ioredis.js +26 -0
- package/build/services/connector/providers/nats.d.ts +9 -0
- package/build/services/connector/providers/nats.js +34 -0
- package/build/services/connector/providers/postgres.d.ts +20 -0
- package/build/services/connector/providers/postgres.js +102 -0
- package/build/services/connector/providers/redis.d.ts +9 -0
- package/build/services/connector/providers/redis.js +38 -0
- package/build/services/engine/index.d.ts +264 -0
- package/build/services/engine/index.js +761 -0
- package/build/services/exporter/index.d.ts +44 -0
- package/build/services/exporter/index.js +126 -0
- package/build/services/hotmesh/index.d.ts +483 -0
- package/build/services/hotmesh/index.js +622 -0
- package/build/services/logger/index.d.ts +16 -0
- package/build/services/logger/index.js +54 -0
- package/build/services/mapper/index.d.ts +28 -0
- package/build/services/mapper/index.js +81 -0
- package/build/services/memflow/client.d.ts +108 -0
- package/build/services/memflow/client.js +372 -0
- package/build/services/memflow/connection.d.ts +23 -0
- package/build/services/memflow/connection.js +33 -0
- package/build/services/memflow/context.d.ts +143 -0
- package/build/services/memflow/context.js +299 -0
- package/build/services/memflow/exporter.d.ts +51 -0
- package/build/services/memflow/exporter.js +215 -0
- package/build/services/memflow/handle.d.ts +90 -0
- package/build/services/memflow/handle.js +176 -0
- package/build/services/memflow/index.d.ts +116 -0
- package/build/services/memflow/index.js +122 -0
- package/build/services/memflow/schemas/factory.d.ts +29 -0
- package/build/services/memflow/schemas/factory.js +2492 -0
- package/build/services/memflow/search.d.ts +142 -0
- package/build/services/memflow/search.js +320 -0
- package/build/services/memflow/worker.d.ts +124 -0
- package/build/services/memflow/worker.js +514 -0
- package/build/services/memflow/workflow/all.d.ts +7 -0
- package/build/services/memflow/workflow/all.js +15 -0
- package/build/services/memflow/workflow/common.d.ts +20 -0
- package/build/services/memflow/workflow/common.js +47 -0
- package/build/services/memflow/workflow/context.d.ts +6 -0
- package/build/services/memflow/workflow/context.js +45 -0
- package/build/services/memflow/workflow/contextMethods.d.ts +14 -0
- package/build/services/memflow/workflow/contextMethods.js +33 -0
- package/build/services/memflow/workflow/didRun.d.ts +7 -0
- package/build/services/memflow/workflow/didRun.js +22 -0
- package/build/services/memflow/workflow/emit.d.ts +11 -0
- package/build/services/memflow/workflow/emit.js +29 -0
- package/build/services/memflow/workflow/enrich.d.ts +9 -0
- package/build/services/memflow/workflow/enrich.js +17 -0
- package/build/services/memflow/workflow/execChild.d.ts +18 -0
- package/build/services/memflow/workflow/execChild.js +102 -0
- package/build/services/memflow/workflow/execHook.d.ts +65 -0
- package/build/services/memflow/workflow/execHook.js +73 -0
- package/build/services/memflow/workflow/hook.d.ts +9 -0
- package/build/services/memflow/workflow/hook.js +56 -0
- package/build/services/memflow/workflow/index.d.ts +74 -0
- package/build/services/memflow/workflow/index.js +87 -0
- package/build/services/memflow/workflow/interrupt.d.ts +9 -0
- package/build/services/memflow/workflow/interrupt.js +24 -0
- package/build/services/memflow/workflow/isSideEffectAllowed.d.ts +10 -0
- package/build/services/memflow/workflow/isSideEffectAllowed.js +33 -0
- package/build/services/memflow/workflow/proxyActivities.d.ts +20 -0
- package/build/services/memflow/workflow/proxyActivities.js +97 -0
- package/build/services/memflow/workflow/random.d.ts +6 -0
- package/build/services/memflow/workflow/random.js +16 -0
- package/build/services/memflow/workflow/searchMethods.d.ts +6 -0
- package/build/services/memflow/workflow/searchMethods.js +25 -0
- package/build/services/memflow/workflow/signal.d.ts +7 -0
- package/build/services/memflow/workflow/signal.js +28 -0
- package/build/services/memflow/workflow/sleepFor.d.ts +8 -0
- package/build/services/memflow/workflow/sleepFor.js +35 -0
- package/build/services/memflow/workflow/trace.d.ts +14 -0
- package/build/services/memflow/workflow/trace.js +33 -0
- package/build/services/memflow/workflow/waitFor.d.ts +8 -0
- package/build/services/memflow/workflow/waitFor.js +35 -0
- package/build/services/meshcall/index.d.ts +194 -0
- package/build/services/meshcall/index.js +452 -0
- package/build/services/meshcall/schemas/factory.d.ts +9 -0
- package/build/services/meshcall/schemas/factory.js +189 -0
- package/build/services/meshdata/index.d.ts +795 -0
- package/build/services/meshdata/index.js +1235 -0
- package/build/services/meshos/index.d.ts +293 -0
- package/build/services/meshos/index.js +547 -0
- package/build/services/pipe/functions/array.d.ts +17 -0
- package/build/services/pipe/functions/array.js +74 -0
- package/build/services/pipe/functions/bitwise.d.ts +9 -0
- package/build/services/pipe/functions/bitwise.js +24 -0
- package/build/services/pipe/functions/conditional.d.ts +13 -0
- package/build/services/pipe/functions/conditional.js +36 -0
- package/build/services/pipe/functions/cron.d.ts +12 -0
- package/build/services/pipe/functions/cron.js +40 -0
- package/build/services/pipe/functions/date.d.ts +58 -0
- package/build/services/pipe/functions/date.js +171 -0
- package/build/services/pipe/functions/index.d.ts +29 -0
- package/build/services/pipe/functions/index.js +30 -0
- package/build/services/pipe/functions/json.d.ts +5 -0
- package/build/services/pipe/functions/json.js +12 -0
- package/build/services/pipe/functions/logical.d.ts +5 -0
- package/build/services/pipe/functions/logical.js +12 -0
- package/build/services/pipe/functions/math.d.ts +42 -0
- package/build/services/pipe/functions/math.js +184 -0
- package/build/services/pipe/functions/number.d.ts +21 -0
- package/build/services/pipe/functions/number.js +60 -0
- package/build/services/pipe/functions/object.d.ts +25 -0
- package/build/services/pipe/functions/object.js +81 -0
- package/build/services/pipe/functions/string.d.ts +23 -0
- package/build/services/pipe/functions/string.js +69 -0
- package/build/services/pipe/functions/symbol.d.ts +12 -0
- package/build/services/pipe/functions/symbol.js +33 -0
- package/build/services/pipe/functions/unary.d.ts +7 -0
- package/build/services/pipe/functions/unary.js +18 -0
- package/build/services/pipe/index.d.ts +48 -0
- package/build/services/pipe/index.js +242 -0
- package/build/services/quorum/index.d.ts +90 -0
- package/build/services/quorum/index.js +263 -0
- package/build/services/reporter/index.d.ts +50 -0
- package/build/services/reporter/index.js +348 -0
- package/build/services/router/config/index.d.ts +11 -0
- package/build/services/router/config/index.js +36 -0
- package/build/services/router/consumption/index.d.ts +34 -0
- package/build/services/router/consumption/index.js +395 -0
- package/build/services/router/error-handling/index.d.ts +8 -0
- package/build/services/router/error-handling/index.js +98 -0
- package/build/services/router/index.d.ts +57 -0
- package/build/services/router/index.js +121 -0
- package/build/services/router/lifecycle/index.d.ts +27 -0
- package/build/services/router/lifecycle/index.js +80 -0
- package/build/services/router/telemetry/index.d.ts +11 -0
- package/build/services/router/telemetry/index.js +32 -0
- package/build/services/router/throttling/index.d.ts +23 -0
- package/build/services/router/throttling/index.js +76 -0
- package/build/services/search/factory.d.ts +7 -0
- package/build/services/search/factory.js +24 -0
- package/build/services/search/index.d.ts +23 -0
- package/build/services/search/index.js +10 -0
- package/build/services/search/providers/postgres/postgres.d.ts +25 -0
- package/build/services/search/providers/postgres/postgres.js +149 -0
- package/build/services/search/providers/redis/ioredis.d.ts +19 -0
- package/build/services/search/providers/redis/ioredis.js +121 -0
- package/build/services/search/providers/redis/redis.d.ts +19 -0
- package/build/services/search/providers/redis/redis.js +134 -0
- package/build/services/serializer/index.d.ts +42 -0
- package/build/services/serializer/index.js +282 -0
- package/build/services/store/cache.d.ts +67 -0
- package/build/services/store/cache.js +128 -0
- package/build/services/store/factory.d.ts +8 -0
- package/build/services/store/factory.js +24 -0
- package/build/services/store/index.d.ts +89 -0
- package/build/services/store/index.js +9 -0
- package/build/services/store/providers/postgres/kvsql.d.ts +168 -0
- package/build/services/store/providers/postgres/kvsql.js +198 -0
- package/build/services/store/providers/postgres/kvtables.d.ts +20 -0
- package/build/services/store/providers/postgres/kvtables.js +441 -0
- package/build/services/store/providers/postgres/kvtransaction.d.ts +36 -0
- package/build/services/store/providers/postgres/kvtransaction.js +248 -0
- package/build/services/store/providers/postgres/kvtypes/hash.d.ts +60 -0
- package/build/services/store/providers/postgres/kvtypes/hash.js +1287 -0
- package/build/services/store/providers/postgres/kvtypes/list.d.ts +33 -0
- package/build/services/store/providers/postgres/kvtypes/list.js +194 -0
- package/build/services/store/providers/postgres/kvtypes/string.d.ts +20 -0
- package/build/services/store/providers/postgres/kvtypes/string.js +115 -0
- package/build/services/store/providers/postgres/kvtypes/zset.d.ts +41 -0
- package/build/services/store/providers/postgres/kvtypes/zset.js +214 -0
- package/build/services/store/providers/postgres/postgres.d.ts +145 -0
- package/build/services/store/providers/postgres/postgres.js +1036 -0
- package/build/services/store/providers/redis/_base.d.ts +137 -0
- package/build/services/store/providers/redis/_base.js +980 -0
- package/build/services/store/providers/redis/ioredis.d.ts +20 -0
- package/build/services/store/providers/redis/ioredis.js +180 -0
- package/build/services/store/providers/redis/redis.d.ts +18 -0
- package/build/services/store/providers/redis/redis.js +199 -0
- package/build/services/store/providers/store-initializable.d.ts +5 -0
- package/build/services/store/providers/store-initializable.js +2 -0
- package/build/services/stream/factory.d.ts +8 -0
- package/build/services/stream/factory.js +37 -0
- package/build/services/stream/index.d.ts +69 -0
- package/build/services/stream/index.js +11 -0
- package/build/services/stream/providers/nats/nats.d.ts +60 -0
- package/build/services/stream/providers/nats/nats.js +225 -0
- package/build/services/stream/providers/postgres/kvtables.d.ts +3 -0
- package/build/services/stream/providers/postgres/kvtables.js +146 -0
- package/build/services/stream/providers/postgres/postgres.d.ts +107 -0
- package/build/services/stream/providers/postgres/postgres.js +519 -0
- package/build/services/stream/providers/redis/ioredis.d.ts +61 -0
- package/build/services/stream/providers/redis/ioredis.js +272 -0
- package/build/services/stream/providers/redis/redis.d.ts +61 -0
- package/build/services/stream/providers/redis/redis.js +305 -0
- package/build/services/stream/providers/stream-initializable.d.ts +4 -0
- package/build/services/stream/providers/stream-initializable.js +2 -0
- package/build/services/sub/factory.d.ts +7 -0
- package/build/services/sub/factory.js +29 -0
- package/build/services/sub/index.d.ts +22 -0
- package/build/services/sub/index.js +10 -0
- package/build/services/sub/providers/nats/nats.d.ts +19 -0
- package/build/services/sub/providers/nats/nats.js +105 -0
- package/build/services/sub/providers/postgres/postgres.d.ts +19 -0
- package/build/services/sub/providers/postgres/postgres.js +92 -0
- package/build/services/sub/providers/redis/ioredis.d.ts +17 -0
- package/build/services/sub/providers/redis/ioredis.js +81 -0
- package/build/services/sub/providers/redis/redis.d.ts +17 -0
- package/build/services/sub/providers/redis/redis.js +72 -0
- package/build/services/task/index.d.ts +36 -0
- package/build/services/task/index.js +206 -0
- package/build/services/telemetry/index.d.ts +52 -0
- package/build/services/telemetry/index.js +306 -0
- package/build/services/worker/index.d.ts +77 -0
- package/build/services/worker/index.js +197 -0
- package/package.json +1 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
- package/typedoc.json +0 -47
- package/types/activity.ts +0 -268
- package/types/app.ts +0 -20
- package/types/async.ts +0 -6
- package/types/cache.ts +0 -1
- package/types/collator.ts +0 -9
- package/types/error.ts +0 -56
- package/types/exporter.ts +0 -102
- package/types/hook.ts +0 -44
- package/types/hotmesh.ts +0 -314
- package/types/index.ts +0 -306
- package/types/job.ts +0 -233
- package/types/logger.ts +0 -8
- package/types/manifest.ts +0 -70
- package/types/map.ts +0 -5
- package/types/memflow.ts +0 -645
- package/types/meshcall.ts +0 -235
- package/types/meshdata.ts +0 -278
- package/types/ms.d.ts +0 -7
- package/types/nats.ts +0 -270
- package/types/pipe.ts +0 -90
- package/types/postgres.ts +0 -114
- package/types/provider.ts +0 -161
- package/types/quorum.ts +0 -167
- package/types/redis.ts +0 -404
- package/types/serializer.ts +0 -40
- package/types/stats.ts +0 -117
- package/types/stream.ts +0 -231
- package/types/task.ts +0 -7
- package/types/telemetry.ts +0 -16
- package/types/transition.ts +0 -20
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KVTables = void 0;
|
|
4
|
+
const enums_1 = require("../../../../modules/enums");
|
|
5
|
+
const utils_1 = require("../../../../modules/utils");
|
|
6
|
+
const KVTables = (context) => ({
|
|
7
|
+
/**
|
|
8
|
+
* Deploys the necessary tables with the specified naming strategy.
|
|
9
|
+
* @param appName - The name of the application.
|
|
10
|
+
*/
|
|
11
|
+
async deploy(appName) {
|
|
12
|
+
const transactionClient = context.pgClient;
|
|
13
|
+
let client;
|
|
14
|
+
let releaseClient = false;
|
|
15
|
+
if (transactionClient?.totalCount !== undefined &&
|
|
16
|
+
transactionClient?.idleCount !== undefined) {
|
|
17
|
+
// It's a Pool, need to acquire a client
|
|
18
|
+
client = await transactionClient.connect();
|
|
19
|
+
releaseClient = true;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
// Assume it's a connected Client
|
|
23
|
+
client = transactionClient;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
// Acquire advisory lock
|
|
27
|
+
const lockId = this.getAdvisoryLockId(appName);
|
|
28
|
+
const lockResult = await client.query('SELECT pg_try_advisory_lock($1) AS locked', [lockId]);
|
|
29
|
+
if (lockResult.rows[0].locked) {
|
|
30
|
+
// Begin transaction
|
|
31
|
+
await client.query('BEGIN');
|
|
32
|
+
// Check and create tables
|
|
33
|
+
const tablesExist = await this.checkIfTablesExist(client, appName);
|
|
34
|
+
if (!tablesExist) {
|
|
35
|
+
await this.createTables(client, appName);
|
|
36
|
+
}
|
|
37
|
+
// Commit transaction
|
|
38
|
+
await client.query('COMMIT');
|
|
39
|
+
// Release the lock
|
|
40
|
+
await client.query('SELECT pg_advisory_unlock($1)', [lockId]);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Release the client before waiting
|
|
44
|
+
if (releaseClient && client.release) {
|
|
45
|
+
await client.release();
|
|
46
|
+
releaseClient = false;
|
|
47
|
+
}
|
|
48
|
+
// Wait for the deploy process to complete
|
|
49
|
+
await this.waitForTablesCreation(lockId, appName);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error(error);
|
|
54
|
+
context.logger.error('Error deploying tables', { error });
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
if (releaseClient && client.release) {
|
|
59
|
+
await client.release();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
getAdvisoryLockId(appName) {
|
|
64
|
+
return this.hashStringToInt(appName);
|
|
65
|
+
},
|
|
66
|
+
hashStringToInt(str) {
|
|
67
|
+
let hash = 0;
|
|
68
|
+
for (let i = 0; i < str.length; i++) {
|
|
69
|
+
hash = (hash << 5) - hash + str.charCodeAt(i);
|
|
70
|
+
hash |= 0; // Convert to 32-bit integer
|
|
71
|
+
}
|
|
72
|
+
return Math.abs(hash);
|
|
73
|
+
},
|
|
74
|
+
async waitForTablesCreation(lockId, appName) {
|
|
75
|
+
let retries = 0;
|
|
76
|
+
const maxRetries = Math.round(enums_1.HMSH_DEPLOYMENT_DELAY / enums_1.HMSH_DEPLOYMENT_PAUSE);
|
|
77
|
+
while (retries < maxRetries) {
|
|
78
|
+
await (0, utils_1.sleepFor)(enums_1.HMSH_DEPLOYMENT_PAUSE);
|
|
79
|
+
let client;
|
|
80
|
+
let releaseClient = false;
|
|
81
|
+
const transactionClient = context.pgClient;
|
|
82
|
+
if (transactionClient?.totalCount !== undefined &&
|
|
83
|
+
transactionClient?.idleCount !== undefined) {
|
|
84
|
+
// It's a Pool, need to acquire a client
|
|
85
|
+
client = await transactionClient.connect();
|
|
86
|
+
releaseClient = true;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// Assume it's a connected Client
|
|
90
|
+
client = transactionClient;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const lockCheck = await client.query("SELECT NOT EXISTS (SELECT 1 FROM pg_locks WHERE locktype = 'advisory' AND objid = $1::bigint) AS unlocked", [lockId]);
|
|
94
|
+
if (lockCheck.rows[0].unlocked) {
|
|
95
|
+
// Lock has been released, tables should exist now
|
|
96
|
+
const tablesExist = await this.checkIfTablesExist(client, appName);
|
|
97
|
+
if (tablesExist) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
if (releaseClient && client.release) {
|
|
104
|
+
await client.release();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
retries++;
|
|
108
|
+
}
|
|
109
|
+
console.error('table-create-timeout', { appName });
|
|
110
|
+
throw new Error('Timeout waiting for table creation');
|
|
111
|
+
},
|
|
112
|
+
async checkIfTablesExist(client, appName) {
|
|
113
|
+
const tableNames = this.getTableNames(appName);
|
|
114
|
+
const checkTablePromises = tableNames.map((tableName) => client.query(`SELECT to_regclass('${tableName}') AS table`));
|
|
115
|
+
const results = await Promise.all(checkTablePromises);
|
|
116
|
+
return results.every((res) => res.rows[0].table !== null);
|
|
117
|
+
},
|
|
118
|
+
async createTables(client, appName) {
|
|
119
|
+
try {
|
|
120
|
+
await client.query('BEGIN');
|
|
121
|
+
const schemaName = context.storeClient.safeName(appName);
|
|
122
|
+
await client.query(`CREATE SCHEMA IF NOT EXISTS ${schemaName};`);
|
|
123
|
+
const tableDefinitions = this.getTableDefinitions(appName);
|
|
124
|
+
for (const tableDef of tableDefinitions) {
|
|
125
|
+
const fullTableName = `${tableDef.schema}.${tableDef.name}`;
|
|
126
|
+
switch (tableDef.type) {
|
|
127
|
+
case 'string':
|
|
128
|
+
await client.query(`
|
|
129
|
+
CREATE TABLE IF NOT EXISTS ${fullTableName} (
|
|
130
|
+
key TEXT PRIMARY KEY,
|
|
131
|
+
value TEXT,
|
|
132
|
+
expiry TIMESTAMP WITH TIME ZONE
|
|
133
|
+
);
|
|
134
|
+
`);
|
|
135
|
+
break;
|
|
136
|
+
case 'hash':
|
|
137
|
+
await client.query(`
|
|
138
|
+
CREATE TABLE IF NOT EXISTS ${fullTableName} (
|
|
139
|
+
key TEXT NOT NULL,
|
|
140
|
+
field TEXT NOT NULL,
|
|
141
|
+
value TEXT,
|
|
142
|
+
expiry TIMESTAMP WITH TIME ZONE,
|
|
143
|
+
PRIMARY KEY (key, field)
|
|
144
|
+
);
|
|
145
|
+
`);
|
|
146
|
+
break;
|
|
147
|
+
case 'jobhash':
|
|
148
|
+
// Create the enum type in the schema
|
|
149
|
+
await client.query(`
|
|
150
|
+
DO $$
|
|
151
|
+
BEGIN
|
|
152
|
+
IF NOT EXISTS (
|
|
153
|
+
SELECT 1 FROM pg_type t
|
|
154
|
+
JOIN pg_namespace n ON n.oid = t.typnamespace
|
|
155
|
+
WHERE t.typname = 'type_enum' AND n.nspname = '${schemaName}'
|
|
156
|
+
) THEN
|
|
157
|
+
CREATE TYPE ${schemaName}.type_enum AS ENUM ('jmark', 'hmark', 'status', 'jdata', 'adata', 'udata', 'other');
|
|
158
|
+
END IF;
|
|
159
|
+
END$$;
|
|
160
|
+
`);
|
|
161
|
+
// Create the main jobs table with partitioning on id
|
|
162
|
+
await client.query(`
|
|
163
|
+
CREATE TABLE IF NOT EXISTS ${fullTableName} (
|
|
164
|
+
id UUID DEFAULT gen_random_uuid(),
|
|
165
|
+
key TEXT NOT NULL,
|
|
166
|
+
entity TEXT,
|
|
167
|
+
status INTEGER NOT NULL,
|
|
168
|
+
context JSONB DEFAULT '{}',
|
|
169
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
170
|
+
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
171
|
+
expired_at TIMESTAMP WITH TIME ZONE,
|
|
172
|
+
is_live BOOLEAN DEFAULT TRUE,
|
|
173
|
+
PRIMARY KEY (id)
|
|
174
|
+
) PARTITION BY HASH (id);
|
|
175
|
+
`);
|
|
176
|
+
// Create GIN index for full JSONB search
|
|
177
|
+
await client.query(`
|
|
178
|
+
CREATE INDEX IF NOT EXISTS idx_${tableDef.name}_context_gin
|
|
179
|
+
ON ${fullTableName} USING GIN (context);
|
|
180
|
+
`);
|
|
181
|
+
// Create partitions using a DO block
|
|
182
|
+
await client.query(`
|
|
183
|
+
DO $$
|
|
184
|
+
BEGIN
|
|
185
|
+
FOR i IN 0..7 LOOP
|
|
186
|
+
EXECUTE format(
|
|
187
|
+
'CREATE TABLE IF NOT EXISTS ${fullTableName}_part_%s PARTITION OF ${fullTableName}
|
|
188
|
+
FOR VALUES WITH (modulus 8, remainder %s)',
|
|
189
|
+
i, i
|
|
190
|
+
);
|
|
191
|
+
END LOOP;
|
|
192
|
+
END$$;
|
|
193
|
+
`);
|
|
194
|
+
// Create optimized indexes
|
|
195
|
+
await client.query(`
|
|
196
|
+
CREATE INDEX IF NOT EXISTS idx_${tableDef.name}_key_expired_at
|
|
197
|
+
ON ${fullTableName} (key, expired_at) INCLUDE (is_live);
|
|
198
|
+
`);
|
|
199
|
+
await client.query(`
|
|
200
|
+
CREATE INDEX IF NOT EXISTS idx_${tableDef.name}_entity_status
|
|
201
|
+
ON ${fullTableName} (entity, status);
|
|
202
|
+
`);
|
|
203
|
+
await client.query(`
|
|
204
|
+
CREATE INDEX IF NOT EXISTS idx_${tableDef.name}_expired_at
|
|
205
|
+
ON ${fullTableName} (expired_at);
|
|
206
|
+
`);
|
|
207
|
+
// Create function to update is_live flag in the schema
|
|
208
|
+
await client.query(`
|
|
209
|
+
CREATE OR REPLACE FUNCTION ${schemaName}.update_is_live()
|
|
210
|
+
RETURNS TRIGGER AS $$
|
|
211
|
+
BEGIN
|
|
212
|
+
NEW.is_live := NEW.expired_at IS NULL OR NEW.expired_at > NOW();
|
|
213
|
+
RETURN NEW;
|
|
214
|
+
END;
|
|
215
|
+
$$ LANGUAGE plpgsql;
|
|
216
|
+
`);
|
|
217
|
+
// Create trigger for is_live updates
|
|
218
|
+
await client.query(`
|
|
219
|
+
CREATE TRIGGER trg_update_is_live
|
|
220
|
+
BEFORE INSERT OR UPDATE ON ${fullTableName}
|
|
221
|
+
FOR EACH ROW EXECUTE PROCEDURE ${schemaName}.update_is_live();
|
|
222
|
+
`);
|
|
223
|
+
// Create function to enforce uniqueness of live jobs
|
|
224
|
+
await client.query(`
|
|
225
|
+
CREATE OR REPLACE FUNCTION ${schemaName}.enforce_live_job_uniqueness()
|
|
226
|
+
RETURNS TRIGGER AS $$
|
|
227
|
+
BEGIN
|
|
228
|
+
IF (NEW.expired_at IS NULL OR NEW.expired_at > NOW()) THEN
|
|
229
|
+
PERFORM pg_advisory_xact_lock(hashtextextended(NEW.key, 0));
|
|
230
|
+
IF EXISTS (
|
|
231
|
+
SELECT 1 FROM ${fullTableName}
|
|
232
|
+
WHERE key = NEW.key
|
|
233
|
+
AND (expired_at IS NULL OR expired_at > NOW())
|
|
234
|
+
AND id <> NEW.id
|
|
235
|
+
) THEN
|
|
236
|
+
RAISE EXCEPTION 'A live job with key % already exists.', NEW.key;
|
|
237
|
+
END IF;
|
|
238
|
+
END IF;
|
|
239
|
+
RETURN NEW;
|
|
240
|
+
END;
|
|
241
|
+
$$ LANGUAGE plpgsql;
|
|
242
|
+
`);
|
|
243
|
+
// Create trigger for uniqueness enforcement
|
|
244
|
+
await client.query(`
|
|
245
|
+
CREATE TRIGGER trg_enforce_live_job_uniqueness
|
|
246
|
+
BEFORE INSERT OR UPDATE ON ${fullTableName}
|
|
247
|
+
FOR EACH ROW EXECUTE PROCEDURE ${schemaName}.enforce_live_job_uniqueness();
|
|
248
|
+
`);
|
|
249
|
+
// Create the attributes table with partitioning
|
|
250
|
+
const attributesTableName = `${fullTableName}_attributes`;
|
|
251
|
+
await client.query(`
|
|
252
|
+
CREATE TABLE IF NOT EXISTS ${attributesTableName} (
|
|
253
|
+
job_id UUID NOT NULL,
|
|
254
|
+
field TEXT NOT NULL,
|
|
255
|
+
value TEXT,
|
|
256
|
+
type ${schemaName}.type_enum NOT NULL,
|
|
257
|
+
PRIMARY KEY (job_id, field),
|
|
258
|
+
FOREIGN KEY (job_id) REFERENCES ${fullTableName} (id) ON DELETE CASCADE
|
|
259
|
+
) PARTITION BY HASH (job_id);
|
|
260
|
+
`);
|
|
261
|
+
// Create partitions for attributes table
|
|
262
|
+
await client.query(`
|
|
263
|
+
DO $$
|
|
264
|
+
BEGIN
|
|
265
|
+
FOR i IN 0..7 LOOP
|
|
266
|
+
EXECUTE format(
|
|
267
|
+
'CREATE TABLE IF NOT EXISTS ${attributesTableName}_part_%s PARTITION OF ${attributesTableName}
|
|
268
|
+
FOR VALUES WITH (modulus 8, remainder %s)',
|
|
269
|
+
i, i
|
|
270
|
+
);
|
|
271
|
+
END LOOP;
|
|
272
|
+
END$$;
|
|
273
|
+
`);
|
|
274
|
+
// Create indexes for attributes table
|
|
275
|
+
await client.query(`
|
|
276
|
+
CREATE INDEX IF NOT EXISTS idx_${tableDef.name}_attributes_type_field
|
|
277
|
+
ON ${attributesTableName} (type, field);
|
|
278
|
+
`);
|
|
279
|
+
await client.query(`
|
|
280
|
+
CREATE INDEX IF NOT EXISTS idx_${tableDef.name}_attributes_field
|
|
281
|
+
ON ${attributesTableName} (field);
|
|
282
|
+
`);
|
|
283
|
+
break;
|
|
284
|
+
case 'list':
|
|
285
|
+
await client.query(`
|
|
286
|
+
CREATE TABLE IF NOT EXISTS ${fullTableName} (
|
|
287
|
+
key TEXT NOT NULL,
|
|
288
|
+
index BIGINT NOT NULL,
|
|
289
|
+
value TEXT,
|
|
290
|
+
expiry TIMESTAMP WITH TIME ZONE,
|
|
291
|
+
PRIMARY KEY (key, index)
|
|
292
|
+
);
|
|
293
|
+
`);
|
|
294
|
+
await client.query(`
|
|
295
|
+
CREATE INDEX IF NOT EXISTS idx_${tableDef.name}_key_expiry
|
|
296
|
+
ON ${fullTableName} (key, expiry);
|
|
297
|
+
`);
|
|
298
|
+
break;
|
|
299
|
+
case 'sorted_set':
|
|
300
|
+
await client.query(`
|
|
301
|
+
CREATE TABLE IF NOT EXISTS ${fullTableName} (
|
|
302
|
+
key TEXT NOT NULL,
|
|
303
|
+
member TEXT NOT NULL,
|
|
304
|
+
score DOUBLE PRECISION NOT NULL,
|
|
305
|
+
expiry TIMESTAMP WITH TIME ZONE,
|
|
306
|
+
PRIMARY KEY (key, member)
|
|
307
|
+
);
|
|
308
|
+
`);
|
|
309
|
+
await client.query(`
|
|
310
|
+
CREATE INDEX IF NOT EXISTS idx_${tableDef.name}_key_score_member
|
|
311
|
+
ON ${fullTableName} (key, score, member);
|
|
312
|
+
`);
|
|
313
|
+
break;
|
|
314
|
+
default:
|
|
315
|
+
context.logger.warn(`Unknown table type for ${tableDef.name}`);
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// Commit transaction
|
|
320
|
+
await client.query('COMMIT');
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
context.logger.error('postgres-create-tables-error', { error });
|
|
324
|
+
await client.query('ROLLBACK');
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
getTableNames(appName) {
|
|
329
|
+
const tableNames = [];
|
|
330
|
+
// Applications table (only hotmesh prefix)
|
|
331
|
+
tableNames.push('hotmesh_applications', 'hotmesh_connections');
|
|
332
|
+
// Other tables with appName
|
|
333
|
+
const tablesWithAppName = [
|
|
334
|
+
'throttles',
|
|
335
|
+
'roles',
|
|
336
|
+
'task_priorities',
|
|
337
|
+
'task_schedules',
|
|
338
|
+
'task_lists',
|
|
339
|
+
'events',
|
|
340
|
+
'jobs',
|
|
341
|
+
'stats_counted',
|
|
342
|
+
'stats_indexed',
|
|
343
|
+
'stats_ordered',
|
|
344
|
+
'versions',
|
|
345
|
+
'signal_patterns',
|
|
346
|
+
'signal_registry',
|
|
347
|
+
'symbols',
|
|
348
|
+
];
|
|
349
|
+
tablesWithAppName.forEach((table) => {
|
|
350
|
+
tableNames.push(`${context.storeClient.safeName(appName)}.${table}`);
|
|
351
|
+
});
|
|
352
|
+
return tableNames;
|
|
353
|
+
},
|
|
354
|
+
getTableDefinitions(appName) {
|
|
355
|
+
const schemaName = context.storeClient.safeName(appName);
|
|
356
|
+
const tableDefinitions = [
|
|
357
|
+
{
|
|
358
|
+
schema: 'public',
|
|
359
|
+
name: 'hotmesh_applications',
|
|
360
|
+
type: 'hash',
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
schema: 'public',
|
|
364
|
+
name: 'hotmesh_connections',
|
|
365
|
+
type: 'hash',
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
schema: schemaName,
|
|
369
|
+
name: 'throttles',
|
|
370
|
+
type: 'hash',
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
schema: schemaName,
|
|
374
|
+
name: 'roles',
|
|
375
|
+
type: 'string',
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
schema: schemaName,
|
|
379
|
+
name: 'task_schedules',
|
|
380
|
+
type: 'sorted_set',
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
schema: schemaName,
|
|
384
|
+
name: 'task_priorities',
|
|
385
|
+
type: 'sorted_set',
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
schema: schemaName,
|
|
389
|
+
name: 'task_lists',
|
|
390
|
+
type: 'list',
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
schema: schemaName,
|
|
394
|
+
name: 'events',
|
|
395
|
+
type: 'hash',
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
schema: schemaName,
|
|
399
|
+
name: 'jobs',
|
|
400
|
+
type: 'jobhash', // Adds partitioning, indexes, and enum type
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
schema: schemaName,
|
|
404
|
+
name: 'stats_counted',
|
|
405
|
+
type: 'hash',
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
schema: schemaName,
|
|
409
|
+
name: 'stats_ordered',
|
|
410
|
+
type: 'sorted_set',
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
schema: schemaName,
|
|
414
|
+
name: 'stats_indexed',
|
|
415
|
+
type: 'list',
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
schema: schemaName,
|
|
419
|
+
name: 'versions',
|
|
420
|
+
type: 'hash',
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
schema: schemaName,
|
|
424
|
+
name: 'signal_patterns',
|
|
425
|
+
type: 'hash',
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
schema: schemaName,
|
|
429
|
+
name: 'symbols',
|
|
430
|
+
type: 'hash',
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
schema: schemaName,
|
|
434
|
+
name: 'signal_registry',
|
|
435
|
+
type: 'string',
|
|
436
|
+
},
|
|
437
|
+
];
|
|
438
|
+
return tableDefinitions;
|
|
439
|
+
},
|
|
440
|
+
});
|
|
441
|
+
exports.KVTables = KVTables;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { HSetOptions, KVSQLProviderTransaction, SetOptions, ZAddOptions } from '../../../../types/provider';
|
|
2
|
+
import type { KVSQL } from './kvsql';
|
|
3
|
+
export declare class KVTransaction implements KVSQLProviderTransaction {
|
|
4
|
+
private kvsql;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
private commands;
|
|
7
|
+
constructor(kvsql: KVSQL);
|
|
8
|
+
addCommand(sql: string, params: any[], returnType: string, transform?: (rows: any[]) => any): this;
|
|
9
|
+
set(key: string, value: string, options?: SetOptions): this;
|
|
10
|
+
setnx(key: string, value: string): this;
|
|
11
|
+
setnxex(key: string, value: string, expireSeconds: number): this;
|
|
12
|
+
get(key: string): this;
|
|
13
|
+
del(key: string): this;
|
|
14
|
+
expire(key: string, seconds: number): this;
|
|
15
|
+
hset(key: string, fields: Record<string, string>, options?: HSetOptions): this;
|
|
16
|
+
hget(key: string, field: string): this;
|
|
17
|
+
hdel(key: string, fields: string[]): this;
|
|
18
|
+
hmget(key: string, fields: string[]): this;
|
|
19
|
+
hgetall(key: string): this;
|
|
20
|
+
hincrbyfloat(key: string, field: string, increment: number): this;
|
|
21
|
+
hscan(key: string, cursor: string, count?: number): this;
|
|
22
|
+
lrange(key: string, start: number, end: number): this;
|
|
23
|
+
rpush(key: string, value: string | string[]): this;
|
|
24
|
+
lpush(key: string, value: string | string[]): this;
|
|
25
|
+
lpop(key: string): this;
|
|
26
|
+
lmove(source: string, destination: string, srcPosition: 'LEFT' | 'RIGHT', destPosition: 'LEFT' | 'RIGHT'): this;
|
|
27
|
+
zadd(key: string, score: number, member: string, options?: ZAddOptions): this;
|
|
28
|
+
zrange(key: string, start: number, stop: number): this;
|
|
29
|
+
zrangebyscore(key: string, min: number, max: number): this;
|
|
30
|
+
zrangebyscore_withscores(key: string, min: number, max: number): this;
|
|
31
|
+
zrem(key: string, member: string): this;
|
|
32
|
+
zrank(key: string, member: string): this;
|
|
33
|
+
scan(cursor: number, count?: number): this;
|
|
34
|
+
rename(oldKey: string, newKey: string): this;
|
|
35
|
+
exec(): Promise<any[]>;
|
|
36
|
+
}
|