prostgles-server 4.2.157 → 4.2.159

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.
Files changed (159) hide show
  1. package/dist/Auth/AuthHandler.js +2 -2
  2. package/dist/Auth/AuthHandler.js.map +1 -1
  3. package/dist/Auth/AuthTypes.d.ts +4 -8
  4. package/dist/Auth/AuthTypes.d.ts.map +1 -1
  5. package/dist/Auth/setAuthProviders.d.ts +1 -1
  6. package/dist/Auth/setAuthProviders.d.ts.map +1 -1
  7. package/dist/Auth/setAuthProviders.js +6 -7
  8. package/dist/Auth/setAuthProviders.js.map +1 -1
  9. package/dist/Auth/setEmailProvider.d.ts +1 -1
  10. package/dist/Auth/setEmailProvider.d.ts.map +1 -1
  11. package/dist/Auth/setEmailProvider.js +22 -2
  12. package/dist/Auth/setEmailProvider.js.map +1 -1
  13. package/dist/Auth/setupAuthRoutes.js +1 -1
  14. package/dist/Auth/setupAuthRoutes.js.map +1 -1
  15. package/dist/Prostgles.d.ts +1 -0
  16. package/dist/Prostgles.d.ts.map +1 -1
  17. package/dist/Prostgles.js +6 -0
  18. package/dist/Prostgles.js.map +1 -1
  19. package/dist/initProstgles.d.ts.map +1 -1
  20. package/dist/initProstgles.js +2 -6
  21. package/dist/initProstgles.js.map +1 -1
  22. package/package.json +1 -1
  23. package/lib/Auth/AuthHandler.ts +0 -436
  24. package/lib/Auth/AuthTypes.ts +0 -285
  25. package/lib/Auth/getSafeReturnURL.ts +0 -35
  26. package/lib/Auth/sendEmail.ts +0 -83
  27. package/lib/Auth/setAuthProviders.ts +0 -129
  28. package/lib/Auth/setEmailProvider.ts +0 -63
  29. package/lib/Auth/setupAuthRoutes.ts +0 -161
  30. package/lib/DBEventsManager.ts +0 -178
  31. package/lib/DBSchemaBuilder.ts +0 -225
  32. package/lib/DboBuilder/DboBuilder.ts +0 -319
  33. package/lib/DboBuilder/DboBuilderTypes.ts +0 -361
  34. package/lib/DboBuilder/QueryBuilder/Functions.ts +0 -1153
  35. package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +0 -288
  36. package/lib/DboBuilder/QueryBuilder/getJoinQuery.ts +0 -263
  37. package/lib/DboBuilder/QueryBuilder/getNewQuery.ts +0 -271
  38. package/lib/DboBuilder/QueryBuilder/getSelectQuery.ts +0 -136
  39. package/lib/DboBuilder/QueryBuilder/prepareHaving.ts +0 -22
  40. package/lib/DboBuilder/QueryStreamer.ts +0 -250
  41. package/lib/DboBuilder/TableHandler/DataValidator.ts +0 -428
  42. package/lib/DboBuilder/TableHandler/TableHandler.ts +0 -205
  43. package/lib/DboBuilder/TableHandler/delete.ts +0 -115
  44. package/lib/DboBuilder/TableHandler/insert.ts +0 -183
  45. package/lib/DboBuilder/TableHandler/insertTest.ts +0 -78
  46. package/lib/DboBuilder/TableHandler/onDeleteFromFileTable.ts +0 -62
  47. package/lib/DboBuilder/TableHandler/runInsertUpdateQuery.ts +0 -134
  48. package/lib/DboBuilder/TableHandler/update.ts +0 -126
  49. package/lib/DboBuilder/TableHandler/updateBatch.ts +0 -49
  50. package/lib/DboBuilder/TableHandler/updateFile.ts +0 -48
  51. package/lib/DboBuilder/TableHandler/upsert.ts +0 -34
  52. package/lib/DboBuilder/ViewHandler/ViewHandler.ts +0 -393
  53. package/lib/DboBuilder/ViewHandler/count.ts +0 -38
  54. package/lib/DboBuilder/ViewHandler/find.ts +0 -153
  55. package/lib/DboBuilder/ViewHandler/getExistsCondition.ts +0 -73
  56. package/lib/DboBuilder/ViewHandler/getExistsFilters.ts +0 -74
  57. package/lib/DboBuilder/ViewHandler/getInfo.ts +0 -32
  58. package/lib/DboBuilder/ViewHandler/getTableJoinQuery.ts +0 -84
  59. package/lib/DboBuilder/ViewHandler/parseComplexFilter.ts +0 -96
  60. package/lib/DboBuilder/ViewHandler/parseFieldFilter.ts +0 -105
  61. package/lib/DboBuilder/ViewHandler/parseJoinPath.ts +0 -208
  62. package/lib/DboBuilder/ViewHandler/prepareSortItems.ts +0 -163
  63. package/lib/DboBuilder/ViewHandler/prepareWhere.ts +0 -90
  64. package/lib/DboBuilder/ViewHandler/size.ts +0 -37
  65. package/lib/DboBuilder/ViewHandler/subscribe.ts +0 -118
  66. package/lib/DboBuilder/ViewHandler/validateViewRules.ts +0 -70
  67. package/lib/DboBuilder/dboBuilderUtils.ts +0 -222
  68. package/lib/DboBuilder/getColumns.ts +0 -114
  69. package/lib/DboBuilder/getCondition.ts +0 -201
  70. package/lib/DboBuilder/getSubscribeRelatedTables.ts +0 -190
  71. package/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts +0 -426
  72. package/lib/DboBuilder/insertNestedRecords.ts +0 -355
  73. package/lib/DboBuilder/parseUpdateRules.ts +0 -187
  74. package/lib/DboBuilder/prepareShortestJoinPaths.ts +0 -186
  75. package/lib/DboBuilder/runSQL.ts +0 -182
  76. package/lib/DboBuilder/runTransaction.ts +0 -50
  77. package/lib/DboBuilder/sqlErrCodeToMsg.ts +0 -254
  78. package/lib/DboBuilder/uploadFile.ts +0 -69
  79. package/lib/Event_Trigger_Tags.ts +0 -118
  80. package/lib/FileManager/FileManager.ts +0 -358
  81. package/lib/FileManager/getValidatedFileType.ts +0 -69
  82. package/lib/FileManager/initFileManager.ts +0 -187
  83. package/lib/FileManager/upload.ts +0 -62
  84. package/lib/FileManager/uploadStream.ts +0 -79
  85. package/lib/Filtering.ts +0 -463
  86. package/lib/JSONBValidation/validate_jsonb_schema_sql.ts +0 -502
  87. package/lib/JSONBValidation/validation.ts +0 -143
  88. package/lib/Logging.ts +0 -127
  89. package/lib/PostgresNotifListenManager.ts +0 -143
  90. package/lib/Prostgles.ts +0 -479
  91. package/lib/ProstglesTypes.ts +0 -196
  92. package/lib/PubSubManager/PubSubManager.ts +0 -609
  93. package/lib/PubSubManager/addSub.ts +0 -138
  94. package/lib/PubSubManager/addSync.ts +0 -141
  95. package/lib/PubSubManager/getCreatePubSubManagerError.ts +0 -72
  96. package/lib/PubSubManager/getPubSubManagerInitQuery.ts +0 -662
  97. package/lib/PubSubManager/initPubSubManager.ts +0 -79
  98. package/lib/PubSubManager/notifListener.ts +0 -173
  99. package/lib/PubSubManager/orphanTriggerCheck.ts +0 -70
  100. package/lib/PubSubManager/pushSubData.ts +0 -55
  101. package/lib/PublishParser/PublishParser.ts +0 -162
  102. package/lib/PublishParser/getFileTableRules.ts +0 -124
  103. package/lib/PublishParser/getSchemaFromPublish.ts +0 -141
  104. package/lib/PublishParser/getTableRulesWithoutFileTable.ts +0 -177
  105. package/lib/PublishParser/publishTypesAndUtils.ts +0 -399
  106. package/lib/RestApi.ts +0 -127
  107. package/lib/SchemaWatch/SchemaWatch.ts +0 -90
  108. package/lib/SchemaWatch/createSchemaWatchEventTrigger.ts +0 -3
  109. package/lib/SchemaWatch/getValidatedWatchSchemaType.ts +0 -45
  110. package/lib/SchemaWatch/getWatchSchemaTagList.ts +0 -27
  111. package/lib/SyncReplication.ts +0 -557
  112. package/lib/TableConfig/TableConfig.ts +0 -468
  113. package/lib/TableConfig/getColumnDefinitionQuery.ts +0 -111
  114. package/lib/TableConfig/getConstraintDefinitionQueries.ts +0 -95
  115. package/lib/TableConfig/getFutureTableSchema.ts +0 -64
  116. package/lib/TableConfig/getPGIndexes.ts +0 -53
  117. package/lib/TableConfig/getTableColumnQueries.ts +0 -129
  118. package/lib/TableConfig/initTableConfig.ts +0 -326
  119. package/lib/index.ts +0 -13
  120. package/lib/initProstgles.ts +0 -322
  121. package/lib/onSocketConnected.ts +0 -102
  122. package/lib/runClientRequest.ts +0 -129
  123. package/lib/shortestPath.ts +0 -122
  124. package/lib/typeTests/DBoGenerated.d.ts +0 -320
  125. package/lib/typeTests/dboTypeCheck.ts +0 -81
  126. package/lib/utils.ts +0 -15
  127. package/tests/client/hooks.spec.ts +0 -205
  128. package/tests/client/index.ts +0 -139
  129. package/tests/client/package-lock.json +0 -637
  130. package/tests/client/package.json +0 -26
  131. package/tests/client/renderReactHook.ts +0 -177
  132. package/tests/client/tsconfig.json +0 -15
  133. package/tests/client/useProstgles.spec.ts +0 -120
  134. package/tests/clientFileTests.spec.ts +0 -102
  135. package/tests/clientOnlyQueries.spec.ts +0 -667
  136. package/tests/clientRestApi.spec.ts +0 -82
  137. package/tests/config_test/DBoGenerated.d.ts +0 -407
  138. package/tests/config_test/index.html +0 -109
  139. package/tests/config_test/index.js +0 -86
  140. package/tests/config_test/index.js.map +0 -1
  141. package/tests/config_test/index.ts +0 -91
  142. package/tests/config_test/init.sql +0 -48
  143. package/tests/config_test/package.json +0 -29
  144. package/tests/config_test/tsconfig.json +0 -23
  145. package/tests/config_testDBoGenerated.d.ts +0 -407
  146. package/tests/isomorphicQueries.spec.ts +0 -1493
  147. package/tests/server/DBoGenerated.d.ts +0 -537
  148. package/tests/server/index.html +0 -73
  149. package/tests/server/index.ts +0 -289
  150. package/tests/server/init.sql +0 -224
  151. package/tests/server/package-lock.json +0 -2164
  152. package/tests/server/package.json +0 -25
  153. package/tests/server/publishTypeCheck.ts +0 -136
  154. package/tests/server/server.ts +0 -35
  155. package/tests/server/testPublish.ts +0 -147
  156. package/tests/server/testTableConfig.ts +0 -156
  157. package/tests/server/tsconfig.json +0 -22
  158. package/tests/serverOnlyQueries.spec.ts +0 -32
  159. package/tests/test.sh +0 -20
@@ -1,609 +0,0 @@
1
- /*---------------------------------------------------------------------------------------------
2
- * Copyright (c) Stefan L. All rights reserved.
3
- * Licensed under the MIT License. See LICENSE in the project root for license information.
4
- *--------------------------------------------------------------------------------------------*/
5
-
6
- import * as crypto from "crypto";
7
- import { DBHandlerServer, DboBuilder, PRGLIOSocket, TableInfo, TableOrViewInfo } from "../DboBuilder/DboBuilder";
8
- import { PostgresNotifListenManager } from "../PostgresNotifListenManager";
9
- import { DB, getIsSuperUser } from "../Prostgles";
10
- import { addSync } from "./addSync";
11
- import { initPubSubManager } from "./initPubSubManager";
12
-
13
- import * as pgPromise from 'pg-promise';
14
- import pg from 'pg-promise/typescript/pg-subset';
15
-
16
- import { AnyObject, FieldFilter, SelectParams, SubscribeParams, WAL } from "prostgles-types";
17
-
18
- import { find, pickKeys, tryCatch } from "prostgles-types/dist/util";
19
- import { LocalFuncs, getOnDataFunc, matchesLocalFuncs } from "../DboBuilder/ViewHandler/subscribe";
20
- import { EVENT_TRIGGER_TAGS } from "../Event_Trigger_Tags";
21
- import { EventTypes } from "../Logging";
22
- import { TableRule } from "../PublishParser/PublishParser";
23
- import { syncData } from "../SyncReplication";
24
- import { addSub } from "./addSub";
25
- import { DB_OBJ_NAMES } from "./getPubSubManagerInitQuery";
26
- import { notifListener } from "./notifListener";
27
- import { DELETE_DISCONNECTED_APPS_QUERY } from "./orphanTriggerCheck";
28
- import { pushSubData } from "./pushSubData";
29
-
30
- type PGP = pgPromise.IMain<{}, pg.IClient>;
31
- const pgp: PGP = pgPromise({
32
- });
33
- export const asValue = (v: any) => pgp.as.format("$1", [v]);
34
- export const DEFAULT_SYNC_BATCH_SIZE = 50;
35
-
36
- export const log = (...args: any[]) => {
37
- if (process.env.TEST_TYPE) {
38
- console.log(...args)
39
- }
40
- }
41
-
42
- export type BasicCallback = (err?: any, res?: any) => void
43
-
44
- export type SyncParams = {
45
- socket_id: string;
46
- sid: string | undefined;
47
- channel_name: string;
48
- table_name: string;
49
- table_rules?: TableRule;
50
- synced_field: string;
51
- allow_delete: boolean;
52
- id_fields: string[];
53
- batch_size: number;
54
- filter: object;
55
- params: {
56
- select: FieldFilter
57
- };
58
- condition: string;
59
- wal?: WAL,
60
- throttle?: number;
61
- lr?: AnyObject;
62
- last_synced: number;
63
- is_syncing: boolean;
64
- }
65
-
66
- export type AddSyncParams = {
67
- socket: PRGLIOSocket;
68
- table_info: TableInfo;
69
- table_rules: TableRule;
70
- synced_field: string;
71
- allow_delete?: boolean;
72
- id_fields: string[];
73
- filter: object;
74
- params: {
75
- select: FieldFilter
76
- };
77
- condition: string;
78
- throttle?: number;
79
- }
80
-
81
- export type ViewSubscriptionOptions = ({
82
- type: "view";
83
- viewName: string;
84
- definition: string;
85
- } | {
86
- type: "table";
87
- viewName?: undefined;
88
- definition?: undefined;
89
- }) & {
90
- relatedTables: {
91
- tableName: string;
92
- tableNameEscaped: string;
93
- condition: string;
94
- }[];
95
- }
96
-
97
- export type SubscriptionParams = Pick<SubscribeParams, "throttle" | "throttleOpts"> & {
98
- socket_id?: string;
99
- channel_name: string;
100
-
101
- /**
102
- * If this is a view then an array with all related tables will be
103
- * */
104
- viewOptions?: ViewSubscriptionOptions;
105
- parentSubParams: Omit<SubscriptionParams, "parentSubParams"> | undefined;
106
-
107
- table_info: TableOrViewInfo;
108
-
109
- /* Used as input */
110
- table_rules?: TableRule;
111
- filter: object;
112
- params: SelectParams;
113
-
114
- localFuncs?: LocalFuncs;
115
- socket: PRGLIOSocket | undefined;
116
-
117
- last_throttled: number;
118
- is_throttling?: any;
119
- is_ready?: boolean;
120
- }
121
-
122
- export type PubSubManagerOptions = {
123
- dboBuilder: DboBuilder;
124
- wsChannelNamePrefix?: string;
125
- pgChannelName?: string;
126
- }
127
-
128
- export type Subscription = Pick<SubscriptionParams,
129
- | "throttle"
130
- | "is_throttling"
131
- | "last_throttled"
132
- | "throttleOpts"
133
- | "channel_name"
134
- | "is_ready"
135
- | "localFuncs"
136
- | "socket"
137
- | "socket_id"
138
- | "table_info"
139
- | "filter"
140
- | "params"
141
- | "table_rules"
142
- > & {
143
- triggers: {
144
- table_name: string;
145
- condition: string;
146
- is_related: boolean;
147
- }[];
148
- }
149
-
150
- /**
151
- * Used to facilitate table subscribe and sync
152
- */
153
- export class PubSubManager {
154
- static DELIMITER = '|$prstgls$|' as const;
155
-
156
- static EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID = "prostgles internal query that should be excluded from schema watch " as const;
157
-
158
- public static create = async (options: PubSubManagerOptions) => {
159
- const instance = new PubSubManager(options);
160
- const result = await initPubSubManager.bind(instance)();
161
- return result;
162
- }
163
-
164
- appInfoWasInserted = false;
165
- get appId() {
166
- return this.dboBuilder.prostgles.appId;
167
- }
168
- get db(): DB {
169
- return this.dboBuilder.db;
170
- }
171
- get dbo(): DBHandlerServer {
172
- return this.dboBuilder.dbo;
173
- }
174
-
175
- dboBuilder: DboBuilder;
176
- _triggers?: Record<string, string[]>;
177
- sockets: AnyObject = {};
178
-
179
- subs: Subscription[] = [];
180
- syncs: SyncParams[] = [];
181
- socketChannelPreffix: string;
182
- postgresNotifListenManager?: PostgresNotifListenManager;
183
-
184
- private constructor(options: PubSubManagerOptions) {
185
- const { wsChannelNamePrefix, dboBuilder } = options;
186
- if (!dboBuilder.db || !dboBuilder.dbo) {
187
- throw 'MISSING: db_pg, db';
188
- }
189
-
190
- this.dboBuilder = dboBuilder;
191
-
192
- this.socketChannelPreffix = wsChannelNamePrefix || "_psqlWS_";
193
-
194
- log("Created PubSubManager");
195
- }
196
- appCheckFrequencyMS = 10 * 1000;
197
- appCheck?: ReturnType<typeof setInterval>;
198
-
199
- destroyed = false;
200
- destroy = () => {
201
- this.destroyed = true;
202
- if (this.appCheck) {
203
- clearInterval(this.appCheck);
204
- }
205
- this.subs = [];
206
- this.syncs = [];
207
- this.postgresNotifListenManager?.destroy();
208
- }
209
-
210
- getIsDestroyed = () => {
211
- if (this.destroyed) {
212
- console.trace("Could not start destroyed instance");
213
- return false
214
- }
215
- return true
216
- }
217
-
218
- appChecking = false;
219
- checkedListenerTableCond?: string[];
220
-
221
- initialiseEventTriggers = async () => {
222
- const { watchSchema } = this.dboBuilder.prostgles.opts;
223
- if (watchSchema && !(await getIsSuperUser(this.db))) {
224
- console.warn("prostgles watchSchema requires superuser db user. Will not watch using event triggers")
225
- }
226
-
227
- try {
228
- /** We use these names because they include schema where necessary */
229
- const allTableNames = Object.keys(this.dbo).filter(k => this.dbo[k]?.tableOrViewInfo);
230
- const tableFilterQuery = allTableNames.length ? `OR table_name NOT IN (${allTableNames.map(tblName => asValue(tblName)).join(", ")})` : "";
231
- const query = pgp.as.format(`
232
- BEGIN;-- ISOLATION LEVEL SERIALIZABLE;
233
-
234
- /**
235
- * ${PubSubManager.EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID}
236
- * Drop stale triggers
237
- * */
238
- DO
239
- $do$
240
- DECLARE trg RECORD;
241
- q TEXT;
242
- ev_trg_needed BOOLEAN := FALSE;
243
- ev_trg_exists BOOLEAN := FALSE;
244
- is_super_user BOOLEAN := FALSE;
245
- BEGIN
246
-
247
- /**
248
- * Delete disconnected app records, this will delete related triggers
249
- * */
250
- ${DELETE_DISCONNECTED_APPS_QUERY};
251
-
252
- DELETE FROM prostgles.app_triggers
253
- WHERE app_id NOT IN (SELECT id FROM prostgles.apps)
254
- ${tableFilterQuery}
255
- ;
256
-
257
- /** IS THIS STILL NEEDED? Delete existing triggers without locking
258
- */
259
- LOCK TABLE prostgles.app_triggers IN ACCESS EXCLUSIVE MODE;
260
- EXECUTE format(
261
- $q$
262
-
263
- CREATE TEMP TABLE %1$I AS --ON COMMIT DROP AS
264
- SELECT * FROM prostgles.app_triggers;
265
-
266
- DELETE FROM prostgles.app_triggers;
267
-
268
- INSERT INTO prostgles.app_triggers
269
- SELECT * FROM %1$I;
270
-
271
- DROP TABLE IF EXISTS %1$I;
272
- $q$,
273
- ${asValue('triggers_' + this.appId)}
274
- );
275
-
276
- ${SCHEMA_WATCH_EVENT_TRIGGER_QUERY}
277
-
278
- END
279
- $do$;
280
-
281
-
282
- COMMIT;
283
- `, { EVENT_TRIGGER_TAGS });
284
-
285
- await this.db.tx(t => t.any(query))
286
- .catch(e => {
287
- console.error("prepareTriggers failed: ", e);
288
- throw e;
289
- });
290
-
291
- return true;
292
-
293
- } catch (e) {
294
- console.error("prepareTriggers failed: ", e);
295
- throw e;
296
- }
297
- }
298
-
299
- getClientSubs({ channel_name, localFuncs, socket_id }: Pick<Subscription, "localFuncs" | "socket_id" | "channel_name">): Subscription[] {
300
- return this.subs.filter(s => {
301
- return s.channel_name === channel_name &&
302
- (matchesLocalFuncs(localFuncs, s.localFuncs) || socket_id && s.socket_id === socket_id)
303
- });
304
- }
305
-
306
- getTriggerSubs(table_name: string, condition: string): Subscription[] {
307
- const subs = this.subs.filter(s => find(s.triggers, { table_name, condition }));
308
- return subs;
309
- }
310
-
311
- removeLocalSub(channelName: string, localFuncs: LocalFuncs) {
312
- const matchingSubIdx = this.subs.findIndex(s =>
313
- s.channel_name === channelName &&
314
- getOnDataFunc(localFuncs) === getOnDataFunc(s.localFuncs)
315
- );
316
- if (matchingSubIdx > -1) {
317
- this.subs.splice(matchingSubIdx, 1);
318
- } else {
319
- console.error("Could not unsubscribe. Subscription might not have initialised yet", { channelName })
320
- }
321
- }
322
-
323
- getSyncs(table_name: string, condition: string) {
324
- return (this.syncs || [])
325
- .filter((s: SyncParams) => s.table_name === table_name && s.condition === condition);
326
- }
327
-
328
- notifListener = notifListener.bind(this);
329
-
330
- getSubData = async (sub: Subscription): Promise<
331
- { data: any[]; err?: undefined; } |
332
- { data?: undefined; err: any; }
333
- > => {
334
- const { table_info, filter, params, table_rules } = sub; //, subOne = false
335
- const { name: table_name } = table_info;
336
-
337
- if (!this.dbo?.[table_name]?.find) {
338
- throw new Error(`this.dbo.${table_name}.find undefined`);
339
- }
340
-
341
- try {
342
- const data = await this.dbo?.[table_name]!.find!(filter, params, undefined, table_rules)
343
- return { data };
344
- } catch(err){
345
- return { err };
346
- }
347
- }
348
-
349
- pushSubData = pushSubData.bind(this);
350
-
351
- upsertSocket(socket: PRGLIOSocket | undefined) {
352
- if (socket && !this.sockets[socket.id]) {
353
- this.sockets[socket.id] = socket;
354
- socket.on("disconnect", () => {
355
-
356
- this.subs = this.subs.filter(s => {
357
- return !(s.socket && s.socket.id === socket.id);
358
- });
359
-
360
- this.syncs = this.syncs.filter(s => {
361
- return !(s.socket_id && s.socket_id === socket.id);
362
- });
363
-
364
- delete this.sockets[socket.id];
365
-
366
- this._log({
367
- type: "sync",
368
- command: "upsertSocket.disconnect",
369
- tableName: "",
370
- duration: 0,
371
- sid: this.dboBuilder.prostgles.authHandler?.getSIDNoError({ socket }),
372
- socketId: socket.id,
373
- connectedSocketIds: this.connectedSocketIds,
374
- remainingSubs: JSON.stringify(this.subs.map(s => ({ tableName: s.table_info.name, triggers: s.triggers }))),
375
- remainingSyncs: JSON.stringify(this.syncs.map(s => pickKeys(s, ["table_name", "condition"]))),
376
- });
377
-
378
- return "ok";
379
- });
380
- }
381
- }
382
-
383
- get connectedSocketIds() {
384
- return this.dboBuilder.prostgles.connectedSockets.map(s => s.id);
385
- }
386
- _log = (params: EventTypes.Sync) => {
387
- return this.dboBuilder.prostgles.opts.onLog?.({ ...params });
388
- }
389
-
390
- syncTimeout?: ReturnType<typeof setTimeout>;
391
- syncData = syncData.bind(this);
392
-
393
- addSync = addSync.bind(this);
394
-
395
- addSub = addSub.bind(this);
396
-
397
- getActiveListeners = (): { table_name: string; condition: string }[] => {
398
- const activeListeners: { table_name: string; condition: string }[] = [];
399
- const upsert = (t: string, c: string) => {
400
- if (!activeListeners.find(r => r.table_name === t && r.condition === c)) {
401
- activeListeners.push({ table_name: t, condition: c });
402
- }
403
- }
404
- (this.syncs ?? []).map(s => {
405
- upsert(s.table_name, s.condition)
406
- });
407
-
408
- this.subs.forEach(s => {
409
- s.triggers.forEach(trg => {
410
- upsert(trg.table_name, trg.condition);
411
- });
412
- });
413
-
414
- return activeListeners;
415
- }
416
-
417
- /**
418
- * Sync triggers with database
419
- * */
420
- refreshTriggers = async () => {
421
-
422
- const triggers: {
423
- table_name: string;
424
- condition: string;
425
- }[] = await this.db.any(`
426
- SELECT *
427
- FROM prostgles.v_triggers
428
- WHERE app_id = $1
429
- ORDER BY table_name, condition
430
- `, [this.dboBuilder.prostgles.appId]
431
- );
432
-
433
- this._triggers = {};
434
- triggers.map(t => {
435
- this._triggers ??= {};
436
- this._triggers[t.table_name] ??= [];
437
- if (!this._triggers[t.table_name]?.includes(t.condition)) {
438
- this._triggers[t.table_name]?.push(t.condition)
439
- }
440
- });
441
- }
442
-
443
- addingTrigger: any;
444
- addTriggerPool?: Record<string, string[]> = undefined;
445
- async addTrigger(params: { table_name: string; condition: string; }, viewOptions: ViewSubscriptionOptions | undefined, socket: PRGLIOSocket | undefined) {
446
-
447
- const addedTrigger = await tryCatch(async () => {
448
-
449
- const { table_name } = { ...params }
450
- let { condition } = { ...params }
451
- if (!table_name) throw "MISSING table_name";
452
-
453
- if (!condition || !condition.trim().length) {
454
- condition = "TRUE";
455
- }
456
-
457
- if (this.dbo[table_name]?.tableOrViewInfo?.isHyperTable) {
458
- throw "Triggers do not work on timescaledb hypertables due to bug:\nhttps://github.com/timescale/timescaledb/issues/1084"
459
- }
460
-
461
- const trgVals = {
462
- tbl: asValue(table_name),
463
- cond: asValue(condition),
464
- condHash: asValue(
465
- crypto.createHash('md5').update(condition).digest('hex')
466
- )
467
- };
468
-
469
- await this.db.tx(t => t.any(`
470
- BEGIN WORK;
471
- /* ${PubSubManager.EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID} */
472
- /* why is this lock level needed? */
473
- --LOCK TABLE prostgles.app_triggers IN ACCESS EXCLUSIVE MODE;
474
-
475
- /** app_triggers is not refreshed when tables are dropped */
476
- DELETE FROM prostgles.app_triggers at
477
- WHERE app_id = ${asValue(this.appId)}
478
- AND NOT EXISTS (
479
- SELECT 1
480
- FROM pg_catalog.pg_trigger t
481
- WHERE tgname like format('prostgles_triggers_%s_', at.table_name) || '%'
482
- AND tgenabled = 'O'
483
- );
484
-
485
- INSERT INTO prostgles.app_triggers (
486
- table_name,
487
- condition,
488
- condition_hash,
489
- app_id,
490
- related_view_name,
491
- related_view_def
492
- )
493
- VALUES (
494
- ${trgVals.tbl},
495
- ${trgVals.cond},
496
- ${trgVals.condHash},
497
- ${asValue(this.appId)},
498
- ${asValue(viewOptions?.viewName ?? null)},
499
- ${asValue(viewOptions?.definition ?? null)}
500
- )
501
- ON CONFLICT DO NOTHING;
502
-
503
- COMMIT WORK;
504
- `));
505
-
506
- /** This might be redundant due to trigger on app_triggers */
507
- await this.refreshTriggers();
508
-
509
- return trgVals;
510
- });
511
-
512
- await this._log({
513
- type: "sync",
514
- command: "addTrigger",
515
- condition: addedTrigger.cond ?? params.condition,
516
- duration: addedTrigger.duration,
517
- socketId: socket?.id,
518
- state: !addedTrigger.tbl? "fail" : "ok",
519
- error: addedTrigger.error,
520
- sid: this.dboBuilder.prostgles.authHandler?.getSIDNoError({ socket }),
521
- tableName: addedTrigger.tbl ?? params.table_name,
522
- connectedSocketIds: this.dboBuilder.prostgles.connectedSockets.map(s => s.id),
523
- localParams: { socket }
524
- });
525
-
526
- if(addedTrigger.error) throw addedTrigger.error;
527
-
528
- return addedTrigger;
529
- }
530
- }
531
-
532
- const SCHEMA_WATCH_EVENT_TRIGGER_QUERY = `
533
-
534
- is_super_user := EXISTS (select 1 from pg_user where usename = CURRENT_USER AND usesuper IS TRUE);
535
-
536
- /* DROP the old buggy schema watch trigger */
537
- IF EXISTS (
538
- SELECT 1 FROM pg_catalog.pg_event_trigger
539
- WHERE evtname = 'prostgles_schema_watch_trigger'
540
- ) AND is_super_user IS TRUE
541
- THEN
542
- DROP EVENT TRIGGER IF EXISTS prostgles_schema_watch_trigger;
543
- END IF;
544
-
545
- ev_trg_needed := EXISTS (
546
- SELECT 1 FROM prostgles.apps
547
- WHERE watching_schema_tag_names IS NOT NULL
548
- );
549
- ev_trg_exists := EXISTS (
550
- SELECT 1 FROM pg_catalog.pg_event_trigger
551
- WHERE evtname = ${asValue(DB_OBJ_NAMES.schema_watch_trigger)}
552
- );
553
-
554
- /* DROP stale event trigger */
555
- IF
556
- is_super_user IS TRUE
557
- AND ev_trg_needed IS FALSE
558
- AND ev_trg_exists IS TRUE
559
- THEN
560
-
561
- SELECT format(
562
- $$
563
- DROP EVENT TRIGGER IF EXISTS %I ;
564
- DROP EVENT TRIGGER IF EXISTS %I ;
565
- $$
566
- , ${asValue(DB_OBJ_NAMES.schema_watch_trigger)}
567
- , ${asValue(DB_OBJ_NAMES.schema_watch_trigger_drop)}
568
- )
569
- INTO q;
570
- EXECUTE q;
571
-
572
- /* CREATE event trigger */
573
- ELSIF
574
- is_super_user IS TRUE
575
- AND ev_trg_needed IS TRUE
576
- AND ev_trg_exists IS FALSE
577
- THEN
578
-
579
- DROP EVENT TRIGGER IF EXISTS ${DB_OBJ_NAMES.schema_watch_trigger};
580
- CREATE EVENT TRIGGER ${DB_OBJ_NAMES.schema_watch_trigger}
581
- ON ddl_command_end
582
- WHEN TAG IN (\${EVENT_TRIGGER_TAGS:csv})
583
- EXECUTE PROCEDURE ${DB_OBJ_NAMES.schema_watch_func}();
584
-
585
- DROP EVENT TRIGGER IF EXISTS ${DB_OBJ_NAMES.schema_watch_trigger_drop};
586
- CREATE EVENT TRIGGER ${DB_OBJ_NAMES.schema_watch_trigger_drop}
587
- ON sql_drop
588
- --WHEN TAG IN (\${EVENT_TRIGGER_TAGS:csv})
589
- EXECUTE PROCEDURE ${DB_OBJ_NAMES.schema_watch_func}();
590
-
591
- END IF;
592
- `
593
-
594
- export const NOTIF_TYPE = {
595
- data: "data_has_changed",
596
- data_trigger_change: "data_watch_triggers_have_changed",
597
- schema: "schema_has_changed"
598
- } as const;
599
- export const NOTIF_CHANNEL = {
600
- preffix: 'prostgles_' as const,
601
- getFull: (appID: string | undefined) => {
602
- if (!appID) throw "No appID";
603
- return NOTIF_CHANNEL.preffix + appID;
604
- }
605
- }
606
-
607
- export const parseCondition = (condition: string): string => condition && condition.trim().length ? condition : "TRUE"
608
-
609
- export { omitKeys, pickKeys } from "prostgles-types";