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.
Files changed (136) hide show
  1. package/dist/AuthHandler.d.ts.map +1 -1
  2. package/dist/AuthHandler.js +6 -3
  3. package/dist/AuthHandler.js.map +1 -1
  4. package/dist/DBEventsManager.d.ts.map +1 -1
  5. package/dist/DBEventsManager.js +5 -4
  6. package/dist/DBEventsManager.js.map +1 -1
  7. package/dist/DBSchemaBuilder.js +14 -14
  8. package/dist/DBSchemaBuilder.js.map +1 -1
  9. package/dist/DboBuilder/QueryBuilder/Functions.js +1 -1
  10. package/dist/DboBuilder/QueryBuilder/Functions.js.map +1 -1
  11. package/dist/DboBuilder/QueryBuilder/makeSelectQuery.js.map +1 -1
  12. package/dist/DboBuilder/TableHandler.js +1 -2
  13. package/dist/DboBuilder/TableHandler.js.map +1 -1
  14. package/dist/DboBuilder/ViewHandler.d.ts.map +1 -1
  15. package/dist/DboBuilder/ViewHandler.js +10 -8
  16. package/dist/DboBuilder/ViewHandler.js.map +1 -1
  17. package/dist/DboBuilder/getCondition.js +1 -1
  18. package/dist/DboBuilder/getCondition.js.map +1 -1
  19. package/dist/DboBuilder/insert.js +1 -1
  20. package/dist/DboBuilder/insert.js.map +1 -1
  21. package/dist/DboBuilder/insertDataParse.js +4 -3
  22. package/dist/DboBuilder/insertDataParse.js.map +1 -1
  23. package/dist/DboBuilder/subscribe.d.ts +2 -2
  24. package/dist/DboBuilder/subscribe.d.ts.map +1 -1
  25. package/dist/DboBuilder/subscribe.js +3 -4
  26. package/dist/DboBuilder/subscribe.js.map +1 -1
  27. package/dist/DboBuilder.d.ts.map +1 -1
  28. package/dist/DboBuilder.js +5 -4
  29. package/dist/DboBuilder.js.map +1 -1
  30. package/dist/FileManager.js +1 -1
  31. package/dist/FileManager.js.map +1 -1
  32. package/dist/Filtering.js.map +1 -1
  33. package/dist/JSONBValidation/validation.js.map +1 -1
  34. package/dist/Prostgles.js +1 -1
  35. package/dist/Prostgles.js.map +1 -1
  36. package/dist/PubSubManager/PubSubManager.d.ts +28 -26
  37. package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
  38. package/dist/PubSubManager/PubSubManager.js +53 -433
  39. package/dist/PubSubManager/PubSubManager.js.map +1 -1
  40. package/dist/PubSubManager/addSub.d.ts +8 -0
  41. package/dist/PubSubManager/addSub.d.ts.map +1 -0
  42. package/dist/PubSubManager/addSub.js +163 -0
  43. package/dist/PubSubManager/addSub.js.map +1 -0
  44. package/dist/PubSubManager/addSync.d.ts +8 -0
  45. package/dist/PubSubManager/addSync.d.ts.map +1 -0
  46. package/dist/PubSubManager/addSync.js +110 -0
  47. package/dist/PubSubManager/addSync.js.map +1 -0
  48. package/dist/PubSubManager/notifListener.d.ts +5 -0
  49. package/dist/PubSubManager/notifListener.d.ts.map +1 -0
  50. package/dist/PubSubManager/notifListener.js +99 -0
  51. package/dist/PubSubManager/notifListener.js.map +1 -0
  52. package/dist/PubSubManager/pushSubData.d.ts +3 -0
  53. package/dist/PubSubManager/pushSubData.d.ts.map +1 -0
  54. package/dist/PubSubManager/pushSubData.js +48 -0
  55. package/dist/PubSubManager/pushSubData.js.map +1 -0
  56. package/dist/PublishParser.d.ts.map +1 -1
  57. package/dist/PublishParser.js +4 -3
  58. package/dist/PublishParser.js.map +1 -1
  59. package/dist/TableConfig/TableConfig.js.map +1 -1
  60. package/dist/TableConfig/getConstraintDefinitionQueries.js.map +1 -1
  61. package/dist/TableConfig/getTableColumnQueries.js.map +1 -1
  62. package/lib/AuthHandler.d.ts.map +1 -1
  63. package/lib/AuthHandler.js +6 -3
  64. package/lib/AuthHandler.ts +12 -7
  65. package/lib/DBEventsManager.d.ts.map +1 -1
  66. package/lib/DBEventsManager.js +5 -4
  67. package/lib/DBEventsManager.ts +10 -9
  68. package/lib/DBSchemaBuilder.js +14 -14
  69. package/lib/DBSchemaBuilder.ts +14 -14
  70. package/lib/DboBuilder/QueryBuilder/Functions.js +1 -1
  71. package/lib/DboBuilder/QueryBuilder/Functions.ts +2 -2
  72. package/lib/DboBuilder/QueryBuilder/makeSelectQuery.ts +1 -1
  73. package/lib/DboBuilder/TableHandler.d.ts +1 -5
  74. package/lib/DboBuilder/TableHandler.d.ts.map +1 -1
  75. package/lib/DboBuilder/TableHandler.js +1 -2
  76. package/lib/DboBuilder/TableHandler.ts +3 -3
  77. package/lib/DboBuilder/ViewHandler.d.ts.map +1 -1
  78. package/lib/DboBuilder/ViewHandler.js +10 -8
  79. package/lib/DboBuilder/ViewHandler.ts +22 -20
  80. package/lib/DboBuilder/getCondition.js +1 -1
  81. package/lib/DboBuilder/getCondition.ts +2 -2
  82. package/lib/DboBuilder/insert.js +1 -1
  83. package/lib/DboBuilder/insert.ts +1 -1
  84. package/lib/DboBuilder/insertDataParse.js +4 -3
  85. package/lib/DboBuilder/insertDataParse.ts +15 -13
  86. package/lib/DboBuilder/subscribe.d.ts +2 -2
  87. package/lib/DboBuilder/subscribe.d.ts.map +1 -1
  88. package/lib/DboBuilder/subscribe.js +3 -4
  89. package/lib/DboBuilder/subscribe.ts +8 -9
  90. package/lib/DboBuilder.d.ts.map +1 -1
  91. package/lib/DboBuilder.js +5 -4
  92. package/lib/DboBuilder.ts +15 -21
  93. package/lib/FileManager.js +1 -1
  94. package/lib/FileManager.ts +5 -5
  95. package/lib/Filtering.ts +1 -1
  96. package/lib/JSONBValidation/validation.ts +3 -3
  97. package/lib/Prostgles.js +1 -1
  98. package/lib/Prostgles.ts +3 -3
  99. package/lib/PubSubManager/PubSubManager.d.ts +27 -29
  100. package/lib/PubSubManager/PubSubManager.d.ts.map +1 -1
  101. package/lib/PubSubManager/PubSubManager.js +54 -437
  102. package/lib/PubSubManager/PubSubManager.ts +93 -546
  103. package/lib/PubSubManager/addSub.d.ts +8 -0
  104. package/lib/PubSubManager/addSub.d.ts.map +1 -0
  105. package/lib/PubSubManager/addSub.js +162 -0
  106. package/lib/PubSubManager/addSub.ts +186 -0
  107. package/lib/PubSubManager/addSync.d.ts +8 -0
  108. package/lib/PubSubManager/addSync.d.ts.map +1 -0
  109. package/lib/PubSubManager/addSync.js +109 -0
  110. package/lib/PubSubManager/addSync.ts +127 -0
  111. package/lib/PubSubManager/notifListener.d.ts +5 -0
  112. package/lib/PubSubManager/notifListener.d.ts.map +1 -0
  113. package/lib/PubSubManager/notifListener.js +98 -0
  114. package/lib/PubSubManager/notifListener.ts +124 -0
  115. package/lib/PubSubManager/pushSubData.d.ts +3 -0
  116. package/lib/PubSubManager/pushSubData.d.ts.map +1 -0
  117. package/lib/PubSubManager/pushSubData.js +47 -0
  118. package/lib/PubSubManager/pushSubData.ts +47 -0
  119. package/lib/PublishParser.d.ts.map +1 -1
  120. package/lib/PublishParser.js +4 -3
  121. package/lib/PublishParser.ts +4 -3
  122. package/lib/TableConfig/TableConfig.ts +7 -7
  123. package/lib/TableConfig/getConstraintDefinitionQueries.ts +1 -1
  124. package/lib/TableConfig/getTableColumnQueries.ts +2 -2
  125. package/package.json +2 -2
  126. package/tests/client/PID.txt +1 -1
  127. package/tests/client/package-lock.json +15 -15
  128. package/tests/client/package.json +1 -1
  129. package/tests/client/tsconfig.json +2 -1
  130. package/tests/client_only_queries.js +1 -1
  131. package/tests/client_only_queries.ts +1 -1
  132. package/tests/isomorphic_queries.ts +1 -1
  133. package/tests/server/DBoGenerated.d.ts +2 -2
  134. package/tests/server/package-lock.json +3 -3
  135. package/tests/server/tsconfig.json +2 -1
  136. package/tsconfig.json +1 -1
@@ -4,7 +4,7 @@
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
 
6
6
  import { PostgresNotifListenManager } from "../PostgresNotifListenManager";
7
- import { get } from "../utils";
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, isEmpty, AnyObject } from "prostgles-types";
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, getKeys } from "prostgles-types/dist/util";
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
- func?: (data: any) => any;
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: any;
138
- subs: { [ke: string]: { [ke: string]: { subs: SubscriptionParams[] } } };
139
- syncs: SyncParams[];
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.onSocketDisconnected();
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): SubscriptionParams[] {
368
- const subs = this.subs?.[table_name]?.[condition]?.subs ?? [];
369
-
370
- // if(!subs){
371
- // log("Subs not found:", { table_name, condition }, this.subs)
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
- return s;
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
- /* Relay relevant data to relevant subscriptions */
401
- notifListener = async (data: { payload: string }) => {
402
- const str = data.payload;
411
+ notifListener = notifListener.bind(this);
403
412
 
404
- if (!str) {
405
- console.error("Empty notif?")
406
- return;
407
- }
408
- const dataArr = str.split(PubSubManager.DELIMITER),
409
- notifType = dataArr[0];
410
-
411
- log(str);
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
- if (notifType !== this.NOTIF_TYPE.data) {
428
- console.error("Unexpected notif type: ", notifType);
429
- return;
430
- }
431
- if(dataArr.length < 3){
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
- const table_name = dataArr[1]!,
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
- conditions.map(condition => {
432
+ pushSubData = pushSubData.bind(this);
475
433
 
476
- const subs = this.getSubs(table_name, condition);
477
- const syncs = this.getSyncs(table_name, condition);
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.map((s) => {
481
- this.syncData(s, undefined, "trigger");
443
+ this.syncs = this.syncs.filter(s => {
444
+ return !(s.socket_id && s.socket_id === socket.id);
482
445
  });
483
446
 
484
- if (!subs) {
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
- /* Throttle the subscriptions */
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
- Object.keys(this.subs || {}).map(table_name => {
872
- Object.keys(this.subs[table_name] || {}).map(condition => {
873
- if (this.subs[table_name]![condition]!.subs.length) {
874
- upsert(table_name, condition);
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"