prostgles-server 4.2.293 → 4.2.295
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/DboBuilder/QueryBuilder/QueryBuilder.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.js +7 -3
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/subscribe.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/subscribe.js +1 -0
- package/dist/DboBuilder/ViewHandler/subscribe.js.map +1 -1
- package/dist/Prostgles.d.ts +1 -1
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +1 -24
- package/dist/Prostgles.js.map +1 -1
- package/dist/PubSubManager/PubSubManager.d.ts +3 -1
- package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/PubSubManager.js.map +1 -1
- package/dist/PubSubManager/addSub.d.ts.map +1 -1
- package/dist/PubSubManager/addSub.js +2 -1
- package/dist/PubSubManager/addSub.js.map +1 -1
- package/dist/PubSubManager/getPubSubManagerInitQuery.d.ts.map +1 -1
- package/dist/PubSubManager/getPubSubManagerInitQuery.js +9 -151
- package/dist/PubSubManager/getPubSubManagerInitQuery.js.map +1 -1
- package/dist/PubSubManager/init/getDataWatchFunctionQuery.d.ts +2 -0
- package/dist/PubSubManager/init/getDataWatchFunctionQuery.d.ts.map +1 -0
- package/dist/PubSubManager/init/getDataWatchFunctionQuery.js +187 -0
- package/dist/PubSubManager/init/getDataWatchFunctionQuery.js.map +1 -0
- package/dist/PubSubManager/initPubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/initPubSubManager.js +1 -1
- package/dist/PubSubManager/initPubSubManager.js.map +1 -1
- package/dist/PubSubManager/notifListener.d.ts.map +1 -1
- package/dist/PubSubManager/notifListener.js +9 -1
- package/dist/PubSubManager/notifListener.js.map +1 -1
- package/dist/WebsocketAPI/onSocketConnected.d.ts.map +1 -1
- package/dist/WebsocketAPI/onSocketConnected.js +2 -1
- package/dist/WebsocketAPI/onSocketConnected.js.map +1 -1
- package/dist/initProstgles.d.ts.map +1 -1
- package/dist/initProstgles.js +12 -4
- package/dist/initProstgles.js.map +1 -1
- package/dist/runClientRequest.js +1 -1
- package/dist/runClientRequest.js.map +1 -1
- package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +9 -4
- package/lib/DboBuilder/ViewHandler/subscribe.ts +3 -2
- package/lib/Prostgles.ts +1 -26
- package/lib/PubSubManager/PubSubManager.ts +3 -0
- package/lib/PubSubManager/addSub.ts +2 -1
- package/lib/PubSubManager/getPubSubManagerInitQuery.ts +6 -148
- package/lib/PubSubManager/init/getDataWatchFunctionQuery.ts +183 -0
- package/lib/PubSubManager/initPubSubManager.ts +5 -2
- package/lib/PubSubManager/notifListener.ts +18 -3
- package/lib/WebsocketAPI/onSocketConnected.ts +3 -1
- package/lib/initProstgles.ts +13 -5
- package/lib/runClientRequest.ts +1 -1
- package/package.json +1 -1
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
NOTIF_TYPE,
|
|
10
10
|
} from "./PubSubManagerUtils";
|
|
11
11
|
import { getAppCheckQuery } from "./orphanTriggerCheck";
|
|
12
|
-
|
|
12
|
+
import { version } from "../../package.json";
|
|
13
|
+
import { getDataWatchFunctionQuery } from "./init/getDataWatchFunctionQuery";
|
|
13
14
|
|
|
14
15
|
export const DB_OBJ_NAMES = {
|
|
15
16
|
trigger_add_remove_func: "prostgles.trigger_add_remove_func",
|
|
@@ -195,6 +196,9 @@ BEGIN
|
|
|
195
196
|
table_name TEXT NOT NULL,
|
|
196
197
|
condition TEXT NOT NULL,
|
|
197
198
|
condition_hash TEXT NOT NULL,
|
|
199
|
+
|
|
200
|
+
/** If defined, will check the provided fields for changes */
|
|
201
|
+
fields _TEXT ,
|
|
198
202
|
|
|
199
203
|
/* The view from the root subscription, found in the condition.
|
|
200
204
|
We need this because old_table/new_table data is not reflected in the view inside the AFTER trigger
|
|
@@ -216,153 +220,7 @@ BEGIN
|
|
|
216
220
|
FROM prostgles.app_triggers;
|
|
217
221
|
COMMENT ON VIEW prostgles.v_triggers IS 'Augment trigger table with natural IDs and per app IDs';
|
|
218
222
|
|
|
219
|
-
|
|
220
|
-
CREATE OR REPLACE FUNCTION ${DB_OBJ_NAMES.data_watch_func}() RETURNS TRIGGER
|
|
221
|
-
AS $$
|
|
222
|
-
|
|
223
|
-
DECLARE t_ids TEXT[];
|
|
224
|
-
DECLARE c_ids INTEGER[];
|
|
225
|
-
DECLARE err_c_ids INTEGER[];
|
|
226
|
-
DECLARE unions TEXT := '';
|
|
227
|
-
DECLARE query TEXT := '';
|
|
228
|
-
DECLARE v_trigger RECORD;
|
|
229
|
-
DECLARE has_errors BOOLEAN := FALSE;
|
|
230
|
-
|
|
231
|
-
DECLARE err_text TEXT;
|
|
232
|
-
DECLARE err_detail TEXT;
|
|
233
|
-
DECLARE err_hint TEXT;
|
|
234
|
-
|
|
235
|
-
DECLARE view_def_query TEXT := '';
|
|
236
|
-
|
|
237
|
-
DECLARE escaped_table TEXT;
|
|
238
|
-
|
|
239
|
-
BEGIN
|
|
240
|
-
|
|
241
|
-
--PERFORM pg_notify('debug', concat_ws(' ', 'TABLE', TG_TABLE_NAME, TG_OP));
|
|
242
|
-
|
|
243
|
-
escaped_table := concat_ws('.', CASE WHEN TG_TABLE_SCHEMA <> CURRENT_SCHEMA THEN format('%I', TG_TABLE_SCHEMA) END, format('%I', TG_TABLE_NAME));
|
|
244
|
-
|
|
245
|
-
SELECT string_agg(
|
|
246
|
-
format(
|
|
247
|
-
$c$
|
|
248
|
-
SELECT CASE WHEN EXISTS(
|
|
249
|
-
SELECT 1
|
|
250
|
-
FROM %s
|
|
251
|
-
WHERE %s
|
|
252
|
-
) THEN %s::text END AS t_ids
|
|
253
|
-
$c$,
|
|
254
|
-
table_name,
|
|
255
|
-
condition,
|
|
256
|
-
id
|
|
257
|
-
),
|
|
258
|
-
E' UNION \n '
|
|
259
|
-
)
|
|
260
|
-
INTO unions
|
|
261
|
-
FROM prostgles.v_triggers
|
|
262
|
-
WHERE table_name = escaped_table;
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
/* unions = 'old_table union new_table' or any one of the tables */
|
|
266
|
-
IF unions IS NOT NULL THEN
|
|
267
|
-
|
|
268
|
-
SELECT
|
|
269
|
-
format(
|
|
270
|
-
E'WITH %I AS (\n %s \n) ',
|
|
271
|
-
TG_TABLE_NAME,
|
|
272
|
-
concat_ws(
|
|
273
|
-
E' UNION ALL \n ',
|
|
274
|
-
CASE WHEN (TG_OP = 'DELETE' OR TG_OP = 'UPDATE') THEN ' SELECT * FROM old_table ' END,
|
|
275
|
-
CASE WHEN (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN ' SELECT * FROM new_table ' END
|
|
276
|
-
)
|
|
277
|
-
)
|
|
278
|
-
||
|
|
279
|
-
COALESCE((
|
|
280
|
-
SELECT ', ' || string_agg(format(E' %s AS ( \n %s \n ) ', related_view_name, related_view_def), ', ')
|
|
281
|
-
FROM (
|
|
282
|
-
SELECT DISTINCT related_view_name, related_view_def
|
|
283
|
-
FROM prostgles.v_triggers
|
|
284
|
-
WHERE table_name = escaped_table
|
|
285
|
-
AND related_view_name IS NOT NULL
|
|
286
|
-
AND related_view_def IS NOT NULL
|
|
287
|
-
) t
|
|
288
|
-
), '')
|
|
289
|
-
||
|
|
290
|
-
format(
|
|
291
|
-
$c$
|
|
292
|
-
SELECT ARRAY_AGG(DISTINCT t.t_ids)
|
|
293
|
-
FROM (
|
|
294
|
-
%s
|
|
295
|
-
) t
|
|
296
|
-
$c$,
|
|
297
|
-
unions
|
|
298
|
-
)
|
|
299
|
-
INTO query;
|
|
300
|
-
|
|
301
|
-
BEGIN
|
|
302
|
-
EXECUTE query INTO t_ids;
|
|
303
|
-
|
|
304
|
-
--RAISE NOTICE 'trigger fired ok';
|
|
305
|
-
|
|
306
|
-
EXCEPTION WHEN OTHERS THEN
|
|
307
|
-
|
|
308
|
-
has_errors := TRUE;
|
|
309
|
-
|
|
310
|
-
GET STACKED DIAGNOSTICS
|
|
311
|
-
err_text = MESSAGE_TEXT,
|
|
312
|
-
err_detail = PG_EXCEPTION_DETAIL,
|
|
313
|
-
err_hint = PG_EXCEPTION_HINT;
|
|
314
|
-
|
|
315
|
-
END;
|
|
316
|
-
|
|
317
|
-
--RAISE NOTICE 'has_errors: % ', has_errors;
|
|
318
|
-
--RAISE NOTICE 'unions: % , cids: %', unions, c_ids;
|
|
319
|
-
|
|
320
|
-
IF (t_ids IS NOT NULL OR has_errors) THEN
|
|
321
|
-
|
|
322
|
-
FOR v_trigger IN
|
|
323
|
-
SELECT app_id, string_agg(c_id::text, ',') as cids
|
|
324
|
-
FROM prostgles.v_triggers
|
|
325
|
-
WHERE id = ANY(t_ids)
|
|
326
|
-
OR has_errors
|
|
327
|
-
GROUP BY app_id
|
|
328
|
-
LOOP
|
|
329
|
-
|
|
330
|
-
PERFORM pg_notify(
|
|
331
|
-
${asValue(NOTIF_CHANNEL.preffix)} || v_trigger.app_id ,
|
|
332
|
-
LEFT(concat_ws(
|
|
333
|
-
${asValue(DELIMITER)},
|
|
334
|
-
|
|
335
|
-
${asValue(NOTIF_TYPE.data)},
|
|
336
|
-
COALESCE(escaped_table, 'MISSING'),
|
|
337
|
-
COALESCE(TG_OP, 'MISSING'),
|
|
338
|
-
CASE WHEN has_errors
|
|
339
|
-
THEN concat_ws('; ', 'error', err_text, err_detail, err_hint, 'query: ' || query )
|
|
340
|
-
ELSE COALESCE(v_trigger.cids, '')
|
|
341
|
-
END
|
|
342
|
-
${debugMode ? ", COALESCE(current_query(), 'current_query ??'), ' ', query" : ""}
|
|
343
|
-
), 7999/4) -- Some chars are 2bytes -> 'Ω'
|
|
344
|
-
);
|
|
345
|
-
END LOOP;
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
IF has_errors THEN
|
|
349
|
-
|
|
350
|
-
DELETE FROM prostgles.app_triggers;
|
|
351
|
-
RAISE NOTICE 'trigger dropped due to exception: % % %', err_text, err_detail, err_hint;
|
|
352
|
-
|
|
353
|
-
END IF;
|
|
354
|
-
|
|
355
|
-
END IF;
|
|
356
|
-
END IF;
|
|
357
|
-
|
|
358
|
-
${getAppCheckQuery()}
|
|
359
|
-
|
|
360
|
-
RETURN NULL;
|
|
361
|
-
|
|
362
|
-
END;
|
|
363
|
-
|
|
364
|
-
$$ LANGUAGE plpgsql;
|
|
365
|
-
COMMENT ON FUNCTION ${DB_OBJ_NAMES.data_watch_func} IS 'Prostgles internal function used to notify when data in the table changed';
|
|
223
|
+
${getDataWatchFunctionQuery(debugMode)}
|
|
366
224
|
|
|
367
225
|
CREATE OR REPLACE FUNCTION ${DB_OBJ_NAMES.trigger_add_remove_func}() RETURNS TRIGGER
|
|
368
226
|
AS $$
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { DB_OBJ_NAMES } from "../getPubSubManagerInitQuery";
|
|
2
|
+
import { getAppCheckQuery } from "../orphanTriggerCheck";
|
|
3
|
+
import { asValue, DELIMITER, NOTIF_CHANNEL, NOTIF_TYPE } from "../PubSubManagerUtils";
|
|
4
|
+
|
|
5
|
+
export const getDataWatchFunctionQuery = (debugMode: boolean | undefined) => {
|
|
6
|
+
return `
|
|
7
|
+
|
|
8
|
+
CREATE OR REPLACE FUNCTION ${DB_OBJ_NAMES.data_watch_func}() RETURNS TRIGGER
|
|
9
|
+
AS $$
|
|
10
|
+
|
|
11
|
+
DECLARE t_ids TEXT[];
|
|
12
|
+
DECLARE c_ids INTEGER[];
|
|
13
|
+
DECLARE err_c_ids INTEGER[];
|
|
14
|
+
DECLARE unions TEXT := '';
|
|
15
|
+
DECLARE query TEXT := '';
|
|
16
|
+
DECLARE v_trigger RECORD;
|
|
17
|
+
DECLARE has_errors BOOLEAN := FALSE;
|
|
18
|
+
|
|
19
|
+
DECLARE err_text TEXT;
|
|
20
|
+
DECLARE err_detail TEXT;
|
|
21
|
+
DECLARE err_hint TEXT;
|
|
22
|
+
|
|
23
|
+
DECLARE view_def_query TEXT := '';
|
|
24
|
+
|
|
25
|
+
DECLARE escaped_table TEXT;
|
|
26
|
+
|
|
27
|
+
DECLARE changed_columns TEXT := NULL;
|
|
28
|
+
|
|
29
|
+
BEGIN
|
|
30
|
+
|
|
31
|
+
--PERFORM pg_notify('debug', concat_ws(' ', 'TABLE', TG_TABLE_NAME, TG_OP));
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
-- Determine changed columns for UPDATE operations
|
|
35
|
+
IF TG_OP = 'UPDATE' THEN
|
|
36
|
+
WITH cols AS (
|
|
37
|
+
SELECT column_name::text
|
|
38
|
+
FROM information_schema.columns
|
|
39
|
+
WHERE table_schema = TG_TABLE_SCHEMA
|
|
40
|
+
AND table_name = TG_TABLE_NAME
|
|
41
|
+
),
|
|
42
|
+
changed AS (
|
|
43
|
+
SELECT column_name
|
|
44
|
+
FROM cols
|
|
45
|
+
WHERE EXISTS (
|
|
46
|
+
SELECT 1 FROM new_table n
|
|
47
|
+
JOIN old_table o ON TRUE
|
|
48
|
+
WHERE n.* IS DISTINCT FROM o.*
|
|
49
|
+
LIMIT 1
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
SELECT string_agg(column_name, ',') INTO changed_columns
|
|
53
|
+
FROM changed;
|
|
54
|
+
END IF;
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
escaped_table := concat_ws('.', CASE WHEN TG_TABLE_SCHEMA <> CURRENT_SCHEMA THEN format('%I', TG_TABLE_SCHEMA) END, format('%I', TG_TABLE_NAME));
|
|
58
|
+
|
|
59
|
+
SELECT string_agg(
|
|
60
|
+
format(
|
|
61
|
+
$c$
|
|
62
|
+
SELECT CASE WHEN EXISTS(
|
|
63
|
+
SELECT 1
|
|
64
|
+
FROM %s
|
|
65
|
+
WHERE %s
|
|
66
|
+
) THEN %s::text END AS t_ids
|
|
67
|
+
$c$,
|
|
68
|
+
table_name,
|
|
69
|
+
condition,
|
|
70
|
+
id
|
|
71
|
+
),
|
|
72
|
+
E' UNION \n '
|
|
73
|
+
)
|
|
74
|
+
INTO unions
|
|
75
|
+
FROM prostgles.v_triggers
|
|
76
|
+
WHERE table_name = escaped_table;
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
/* unions = 'old_table union new_table' or any one of the tables */
|
|
80
|
+
IF unions IS NOT NULL THEN
|
|
81
|
+
|
|
82
|
+
SELECT
|
|
83
|
+
format(
|
|
84
|
+
E'WITH %I AS (\n %s \n) ',
|
|
85
|
+
TG_TABLE_NAME,
|
|
86
|
+
concat_ws(
|
|
87
|
+
E' UNION ALL \n ',
|
|
88
|
+
CASE WHEN (TG_OP = 'DELETE' OR TG_OP = 'UPDATE') THEN ' SELECT * FROM old_table ' END,
|
|
89
|
+
CASE WHEN (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN ' SELECT * FROM new_table ' END
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
||
|
|
93
|
+
COALESCE((
|
|
94
|
+
SELECT ', ' || string_agg(format(E' %s AS ( \n %s \n ) ', related_view_name, related_view_def), ', ')
|
|
95
|
+
FROM (
|
|
96
|
+
SELECT DISTINCT related_view_name, related_view_def
|
|
97
|
+
FROM prostgles.v_triggers
|
|
98
|
+
WHERE table_name = escaped_table
|
|
99
|
+
AND related_view_name IS NOT NULL
|
|
100
|
+
AND related_view_def IS NOT NULL
|
|
101
|
+
) t
|
|
102
|
+
), '')
|
|
103
|
+
||
|
|
104
|
+
format(
|
|
105
|
+
$c$
|
|
106
|
+
SELECT ARRAY_AGG(DISTINCT t.t_ids)
|
|
107
|
+
FROM (
|
|
108
|
+
%s
|
|
109
|
+
) t
|
|
110
|
+
$c$,
|
|
111
|
+
unions
|
|
112
|
+
)
|
|
113
|
+
INTO query;
|
|
114
|
+
|
|
115
|
+
BEGIN
|
|
116
|
+
EXECUTE query INTO t_ids;
|
|
117
|
+
|
|
118
|
+
--RAISE NOTICE 'trigger fired ok';
|
|
119
|
+
|
|
120
|
+
EXCEPTION WHEN OTHERS THEN
|
|
121
|
+
|
|
122
|
+
has_errors := TRUE;
|
|
123
|
+
|
|
124
|
+
GET STACKED DIAGNOSTICS
|
|
125
|
+
err_text = MESSAGE_TEXT,
|
|
126
|
+
err_detail = PG_EXCEPTION_DETAIL,
|
|
127
|
+
err_hint = PG_EXCEPTION_HINT;
|
|
128
|
+
|
|
129
|
+
END;
|
|
130
|
+
|
|
131
|
+
--RAISE NOTICE 'has_errors: % ', has_errors;
|
|
132
|
+
--RAISE NOTICE 'unions: % , cids: %', unions, c_ids;
|
|
133
|
+
|
|
134
|
+
IF (t_ids IS NOT NULL OR has_errors) THEN
|
|
135
|
+
|
|
136
|
+
FOR v_trigger IN
|
|
137
|
+
SELECT app_id, string_agg(c_id::text, ',') as cids
|
|
138
|
+
FROM prostgles.v_triggers
|
|
139
|
+
WHERE id = ANY(t_ids)
|
|
140
|
+
OR has_errors
|
|
141
|
+
GROUP BY app_id
|
|
142
|
+
LOOP
|
|
143
|
+
|
|
144
|
+
PERFORM pg_notify(
|
|
145
|
+
${asValue(NOTIF_CHANNEL.preffix)} || v_trigger.app_id ,
|
|
146
|
+
LEFT(concat_ws(
|
|
147
|
+
${asValue(DELIMITER)},
|
|
148
|
+
|
|
149
|
+
${asValue(NOTIF_TYPE.data)},
|
|
150
|
+
COALESCE(escaped_table, 'MISSING'),
|
|
151
|
+
COALESCE(TG_OP, 'MISSING'),
|
|
152
|
+
CASE WHEN has_errors
|
|
153
|
+
THEN concat_ws('; ', 'error', err_text, err_detail, err_hint, 'query: ' || query )
|
|
154
|
+
ELSE COALESCE(v_trigger.cids, '')
|
|
155
|
+
END,
|
|
156
|
+
COALESCE(changed_columns, '')
|
|
157
|
+
${debugMode ? ", COALESCE(current_query(), 'current_query ??'), ' ', query" : ""}
|
|
158
|
+
), 7999/4) -- Some chars are 2bytes -> 'Ω'
|
|
159
|
+
);
|
|
160
|
+
END LOOP;
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
IF has_errors THEN
|
|
164
|
+
|
|
165
|
+
DELETE FROM prostgles.app_triggers;
|
|
166
|
+
RAISE NOTICE 'trigger dropped due to exception: % % %', err_text, err_detail, err_hint;
|
|
167
|
+
|
|
168
|
+
END IF;
|
|
169
|
+
|
|
170
|
+
END IF;
|
|
171
|
+
END IF;
|
|
172
|
+
|
|
173
|
+
${getAppCheckQuery()}
|
|
174
|
+
|
|
175
|
+
RETURN NULL;
|
|
176
|
+
|
|
177
|
+
END;
|
|
178
|
+
|
|
179
|
+
$$ LANGUAGE plpgsql;
|
|
180
|
+
COMMENT ON FUNCTION ${DB_OBJ_NAMES.data_watch_func} IS 'Prostgles internal function used to notify when data in the table changed';
|
|
181
|
+
|
|
182
|
+
`;
|
|
183
|
+
};
|
|
@@ -60,8 +60,11 @@ export async function initPubSubManager(this: PubSubManager): Promise<PubSubMana
|
|
|
60
60
|
[this.appId, check_frequency_ms, watching_schema_tag_names]
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
-
const appRecord = await this.db.one
|
|
64
|
-
|
|
63
|
+
const appRecord = await this.db.one<{ application_name: string | null }>(
|
|
64
|
+
"SELECT * FROM prostgles.apps WHERE id = $1",
|
|
65
|
+
[this.appId]
|
|
66
|
+
);
|
|
67
|
+
if (!appRecord.application_name?.includes(this.appId)) {
|
|
65
68
|
throw `initPubSubManager error: App record with application_name containing appId (${this.appId}) not found`;
|
|
66
69
|
}
|
|
67
70
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { includes, pickKeys } from "prostgles-types";
|
|
1
|
+
import { includes, pickKeys, tryCatchV2 } from "prostgles-types";
|
|
2
2
|
import { parseFieldFilter } from "../DboBuilder/ViewHandler/parseFieldFilter";
|
|
3
3
|
import { PubSubManager } from "./PubSubManager";
|
|
4
4
|
import { DELIMITER, log, NOTIF_TYPE, type NotifTypeName } from "./PubSubManagerUtils";
|
|
5
|
+
import { getJSONBObjectSchemaValidationError } from "../JSONBValidation/JSONBValidation";
|
|
5
6
|
|
|
6
7
|
/* Relay relevant data to relevant subscriptions */
|
|
7
8
|
export async function notifListener(this: PubSubManager, data: { payload: string }) {
|
|
@@ -68,7 +69,7 @@ export async function notifListener(this: PubSubManager, data: { payload: string
|
|
|
68
69
|
throw "notifListener: dataArr length < 3";
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
const [_, table_name, op_name, condition_ids_str] = dataArr;
|
|
72
|
+
const [_, table_name, op_name, condition_ids_str, changed_columns_str = "[]"] = dataArr;
|
|
72
73
|
const condition_ids = condition_ids_str?.split(",").map((v) => +v);
|
|
73
74
|
|
|
74
75
|
if (!table_name) {
|
|
@@ -130,9 +131,23 @@ export async function notifListener(this: PubSubManager, data: { payload: string
|
|
|
130
131
|
((sub.socket_id && this.sockets[sub.socket_id]) || sub.localFuncs)
|
|
131
132
|
)
|
|
132
133
|
);
|
|
134
|
+
const { data: changedColValidation } = tryCatchV2(() =>
|
|
135
|
+
getJSONBObjectSchemaValidationError(
|
|
136
|
+
{ cols: "string[]" },
|
|
137
|
+
{ cols: JSON.parse(changed_columns_str || "[]") as string[] },
|
|
138
|
+
"cols"
|
|
139
|
+
)
|
|
140
|
+
);
|
|
141
|
+
const changedColumns = changedColValidation?.data?.cols;
|
|
142
|
+
|
|
133
143
|
activeAndReadySubs.forEach((sub) => {
|
|
134
144
|
const { throttle = 0, throttleOpts, actions } = sub.subscribeOptions;
|
|
135
|
-
|
|
145
|
+
if (changedColumns?.length) {
|
|
146
|
+
const subFieldsHaveChanged = changedColumns.some((changedColumn) =>
|
|
147
|
+
sub.newQuery.select.some((f) => f.fields.includes(changedColumn))
|
|
148
|
+
);
|
|
149
|
+
if (!subFieldsHaveChanged) return;
|
|
150
|
+
}
|
|
136
151
|
const commandLowerCase = (op_name?.toLowerCase() || "insert") as keyof NonNullable<
|
|
137
152
|
typeof actions
|
|
138
153
|
>;
|
|
@@ -59,7 +59,9 @@ export async function onSocketConnected(this: Prostgles, socket: PRGLIOSocket) {
|
|
|
59
59
|
const { onUseOrSocketConnected } = this.opts.auth ?? {};
|
|
60
60
|
const { authHandler } = this;
|
|
61
61
|
if (onUseOrSocketConnected) {
|
|
62
|
-
if (!authHandler)
|
|
62
|
+
if (!authHandler) {
|
|
63
|
+
throw "authHandler missing";
|
|
64
|
+
}
|
|
63
65
|
const errorInfo = await onUseOrSocketConnected(
|
|
64
66
|
authHandler.getValidatedSid({ socket }),
|
|
65
67
|
getClientRequestIPsInfo({ socket }),
|
package/lib/initProstgles.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as pgPromise from "pg-promise";
|
|
2
2
|
import pg from "pg-promise/typescript/pg-subset";
|
|
3
|
-
import { getKeys, isEmpty } from "prostgles-types";
|
|
3
|
+
import { getKeys, isEmpty, isEqual } from "prostgles-types";
|
|
4
4
|
import { DBEventsManager } from "./DBEventsManager";
|
|
5
5
|
import { DBOFullyTyped } from "./DBSchemaBuilder";
|
|
6
6
|
import { DBHandlerServer, Prostgles, getIsSuperUser } from "./Prostgles";
|
|
@@ -159,7 +159,7 @@ export const initProstgles = async function (
|
|
|
159
159
|
this.dboBuilder.publishParser = this.publishParser;
|
|
160
160
|
|
|
161
161
|
/* 4. Set publish and auth listeners */
|
|
162
|
-
this.
|
|
162
|
+
this.setupSocketIO();
|
|
163
163
|
} else if (this.opts.auth) {
|
|
164
164
|
throw "Auth config does not work without publish";
|
|
165
165
|
}
|
|
@@ -193,10 +193,18 @@ export const initProstgles = async function (
|
|
|
193
193
|
getTSSchema: this.getTSFileContent,
|
|
194
194
|
options: this.opts,
|
|
195
195
|
update: async (newOpts) => {
|
|
196
|
+
let optsHaveChanged = false as boolean;
|
|
196
197
|
getKeys(newOpts).forEach((k) => {
|
|
197
|
-
|
|
198
|
-
|
|
198
|
+
if (!isEqual(this.opts[k], newOpts[k])) {
|
|
199
|
+
optsHaveChanged = true;
|
|
200
|
+
//@ts-ignore
|
|
201
|
+
this.opts[k] = newOpts[k];
|
|
202
|
+
}
|
|
199
203
|
});
|
|
204
|
+
if (!optsHaveChanged) {
|
|
205
|
+
console.warn("No options changed");
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
200
208
|
|
|
201
209
|
if ("fileTable" in newOpts) {
|
|
202
210
|
await this.initFileTable();
|
|
@@ -225,7 +233,7 @@ export const initProstgles = async function (
|
|
|
225
233
|
clientOnlyUpdateKeys.some((key) => key === updatedKey)
|
|
226
234
|
)
|
|
227
235
|
) {
|
|
228
|
-
this.
|
|
236
|
+
this.setupSocketIO();
|
|
229
237
|
} else {
|
|
230
238
|
await this.init(onReady, { type: "prgl.update", newOpts });
|
|
231
239
|
}
|
package/lib/runClientRequest.ts
CHANGED
|
@@ -67,7 +67,7 @@ export const runClientRequest = async function (
|
|
|
67
67
|
|
|
68
68
|
const { tableName, command: nonValidatedCommand, param1, param2, param3 } = args;
|
|
69
69
|
if (!TABLE_METHODS_KEYS.some((v) => v === nonValidatedCommand)) {
|
|
70
|
-
throw `Invalid command: ${nonValidatedCommand}. Expecting one of: ${TABLE_METHODS_KEYS};`;
|
|
70
|
+
throw `Invalid command: ${nonValidatedCommand}. Expecting one of: ${TABLE_METHODS_KEYS.join(", ")};`;
|
|
71
71
|
}
|
|
72
72
|
const command = nonValidatedCommand as keyof TableHandler;
|
|
73
73
|
if (!clientReq.socket && SOCKET_ONLY_COMMANDS.some((v) => v === command)) {
|