prostgles-server 3.0.154 → 4.0.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/dist/AuthHandler.d.ts.map +1 -1
- package/dist/AuthHandler.js +6 -3
- package/dist/AuthHandler.js.map +1 -1
- package/dist/DBEventsManager.d.ts.map +1 -1
- package/dist/DBEventsManager.js +5 -4
- package/dist/DBEventsManager.js.map +1 -1
- package/dist/DBSchemaBuilder.js +14 -14
- package/dist/DBSchemaBuilder.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions.js +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/makeSelectQuery.js.map +1 -1
- package/dist/DboBuilder/TableHandler.js +1 -2
- package/dist/DboBuilder/TableHandler.js.map +1 -1
- package/dist/DboBuilder/ViewHandler.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler.js +10 -8
- package/dist/DboBuilder/ViewHandler.js.map +1 -1
- package/dist/DboBuilder/getCondition.js +1 -1
- package/dist/DboBuilder/getCondition.js.map +1 -1
- package/dist/DboBuilder/insert.js +1 -1
- package/dist/DboBuilder/insert.js.map +1 -1
- package/dist/DboBuilder/insertDataParse.js +4 -3
- package/dist/DboBuilder/insertDataParse.js.map +1 -1
- package/dist/DboBuilder/subscribe.d.ts +2 -2
- package/dist/DboBuilder/subscribe.d.ts.map +1 -1
- package/dist/DboBuilder/subscribe.js +3 -4
- package/dist/DboBuilder/subscribe.js.map +1 -1
- package/dist/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder.js +5 -4
- package/dist/DboBuilder.js.map +1 -1
- package/dist/FileManager.js +1 -1
- package/dist/FileManager.js.map +1 -1
- package/dist/Filtering.js.map +1 -1
- package/dist/JSONBValidation/validation.js.map +1 -1
- package/dist/Prostgles.js +1 -1
- package/dist/Prostgles.js.map +1 -1
- package/dist/PubSubManager/PubSubManager.d.ts +28 -26
- package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/PubSubManager.js +53 -433
- package/dist/PubSubManager/PubSubManager.js.map +1 -1
- package/dist/PubSubManager/addSub.d.ts +8 -0
- package/dist/PubSubManager/addSub.d.ts.map +1 -0
- package/dist/PubSubManager/addSub.js +163 -0
- package/dist/PubSubManager/addSub.js.map +1 -0
- package/dist/PubSubManager/addSync.d.ts +8 -0
- package/dist/PubSubManager/addSync.d.ts.map +1 -0
- package/dist/PubSubManager/addSync.js +110 -0
- package/dist/PubSubManager/addSync.js.map +1 -0
- package/dist/PubSubManager/notifListener.d.ts +5 -0
- package/dist/PubSubManager/notifListener.d.ts.map +1 -0
- package/dist/PubSubManager/notifListener.js +99 -0
- package/dist/PubSubManager/notifListener.js.map +1 -0
- package/dist/PubSubManager/pushSubData.d.ts +3 -0
- package/dist/PubSubManager/pushSubData.d.ts.map +1 -0
- package/dist/PubSubManager/pushSubData.js +48 -0
- package/dist/PubSubManager/pushSubData.js.map +1 -0
- package/dist/PublishParser.d.ts.map +1 -1
- package/dist/PublishParser.js +4 -3
- package/dist/PublishParser.js.map +1 -1
- package/dist/TableConfig/TableConfig.js.map +1 -1
- package/dist/TableConfig/getConstraintDefinitionQueries.js.map +1 -1
- package/dist/TableConfig/getTableColumnQueries.js.map +1 -1
- package/lib/AuthHandler.d.ts.map +1 -1
- package/lib/AuthHandler.js +6 -3
- package/lib/AuthHandler.ts +12 -7
- package/lib/DBEventsManager.d.ts.map +1 -1
- package/lib/DBEventsManager.js +5 -4
- package/lib/DBEventsManager.ts +10 -9
- package/lib/DBSchemaBuilder.js +14 -14
- package/lib/DBSchemaBuilder.ts +14 -14
- package/lib/DboBuilder/QueryBuilder/Functions.js +1 -1
- package/lib/DboBuilder/QueryBuilder/Functions.ts +2 -2
- package/lib/DboBuilder/QueryBuilder/makeSelectQuery.ts +1 -1
- package/lib/DboBuilder/TableHandler.d.ts +1 -5
- package/lib/DboBuilder/TableHandler.d.ts.map +1 -1
- package/lib/DboBuilder/TableHandler.js +1 -2
- package/lib/DboBuilder/TableHandler.ts +3 -3
- package/lib/DboBuilder/ViewHandler.d.ts.map +1 -1
- package/lib/DboBuilder/ViewHandler.js +10 -8
- package/lib/DboBuilder/ViewHandler.ts +22 -20
- package/lib/DboBuilder/getCondition.js +1 -1
- package/lib/DboBuilder/getCondition.ts +2 -2
- package/lib/DboBuilder/insert.js +1 -1
- package/lib/DboBuilder/insert.ts +1 -1
- package/lib/DboBuilder/insertDataParse.js +4 -3
- package/lib/DboBuilder/insertDataParse.ts +15 -13
- package/lib/DboBuilder/subscribe.d.ts +2 -2
- package/lib/DboBuilder/subscribe.d.ts.map +1 -1
- package/lib/DboBuilder/subscribe.js +3 -4
- package/lib/DboBuilder/subscribe.ts +8 -9
- package/lib/DboBuilder.d.ts.map +1 -1
- package/lib/DboBuilder.js +5 -4
- package/lib/DboBuilder.ts +15 -21
- package/lib/FileManager.js +1 -1
- package/lib/FileManager.ts +5 -5
- package/lib/Filtering.ts +1 -1
- package/lib/JSONBValidation/validation.ts +3 -3
- package/lib/Prostgles.js +1 -1
- package/lib/Prostgles.ts +3 -3
- package/lib/PubSubManager/PubSubManager.d.ts +27 -29
- package/lib/PubSubManager/PubSubManager.d.ts.map +1 -1
- package/lib/PubSubManager/PubSubManager.js +54 -437
- package/lib/PubSubManager/PubSubManager.ts +93 -546
- package/lib/PubSubManager/addSub.d.ts +8 -0
- package/lib/PubSubManager/addSub.d.ts.map +1 -0
- package/lib/PubSubManager/addSub.js +162 -0
- package/lib/PubSubManager/addSub.ts +186 -0
- package/lib/PubSubManager/addSync.d.ts +8 -0
- package/lib/PubSubManager/addSync.d.ts.map +1 -0
- package/lib/PubSubManager/addSync.js +109 -0
- package/lib/PubSubManager/addSync.ts +127 -0
- package/lib/PubSubManager/notifListener.d.ts +5 -0
- package/lib/PubSubManager/notifListener.d.ts.map +1 -0
- package/lib/PubSubManager/notifListener.js +98 -0
- package/lib/PubSubManager/notifListener.ts +124 -0
- package/lib/PubSubManager/pushSubData.d.ts +3 -0
- package/lib/PubSubManager/pushSubData.d.ts.map +1 -0
- package/lib/PubSubManager/pushSubData.js +47 -0
- package/lib/PubSubManager/pushSubData.ts +47 -0
- package/lib/PublishParser.d.ts.map +1 -1
- package/lib/PublishParser.js +4 -3
- package/lib/PublishParser.ts +4 -3
- package/lib/TableConfig/TableConfig.ts +7 -7
- package/lib/TableConfig/getConstraintDefinitionQueries.ts +1 -1
- package/lib/TableConfig/getTableColumnQueries.ts +2 -2
- package/package.json +2 -2
- package/tests/client/PID.txt +1 -1
- package/tests/client/package-lock.json +15 -15
- package/tests/client/package.json +1 -1
- package/tests/client/tsconfig.json +2 -1
- package/tests/client_only_queries.js +1 -1
- package/tests/client_only_queries.ts +1 -1
- package/tests/isomorphic_queries.ts +1 -1
- package/tests/server/DBoGenerated.d.ts +2 -2
- package/tests/server/package-lock.json +3 -3
- package/tests/server/tsconfig.json +2 -1
- package/tsconfig.json +1 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
|
|
6
6
|
import { PostgresNotifListenManager } from "../PostgresNotifListenManager";
|
|
7
|
-
import {
|
|
7
|
+
import { addSync } from "./addSync";
|
|
8
8
|
import { TableOrViewInfo, TableInfo, DBHandlerServer, DboBuilder, PRGLIOSocket, canEXECUTE } from "../DboBuilder";
|
|
9
9
|
import { DB, isSuperUser } from "../Prostgles";
|
|
10
10
|
import { initPubSubManager } from "./initPubSubManager";
|
|
@@ -13,13 +13,15 @@ import * as Bluebird from "bluebird";
|
|
|
13
13
|
import * as pgPromise from 'pg-promise';
|
|
14
14
|
import pg from 'pg-promise/typescript/pg-subset';
|
|
15
15
|
|
|
16
|
-
import { SelectParams, FieldFilter, asName, WAL,
|
|
16
|
+
import { SelectParams, FieldFilter, asName, WAL, AnyObject } from "prostgles-types";
|
|
17
17
|
|
|
18
18
|
import { ClientExpressData, syncData } from "../SyncReplication";
|
|
19
19
|
import { TableRule } from "../PublishParser";
|
|
20
|
-
import { find
|
|
20
|
+
import { find } from "prostgles-types/dist/util";
|
|
21
21
|
import { DB_OBJ_NAMES } from "./getInitQuery";
|
|
22
|
-
|
|
22
|
+
import { addSub } from "./addSub";
|
|
23
|
+
import { notifListener } from "./notifListener";
|
|
24
|
+
import { pushSubData } from "./pushSubData";
|
|
23
25
|
|
|
24
26
|
type PGP = pgPromise.IMain<{}, pg.IClient>;
|
|
25
27
|
const pgp: PGP = pgPromise({
|
|
@@ -57,7 +59,7 @@ export type SyncParams = {
|
|
|
57
59
|
is_syncing: boolean;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
type AddSyncParams = {
|
|
62
|
+
export type AddSyncParams = {
|
|
61
63
|
socket: any;
|
|
62
64
|
table_info: TableInfo;
|
|
63
65
|
table_rules: TableRule;
|
|
@@ -88,11 +90,10 @@ export type ViewSubscriptionOptions = ({
|
|
|
88
90
|
}[];
|
|
89
91
|
}
|
|
90
92
|
|
|
91
|
-
type SubscriptionParams = {
|
|
93
|
+
export type SubscriptionParams = {
|
|
92
94
|
socket_id?: string;
|
|
93
95
|
channel_name: string;
|
|
94
|
-
table_name: string;
|
|
95
|
-
socket: PRGLIOSocket | undefined;
|
|
96
|
+
// table_name: string;
|
|
96
97
|
|
|
97
98
|
/**
|
|
98
99
|
* If this is a view then an array with all related tables will be
|
|
@@ -101,18 +102,19 @@ type SubscriptionParams = {
|
|
|
101
102
|
parentSubParams: Omit<SubscriptionParams, "parentSubParams"> | undefined;
|
|
102
103
|
|
|
103
104
|
table_info: TableOrViewInfo;
|
|
105
|
+
|
|
106
|
+
/* Used as input */
|
|
104
107
|
table_rules?: TableRule;
|
|
105
108
|
filter: object;
|
|
106
109
|
params: SelectParams;
|
|
107
|
-
|
|
110
|
+
|
|
111
|
+
func: undefined | ((data: any) => any);
|
|
112
|
+
socket: PRGLIOSocket | undefined;
|
|
113
|
+
|
|
108
114
|
throttle?: number;
|
|
109
115
|
last_throttled: number;
|
|
110
116
|
is_throttling?: any;
|
|
111
|
-
is_ready?: boolean;
|
|
112
|
-
// subOne?: boolean;
|
|
113
|
-
}
|
|
114
|
-
type AddSubscriptionParams = SubscriptionParams & {
|
|
115
|
-
condition: string;
|
|
117
|
+
is_ready?: boolean;
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
export type PubSubManagerOptions = {
|
|
@@ -122,6 +124,27 @@ export type PubSubManagerOptions = {
|
|
|
122
124
|
onSchemaChange?: (event: { command: string; query: string }) => void;
|
|
123
125
|
}
|
|
124
126
|
|
|
127
|
+
export type Subscription = Pick<SubscriptionParams,
|
|
128
|
+
| "throttle"
|
|
129
|
+
| "is_throttling"
|
|
130
|
+
| "last_throttled"
|
|
131
|
+
| "channel_name"
|
|
132
|
+
| "is_ready"
|
|
133
|
+
| "func"
|
|
134
|
+
| "socket"
|
|
135
|
+
| "socket_id"
|
|
136
|
+
| "table_info"
|
|
137
|
+
| "filter"
|
|
138
|
+
| "params"
|
|
139
|
+
| "table_rules"
|
|
140
|
+
> & {
|
|
141
|
+
triggers: {
|
|
142
|
+
table_name: string;
|
|
143
|
+
condition: string;
|
|
144
|
+
is_related: boolean;
|
|
145
|
+
}[];
|
|
146
|
+
}
|
|
147
|
+
|
|
125
148
|
export class PubSubManager {
|
|
126
149
|
static DELIMITER = '|$prstgls$|';
|
|
127
150
|
|
|
@@ -134,9 +157,10 @@ export class PubSubManager {
|
|
|
134
157
|
}
|
|
135
158
|
|
|
136
159
|
_triggers?: Record<string, string[]>;
|
|
137
|
-
sockets:
|
|
138
|
-
subs: { [ke: string]: { [ke: string]: { subs: SubscriptionParams[] } } };
|
|
139
|
-
|
|
160
|
+
sockets: AnyObject = {};
|
|
161
|
+
// subs: { [ke: string]: { [ke: string]: { subs: SubscriptionParams[] } } };
|
|
162
|
+
subs: Subscription[] = [];
|
|
163
|
+
syncs: SyncParams[] = [];
|
|
140
164
|
socketChannelPreffix: string;
|
|
141
165
|
onSchemaChange?: ((event: { command: string; query: string }) => void) = undefined;
|
|
142
166
|
|
|
@@ -150,10 +174,7 @@ export class PubSubManager {
|
|
|
150
174
|
|
|
151
175
|
this.onSchemaChange = onSchemaChange;
|
|
152
176
|
this.dboBuilder = dboBuilder;
|
|
153
|
-
|
|
154
|
-
this.sockets = {};
|
|
155
|
-
this.subs = {};
|
|
156
|
-
this.syncs = [];
|
|
177
|
+
|
|
157
178
|
this.socketChannelPreffix = wsChannelNamePrefix || "_psqlWS_";
|
|
158
179
|
|
|
159
180
|
log("Created PubSubManager");
|
|
@@ -215,7 +236,8 @@ export class PubSubManager {
|
|
|
215
236
|
if (this.appCheck) {
|
|
216
237
|
clearInterval(this.appCheck);
|
|
217
238
|
}
|
|
218
|
-
this.
|
|
239
|
+
this.subs = [];
|
|
240
|
+
this.syncs = [];
|
|
219
241
|
if (!this.postgresNotifListenManager) {
|
|
220
242
|
throw "this.postgresNotifListenManager missing"
|
|
221
243
|
}
|
|
@@ -364,32 +386,21 @@ export class PubSubManager {
|
|
|
364
386
|
return this.postgresNotifListenManager.isListening();
|
|
365
387
|
}
|
|
366
388
|
|
|
367
|
-
getSubs(table_name: string, condition: string):
|
|
368
|
-
const subs = this.subs
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
return subs.flatMap(s => {
|
|
375
|
-
/* Return parentSubs instead to ensure throttling works */
|
|
376
|
-
if(s.parentSubParams){
|
|
377
|
-
const parentSubs: SubscriptionParams[] = [];
|
|
378
|
-
const parentChannel = s.parentSubParams.channel_name;
|
|
379
|
-
for(const tableName in this.subs){
|
|
380
|
-
for(const condition in this.subs[tableName]){
|
|
381
|
-
this.subs[tableName][condition].subs.forEach(parentSub => {
|
|
382
|
-
if(!parentSub.parentSubParams && parentSub.channel_name === parentChannel){
|
|
383
|
-
parentSubs.push(parentSub)
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
return parentSubs ?? s;
|
|
389
|
-
}
|
|
389
|
+
getSubs(table_name: string, condition: string, client?: Pick<Subscription, "func" | "socket_id">): Subscription[] {
|
|
390
|
+
const subs = this.subs.filter(s => find(s.triggers, { table_name, condition }));
|
|
391
|
+
if(client){
|
|
392
|
+
return subs.filter(s => client.func && s.func === client.func || client.socket_id && s.socket_id === client.socket_id);
|
|
393
|
+
}
|
|
394
|
+
return subs;
|
|
395
|
+
}
|
|
390
396
|
|
|
391
|
-
|
|
392
|
-
|
|
397
|
+
removeLocalSub(tableName: string, conditionRaw: string, func: (items: object[]) => any) {
|
|
398
|
+
const condition = parseCondition(conditionRaw);
|
|
399
|
+
if (this.getSubs(tableName, condition, { func }).length) {
|
|
400
|
+
this.subs = this.subs.filter(s => s.func !== func && !find(s.triggers, { tableName, condition }))
|
|
401
|
+
} else {
|
|
402
|
+
console.error("Could not unsubscribe. Subscription might not have initialised yet", { tableName, condition })
|
|
403
|
+
}
|
|
393
404
|
}
|
|
394
405
|
|
|
395
406
|
getSyncs(table_name: string, condition: string) {
|
|
@@ -397,189 +408,46 @@ export class PubSubManager {
|
|
|
397
408
|
.filter((s: SyncParams) => s.table_name === table_name && s.condition === condition);
|
|
398
409
|
}
|
|
399
410
|
|
|
400
|
-
|
|
401
|
-
notifListener = async (data: { payload: string }) => {
|
|
402
|
-
const str = data.payload;
|
|
411
|
+
notifListener = notifListener.bind(this);
|
|
403
412
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
if (notifType === this.NOTIF_TYPE.schema) {
|
|
414
|
-
if (this.onSchemaChange) {
|
|
415
|
-
const command = dataArr[1]!,
|
|
416
|
-
event_type = dataArr[2],
|
|
417
|
-
query = dataArr[3];
|
|
418
|
-
|
|
419
|
-
if (query) {
|
|
420
|
-
this.onSchemaChange({ command, query })
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
return;
|
|
413
|
+
getSubData = async (sub: Subscription): Promise<
|
|
414
|
+
{ data: any[]; err?: undefined; } |
|
|
415
|
+
{ data?: undefined; err: any; }
|
|
416
|
+
> => {
|
|
417
|
+
const { table_info, filter, params, table_rules } = sub; //, subOne = false
|
|
418
|
+
const { name: table_name } = table_info;
|
|
419
|
+
|
|
420
|
+
if (!this.dbo?.[table_name]?.find) {
|
|
421
|
+
throw new Error(`1107 this.dbo.${table_name}.find`);
|
|
425
422
|
}
|
|
426
423
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
throw "dataArr length < 3"
|
|
424
|
+
try {
|
|
425
|
+
const data = await this.dbo?.[table_name]!.find!(filter, params, undefined, table_rules)
|
|
426
|
+
return { data };
|
|
427
|
+
} catch(err){
|
|
428
|
+
return { err };
|
|
433
429
|
}
|
|
434
|
-
|
|
435
|
-
op_name = dataArr[2]!,
|
|
436
|
-
condition_ids_str = dataArr[3]!;
|
|
437
|
-
|
|
438
|
-
// const triggers = await this.db.any("SELECT * FROM prostgles.triggers WHERE table_name = $1 AND id IN ($2:csv)", [table_name, condition_ids_str.split(",").map(v => +v)]);
|
|
439
|
-
// const conditions: string[] = triggers.map(t => t.condition);
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Trigger error
|
|
443
|
-
*/
|
|
444
|
-
log("PG Trigger ->", dataArr.join("__"))
|
|
445
|
-
if (
|
|
446
|
-
condition_ids_str && condition_ids_str.startsWith("error") &&
|
|
447
|
-
this._triggers &&
|
|
448
|
-
this._triggers[table_name]?.length
|
|
449
|
-
) {
|
|
450
|
-
const pref = "INTERNAL ERROR";
|
|
451
|
-
console.error(`${pref}: condition_ids_str: ${condition_ids_str}`)
|
|
452
|
-
this._triggers[table_name]!.map(c => {
|
|
453
|
-
const subs = this.getSubs(table_name, c);
|
|
454
|
-
subs.map(s => {
|
|
455
|
-
this.pushSubData(s, pref + ". Check server logs. Schema might have changed");
|
|
456
|
-
})
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* Trigger ok
|
|
461
|
-
*/
|
|
462
|
-
} else if (
|
|
463
|
-
condition_ids_str?.split(",").length &&
|
|
464
|
-
condition_ids_str?.split(",").every((c: string) => Number.isInteger(+c)) &&
|
|
465
|
-
this._triggers?.[table_name]?.length
|
|
466
|
-
) {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
const idxs = condition_ids_str.split(",").map(v => +v);
|
|
470
|
-
const conditions = this._triggers[table_name]!.filter((c, i) => idxs.includes(i))
|
|
471
|
-
|
|
472
|
-
log("PG Trigger -> ", { table_name, op_name, condition_ids_str, conditions }, this._triggers[table_name]);
|
|
430
|
+
}
|
|
473
431
|
|
|
474
|
-
|
|
432
|
+
pushSubData = pushSubData.bind(this);
|
|
475
433
|
|
|
476
|
-
|
|
477
|
-
|
|
434
|
+
upsertSocket(socket: any) {
|
|
435
|
+
if (socket && !this.sockets[socket.id]) {
|
|
436
|
+
this.sockets[socket.id] = socket;
|
|
437
|
+
socket.on("disconnect", () => {
|
|
478
438
|
|
|
439
|
+
this.subs = this.subs.filter(s => {
|
|
440
|
+
return !(s.socket && s.socket.id === socket.id);
|
|
441
|
+
});
|
|
479
442
|
|
|
480
|
-
syncs.
|
|
481
|
-
|
|
443
|
+
this.syncs = this.syncs.filter(s => {
|
|
444
|
+
return !(s.socket_id && s.socket_id === socket.id);
|
|
482
445
|
});
|
|
483
446
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
// console.error(`sub missing for ${table_name} ${condition}`, this.triggers);
|
|
487
|
-
// console.log(this.subs)
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
447
|
+
delete this.sockets[socket.id];
|
|
490
448
|
|
|
491
|
-
|
|
492
|
-
for (let i = 0; i < subs.length; i++) {
|
|
493
|
-
const sub = subs[i]!;
|
|
494
|
-
if (
|
|
495
|
-
this.dbo[sub.table_name] &&
|
|
496
|
-
sub.is_ready &&
|
|
497
|
-
(sub.socket_id && this.sockets[sub.socket_id]) || sub.func
|
|
498
|
-
) {
|
|
499
|
-
const throttle = sub.throttle || 0;
|
|
500
|
-
if (sub.last_throttled <= Date.now() - throttle) {
|
|
501
|
-
|
|
502
|
-
/* It is assumed the policy was checked before this point */
|
|
503
|
-
this.pushSubData(sub);
|
|
504
|
-
// sub.last_throttled = Date.now();
|
|
505
|
-
} else if (!sub.is_throttling) {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
log("throttling sub")
|
|
509
|
-
sub.is_throttling = setTimeout(() => {
|
|
510
|
-
log("throttling finished. pushSubData...")
|
|
511
|
-
sub.is_throttling = null;
|
|
512
|
-
this.pushSubData(sub);
|
|
513
|
-
}, throttle);// sub.throttle);
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
}
|
|
449
|
+
return "ok";
|
|
517
450
|
});
|
|
518
|
-
|
|
519
|
-
} else {
|
|
520
|
-
|
|
521
|
-
// if(!this._triggers || !this._triggers[table_name] || !this._triggers[table_name].length){
|
|
522
|
-
// console.warn(190, "Trigger sub not found. DROPPING TRIGGER", table_name, condition_ids_str, this._triggers);
|
|
523
|
-
// this.dropTrigger(table_name);
|
|
524
|
-
// } else {
|
|
525
|
-
// }
|
|
526
|
-
console.warn(190, "Trigger sub issue: ", table_name, condition_ids_str, this._triggers);
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
pushSubData(sub: SubscriptionParams, err?: any) {
|
|
532
|
-
if (!sub) throw "pushSubData: invalid sub";
|
|
533
|
-
const { table_name, filter, params, table_rules, socket_id, channel_name, func } = sub; //, subOne = false
|
|
534
|
-
|
|
535
|
-
sub.last_throttled = Date.now();
|
|
536
|
-
|
|
537
|
-
if (err) {
|
|
538
|
-
if (socket_id) {
|
|
539
|
-
this.sockets[socket_id].emit(channel_name, { err });
|
|
540
|
-
}
|
|
541
|
-
return true;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
return new Promise(async (resolve, reject) => {
|
|
545
|
-
/* TODO: Retire subOne -> it's redundant */
|
|
546
|
-
// this.dbo[table_name][subOne? "findOne" : "find"](filter, params, null, table_rules)
|
|
547
|
-
if (!this.dbo?.[table_name]?.find) {
|
|
548
|
-
throw new Error(`1107 this.dbo.${table_name}.find`);
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
this.dbo?.[table_name]?.find?.(filter, params, undefined, table_rules)
|
|
552
|
-
.then(data => {
|
|
553
|
-
|
|
554
|
-
if (socket_id && this.sockets[socket_id]) {
|
|
555
|
-
log("Pushed " + data.length + " records to sub")
|
|
556
|
-
this.sockets[socket_id].emit(channel_name, { data }, () => {
|
|
557
|
-
resolve(data);
|
|
558
|
-
});
|
|
559
|
-
/* TO DO: confirm receiving data or server will unsubscribe
|
|
560
|
-
{ data }, (cb)=> { console.log(cb) });
|
|
561
|
-
*/
|
|
562
|
-
} else if (func) {
|
|
563
|
-
func(data);
|
|
564
|
-
resolve(data);
|
|
565
|
-
}
|
|
566
|
-
sub.last_throttled = Date.now();
|
|
567
|
-
}).catch(err => {
|
|
568
|
-
const errObj = { _err_msg: err.toString(), err };
|
|
569
|
-
if (socket_id && this.sockets[socket_id]) {
|
|
570
|
-
this.sockets[socket_id].emit(channel_name, { err: errObj });
|
|
571
|
-
} else if (func) {
|
|
572
|
-
func({ err: errObj });
|
|
573
|
-
}
|
|
574
|
-
reject(errObj)
|
|
575
|
-
});
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
upsertSocket(socket: any) {
|
|
580
|
-
if (socket && !this.sockets[socket.id]) {
|
|
581
|
-
this.sockets[socket.id] = socket;
|
|
582
|
-
socket.on("disconnect", () => this.onSocketDisconnected(socket));
|
|
583
451
|
}
|
|
584
452
|
}
|
|
585
453
|
|
|
@@ -588,275 +456,10 @@ export class PubSubManager {
|
|
|
588
456
|
return await syncData(this, sync, clientData, source);
|
|
589
457
|
}
|
|
590
458
|
|
|
591
|
-
|
|
592
|
-
* Returns a sync channel
|
|
593
|
-
* A sync channel is unique per socket for each filter
|
|
594
|
-
*/
|
|
595
|
-
async addSync(syncParams: AddSyncParams) {
|
|
596
|
-
const {
|
|
597
|
-
socket = null, table_info = null, table_rules, synced_field = null,
|
|
598
|
-
allow_delete = false, id_fields = [], filter = {},
|
|
599
|
-
params, condition = "", throttle = 0
|
|
600
|
-
} = syncParams || {};
|
|
601
|
-
|
|
602
|
-
const conditionParsed = parseCondition(condition);
|
|
603
|
-
if (!socket || !table_info) throw "socket or table_info missing";
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
const { name: table_name } = table_info,
|
|
607
|
-
channel_name = `${this.socketChannelPreffix}.${table_name}.${JSON.stringify(filter)}.sync`;
|
|
608
|
-
|
|
609
|
-
if (!synced_field) throw "synced_field missing from table_rules";
|
|
610
|
-
|
|
611
|
-
this.upsertSocket(socket);
|
|
612
|
-
|
|
613
|
-
const upsertSync = () => {
|
|
614
|
-
const newSync = {
|
|
615
|
-
channel_name,
|
|
616
|
-
table_name,
|
|
617
|
-
filter,
|
|
618
|
-
condition: conditionParsed,
|
|
619
|
-
synced_field,
|
|
620
|
-
id_fields,
|
|
621
|
-
allow_delete,
|
|
622
|
-
table_rules,
|
|
623
|
-
throttle: Math.max(throttle || 0, table_rules?.sync?.throttle || 0),
|
|
624
|
-
batch_size: get(table_rules, "sync.batch_size") || DEFAULT_SYNC_BATCH_SIZE,
|
|
625
|
-
last_throttled: 0,
|
|
626
|
-
socket_id: socket.id,
|
|
627
|
-
is_sync: true,
|
|
628
|
-
last_synced: 0,
|
|
629
|
-
lr: undefined,
|
|
630
|
-
table_info,
|
|
631
|
-
is_syncing: false,
|
|
632
|
-
wal: undefined,
|
|
633
|
-
socket,
|
|
634
|
-
params
|
|
635
|
-
};
|
|
636
|
-
|
|
637
|
-
/* Only a sync per socket per table per condition allowed */
|
|
638
|
-
this.syncs = this.syncs || [];
|
|
639
|
-
const existing = find(this.syncs, { socket_id: socket.id, channel_name });
|
|
640
|
-
if (!existing) {
|
|
641
|
-
this.syncs.push(newSync);
|
|
642
|
-
// console.log("Added SYNC");
|
|
643
|
-
|
|
644
|
-
socket.removeAllListeners(channel_name + "unsync");
|
|
645
|
-
socket.once(channel_name + "unsync", (_data: any, cb: BasicCallback) => {
|
|
646
|
-
this.onSocketDisconnected(socket, channel_name);
|
|
647
|
-
cb(null, { res: "ok" })
|
|
648
|
-
});
|
|
649
|
-
|
|
650
|
-
socket.removeAllListeners(channel_name);
|
|
651
|
-
socket.on(channel_name, (data: any, cb: BasicCallback) => {
|
|
652
|
-
|
|
653
|
-
if (!data) {
|
|
654
|
-
cb({ err: "Unexpected request. Need data or onSyncRequest" });
|
|
655
|
-
return;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
/*
|
|
659
|
-
*/
|
|
660
|
-
|
|
661
|
-
/* Server will:
|
|
662
|
-
1. Ask for last_synced emit(onSyncRequest)
|
|
663
|
-
2. Ask for data >= server_synced emit(onPullRequest)
|
|
664
|
-
-> Upsert that data
|
|
665
|
-
2. Push data >= last_synced emit(data.data)
|
|
666
|
-
|
|
667
|
-
Client will:
|
|
668
|
-
1. Send last_synced on(onSyncRequest)
|
|
669
|
-
2. Send data >= server_synced on(onPullRequest)
|
|
670
|
-
3. Send data on CRUD emit(data.data | data.deleted)
|
|
671
|
-
4. Upsert data.data | deleted on(data.data | data.deleted)
|
|
672
|
-
*/
|
|
673
|
-
|
|
674
|
-
// if(data.data){
|
|
675
|
-
// console.error("THIS SHOUKD NEVER FIRE !! NEW DATA FROM SYNC");
|
|
676
|
-
// this.upsertClientData(newSync, data.data);
|
|
677
|
-
// } else
|
|
678
|
-
if (data.onSyncRequest) {
|
|
679
|
-
// console.log("syncData from socket")
|
|
680
|
-
this.syncData(newSync, data.onSyncRequest, "client");
|
|
681
|
-
|
|
682
|
-
// console.log("onSyncRequest ", socket._user)
|
|
683
|
-
} else {
|
|
684
|
-
console.error("Unexpected sync request data from client: ", data)
|
|
685
|
-
}
|
|
686
|
-
});
|
|
687
|
-
|
|
688
|
-
// socket.emit(channel_name, { onSyncRequest: true }, (response) => {
|
|
689
|
-
// console.log(response)
|
|
690
|
-
// });
|
|
691
|
-
} else {
|
|
692
|
-
console.warn("UNCLOSED DUPLICATE SYNC FOUND", existing.channel_name);
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
return newSync;
|
|
696
|
-
};
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
// const { min_id, max_id, count, max_synced } = params;
|
|
700
|
-
|
|
701
|
-
const _sync = upsertSync();
|
|
702
|
-
|
|
703
|
-
await this.addTrigger({ table_name, condition: conditionParsed });
|
|
704
|
-
|
|
705
|
-
return channel_name;
|
|
706
|
-
}
|
|
459
|
+
addSync = addSync.bind(this);
|
|
707
460
|
|
|
461
|
+
addSub = addSub.bind(this);
|
|
708
462
|
|
|
709
|
-
/* Must return a channel for socket */
|
|
710
|
-
/* The distinct list of channel names must have a corresponding trigger in the database */
|
|
711
|
-
async addSub(subscriptionParams: Omit<AddSubscriptionParams, "channel_name" | "parentSubParams">) {
|
|
712
|
-
const {
|
|
713
|
-
socket, func = null, table_info = null, table_rules, filter = {},
|
|
714
|
-
params = {}, condition = "", throttle = 0, //subOne = false,
|
|
715
|
-
viewOptions
|
|
716
|
-
} = subscriptionParams || {};
|
|
717
|
-
|
|
718
|
-
let validated_throttle = subscriptionParams.throttle || 10;
|
|
719
|
-
if ((!socket && !func) || !table_info) throw "socket/func or table_info missing";
|
|
720
|
-
|
|
721
|
-
const pubThrottle = get(table_rules, ["subscribe", "throttle"]) || 0;
|
|
722
|
-
if (pubThrottle && Number.isInteger(pubThrottle) && pubThrottle > 0) {
|
|
723
|
-
validated_throttle = pubThrottle;
|
|
724
|
-
}
|
|
725
|
-
if (throttle && Number.isInteger(throttle) && throttle >= pubThrottle) {
|
|
726
|
-
validated_throttle = throttle;
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
const channel_name = `${this.socketChannelPreffix}.${table_info.name}.${JSON.stringify(filter)}.${JSON.stringify(params)}.${"m"}.sub`;
|
|
730
|
-
|
|
731
|
-
this.upsertSocket(socket);
|
|
732
|
-
|
|
733
|
-
const upsertSub = (newSubData: { table_name: string; condition: string; is_ready: boolean; parentSubParams: SubscriptionParams["parentSubParams"] }, isReadyOverride: boolean | undefined) => {
|
|
734
|
-
const { table_name, condition: _cond, is_ready = false, parentSubParams } = newSubData,
|
|
735
|
-
condition = parseCondition(_cond),
|
|
736
|
-
newSub: SubscriptionParams = {
|
|
737
|
-
socket,
|
|
738
|
-
table_name: table_info.name,
|
|
739
|
-
table_info,
|
|
740
|
-
filter,
|
|
741
|
-
params,
|
|
742
|
-
table_rules,
|
|
743
|
-
channel_name,
|
|
744
|
-
parentSubParams,
|
|
745
|
-
func: func ?? undefined,
|
|
746
|
-
socket_id: socket?.id,
|
|
747
|
-
throttle: validated_throttle,
|
|
748
|
-
is_throttling: null,
|
|
749
|
-
last_throttled: 0,
|
|
750
|
-
is_ready,
|
|
751
|
-
};
|
|
752
|
-
|
|
753
|
-
this.subs[table_name] = this.subs[table_name] ?? {};
|
|
754
|
-
this.subs[table_name]![condition] = this.subs[table_name]![condition] ?? { subs: [] };
|
|
755
|
-
this.subs[table_name]![condition]!.subs = this.subs[table_name]![condition]!.subs ?? [];
|
|
756
|
-
|
|
757
|
-
// console.log("1034 upsertSub", this.subs)
|
|
758
|
-
const sub_idx = this.subs[table_name]![condition]!.subs.findIndex(s =>
|
|
759
|
-
s.channel_name === channel_name &&
|
|
760
|
-
(
|
|
761
|
-
socket && s.socket_id === socket.id ||
|
|
762
|
-
func && s.func === func
|
|
763
|
-
)
|
|
764
|
-
);
|
|
765
|
-
if (sub_idx < 0) {
|
|
766
|
-
this.subs[table_name]![condition]!.subs.push(newSub);
|
|
767
|
-
if (socket) {
|
|
768
|
-
const chnUnsub = channel_name + "unsubscribe";
|
|
769
|
-
socket.removeAllListeners(chnUnsub);
|
|
770
|
-
socket.once(chnUnsub, (_data: any, cb: BasicCallback) => {
|
|
771
|
-
const res = this.onSocketDisconnected(socket, channel_name);
|
|
772
|
-
cb(null, { res });
|
|
773
|
-
});
|
|
774
|
-
}
|
|
775
|
-
} else {
|
|
776
|
-
this.subs[table_name]![condition]!.subs[sub_idx] = newSub;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
if (isReadyOverride ?? is_ready) {
|
|
780
|
-
this.pushSubData(newSub);
|
|
781
|
-
}
|
|
782
|
-
};
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
viewOptions?.relatedTables.map(async (relatedTable, relatedTableIdx) => {
|
|
787
|
-
|
|
788
|
-
const params: Omit<Parameters<typeof upsertSub>[0], "is_ready"> = {
|
|
789
|
-
table_name: relatedTable.tableName,
|
|
790
|
-
condition: relatedTable.condition,
|
|
791
|
-
parentSubParams: {
|
|
792
|
-
...subscriptionParams,
|
|
793
|
-
channel_name
|
|
794
|
-
},
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
upsertSub({
|
|
798
|
-
...params,
|
|
799
|
-
is_ready: false,
|
|
800
|
-
|
|
801
|
-
}, false);
|
|
802
|
-
|
|
803
|
-
await this.addTrigger(params, viewOptions);
|
|
804
|
-
|
|
805
|
-
/** Trigger pushSubData only on last related table (if it's a view) to prevent duplicate firings */
|
|
806
|
-
const isLast = relatedTableIdx === viewOptions.relatedTables.length - 1;
|
|
807
|
-
upsertSub({
|
|
808
|
-
...params,
|
|
809
|
-
is_ready: true
|
|
810
|
-
}, isLast && !table_info.is_view);
|
|
811
|
-
|
|
812
|
-
});
|
|
813
|
-
|
|
814
|
-
if (table_info.is_view) {
|
|
815
|
-
if(!viewOptions?.relatedTables.length){
|
|
816
|
-
throw "PubSubManager: view parent_tables missing";
|
|
817
|
-
}
|
|
818
|
-
return channel_name;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
/* Just a table, add table + condition trigger */
|
|
822
|
-
// console.log(table_info, 202);
|
|
823
|
-
|
|
824
|
-
upsertSub({
|
|
825
|
-
table_name: table_info.name,
|
|
826
|
-
condition: parseCondition(condition),
|
|
827
|
-
parentSubParams: undefined,
|
|
828
|
-
is_ready: false
|
|
829
|
-
}, undefined);
|
|
830
|
-
|
|
831
|
-
await this.addTrigger({
|
|
832
|
-
table_name: table_info.name,
|
|
833
|
-
condition: parseCondition(condition),
|
|
834
|
-
});
|
|
835
|
-
|
|
836
|
-
upsertSub({
|
|
837
|
-
table_name: table_info.name,
|
|
838
|
-
condition: parseCondition(condition),
|
|
839
|
-
parentSubParams: undefined,
|
|
840
|
-
is_ready: true
|
|
841
|
-
}, undefined);
|
|
842
|
-
|
|
843
|
-
return channel_name;
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
removeLocalSub(table_name: string, condition: string, func: (items: object[]) => any) {
|
|
847
|
-
const cond = parseCondition(condition);
|
|
848
|
-
if (get(this.subs, [table_name, cond, "subs"])) {
|
|
849
|
-
this.subs[table_name]![cond]!.subs.map((sub, i) => {
|
|
850
|
-
if (
|
|
851
|
-
sub.func && sub.func === func
|
|
852
|
-
) {
|
|
853
|
-
this.subs[table_name]![cond]!.subs.splice(i, 1);
|
|
854
|
-
}
|
|
855
|
-
});
|
|
856
|
-
} else {
|
|
857
|
-
console.error("Could not unsubscribe. Subscription might not have initialised yet")
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
463
|
|
|
861
464
|
getActiveListeners = (): { table_name: string; condition: string }[] => {
|
|
862
465
|
const result: { table_name: string; condition: string }[] = [];
|
|
@@ -868,72 +471,16 @@ export class PubSubManager {
|
|
|
868
471
|
(this.syncs || []).map(s => {
|
|
869
472
|
upsert(s.table_name, s.condition)
|
|
870
473
|
});
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
}
|
|
474
|
+
|
|
475
|
+
this.subs.forEach(s => {
|
|
476
|
+
s.triggers.forEach(trg => {
|
|
477
|
+
upsert(trg.table_name, trg.condition);
|
|
876
478
|
});
|
|
877
479
|
});
|
|
878
480
|
|
|
879
481
|
return result;
|
|
880
482
|
}
|
|
881
483
|
|
|
882
|
-
onSocketDisconnected(socket?: PRGLIOSocket, channel_name?: string) {
|
|
883
|
-
// process.on('warning', e => {
|
|
884
|
-
// console.warn(e.stack)
|
|
885
|
-
// });
|
|
886
|
-
// console.log("onSocketDisconnected", channel_name, this.syncs)
|
|
887
|
-
if (this.subs) {
|
|
888
|
-
Object.keys(this.subs).map(table_name => {
|
|
889
|
-
Object.keys(this.subs[table_name]!).map(condition => {
|
|
890
|
-
this.subs[table_name]![condition]!.subs.map((sub, i) => {
|
|
891
|
-
|
|
892
|
-
/**
|
|
893
|
-
* If a channel name is specified then delete triggers
|
|
894
|
-
*/
|
|
895
|
-
if (
|
|
896
|
-
(socket && sub.socket_id === socket.id) &&
|
|
897
|
-
(!channel_name || sub.channel_name === channel_name)
|
|
898
|
-
) {
|
|
899
|
-
this.subs[table_name]![condition]!.subs.splice(i, 1);
|
|
900
|
-
if (!this.subs[table_name]![condition]!.subs.length) {
|
|
901
|
-
delete this.subs[table_name]![condition];
|
|
902
|
-
|
|
903
|
-
if (isEmpty(this.subs[table_name])) {
|
|
904
|
-
delete this.subs[table_name];
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
});
|
|
909
|
-
})
|
|
910
|
-
});
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
if (this.syncs) {
|
|
914
|
-
this.syncs = this.syncs.filter(s => {
|
|
915
|
-
const matchesSocket = Boolean(socket && s.socket_id !== socket.id)
|
|
916
|
-
if (channel_name) {
|
|
917
|
-
return matchesSocket || s.channel_name !== channel_name
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
return matchesSocket;
|
|
921
|
-
});
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
if (!socket) {
|
|
925
|
-
// Do nothing
|
|
926
|
-
} else if (!channel_name) {
|
|
927
|
-
delete this.sockets[socket.id];
|
|
928
|
-
} else {
|
|
929
|
-
socket.removeAllListeners(channel_name);
|
|
930
|
-
socket.removeAllListeners(channel_name + "unsync");
|
|
931
|
-
socket.removeAllListeners(channel_name + "unsubscribe");
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
return "ok";
|
|
935
|
-
}
|
|
936
|
-
|
|
937
484
|
|
|
938
485
|
checkIfTimescaleBug = async (table_name: string) => {
|
|
939
486
|
const schema = "_timescaledb_catalog",
|
|
@@ -1037,6 +584,6 @@ export class PubSubManager {
|
|
|
1037
584
|
}
|
|
1038
585
|
|
|
1039
586
|
|
|
1040
|
-
const parseCondition = (condition: string): string => condition && condition.trim().length ? condition : "TRUE"
|
|
587
|
+
export const parseCondition = (condition: string): string => condition && condition.trim().length ? condition : "TRUE"
|
|
1041
588
|
|
|
1042
589
|
export { pickKeys, omitKeys } from "prostgles-types"
|