prostgles-server 4.2.534 → 4.2.537

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 (64) hide show
  1. package/dist/Auth/AuthHandler.js +1 -1
  2. package/dist/Auth/AuthHandler.js.map +1 -1
  3. package/dist/Auth/getClientAuth.js +2 -2
  4. package/dist/Auth/getClientAuth.js.map +1 -1
  5. package/dist/DboBuilder/DboBuilder.d.ts +1 -1
  6. package/dist/DboBuilder/DboBuilderTypes.d.ts +3 -1
  7. package/dist/DboBuilder/DboBuilderTypes.d.ts.map +1 -1
  8. package/dist/DboBuilder/TableHandler/TableHandler.d.ts +3 -1
  9. package/dist/DboBuilder/TableHandler/TableHandler.d.ts.map +1 -1
  10. package/dist/DboBuilder/TableHandler/TableHandler.js +20 -6
  11. package/dist/DboBuilder/TableHandler/TableHandler.js.map +1 -1
  12. package/dist/DboBuilder/runSql/runSqlUtils.d.ts +1 -1
  13. package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.d.ts.map +1 -1
  14. package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.js +0 -4
  15. package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.js.map +1 -1
  16. package/dist/JSONBSchemaValidation/validateJSONBSchemaSQL.d.ts +1 -1
  17. package/dist/Logging.d.ts +4 -1
  18. package/dist/Logging.d.ts.map +1 -1
  19. package/dist/PubSubManager/PubSubManager.d.ts +5 -4
  20. package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
  21. package/dist/PubSubManager/PubSubManager.js +4 -2
  22. package/dist/PubSubManager/PubSubManager.js.map +1 -1
  23. package/dist/PubSubManager/SyncReplication/fetchSyncServerData.d.ts +11 -0
  24. package/dist/PubSubManager/SyncReplication/fetchSyncServerData.d.ts.map +1 -0
  25. package/dist/PubSubManager/SyncReplication/fetchSyncServerData.js +25 -0
  26. package/dist/PubSubManager/SyncReplication/fetchSyncServerData.js.map +1 -0
  27. package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.d.ts +14 -0
  28. package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.d.ts.map +1 -0
  29. package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.js +19 -0
  30. package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.js.map +1 -0
  31. package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.d.ts +8 -0
  32. package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.d.ts.map +1 -0
  33. package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.js +9 -0
  34. package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.js.map +1 -0
  35. package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.d.ts +40 -0
  36. package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.d.ts.map +1 -0
  37. package/dist/{SyncReplication.js → PubSubManager/SyncReplication/getSyncUtilFunctions.js} +84 -214
  38. package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.js.map +1 -0
  39. package/dist/{SyncReplication.d.ts → PubSubManager/SyncReplication/syncData.d.ts} +4 -4
  40. package/dist/PubSubManager/SyncReplication/syncData.d.ts.map +1 -0
  41. package/dist/PubSubManager/SyncReplication/syncData.js +131 -0
  42. package/dist/PubSubManager/SyncReplication/syncData.js.map +1 -0
  43. package/dist/PubSubManager/addSync.d.ts.map +1 -1
  44. package/dist/PubSubManager/addSync.js +15 -10
  45. package/dist/PubSubManager/addSync.js.map +1 -1
  46. package/dist/WebsocketAPI/onSocketConnected.js +1 -1
  47. package/dist/WebsocketAPI/onSocketConnected.js.map +1 -1
  48. package/lib/Auth/AuthHandler.ts +1 -1
  49. package/lib/Auth/getClientAuth.ts +2 -2
  50. package/lib/DboBuilder/DboBuilderTypes.ts +2 -1
  51. package/lib/DboBuilder/TableHandler/TableHandler.ts +26 -8
  52. package/lib/DboBuilder/schema/getTablesForSchemaPostgresSQL.ts +0 -4
  53. package/lib/Logging.ts +13 -1
  54. package/lib/PubSubManager/PubSubManager.ts +7 -5
  55. package/lib/PubSubManager/SyncReplication/fetchSyncServerData.ts +55 -0
  56. package/lib/PubSubManager/SyncReplication/getSyncBatchOptions.ts +31 -0
  57. package/lib/PubSubManager/SyncReplication/getSyncOrderByAndFields.ts +11 -0
  58. package/lib/{SyncReplication.ts → PubSubManager/SyncReplication/getSyncUtilFunctions.ts} +144 -310
  59. package/lib/PubSubManager/SyncReplication/syncData.ts +194 -0
  60. package/lib/PubSubManager/addSync.ts +19 -20
  61. package/lib/WebsocketAPI/onSocketConnected.ts +7 -7
  62. package/package.json +2 -2
  63. package/dist/SyncReplication.d.ts.map +0 -1
  64. package/dist/SyncReplication.js.map +0 -1
@@ -1,98 +1,44 @@
1
- import type { AnyObject, OrderBy, SyncBatchParams } from "prostgles-types";
2
- import { WAL, omitKeys, pickKeys } from "prostgles-types";
3
- import type { TableHandler } from "./DboBuilder/TableHandler/TableHandler";
4
- import type { PubSubManager, SyncParams } from "./PubSubManager/PubSubManager";
5
- import { log } from "./PubSubManager/PubSubManagerUtils";
6
-
7
- export type ClientSyncInfo = Partial<{
8
- c_fr: AnyObject;
9
- c_lr: AnyObject;
10
- /**
11
- * PG count is ussually string due to bigint
12
- */
13
- c_count: number | string;
14
- }>;
15
-
16
- export type ServerSyncInfo = Partial<{
17
- s_fr: AnyObject;
18
- s_lr: AnyObject;
19
- /**
20
- * PG count is ussually string due to bigint
21
- */
22
- s_count: number | string;
23
- }>;
24
-
25
- export type SyncBatchInfo = Partial<{
26
- from_synced: number | null;
27
- to_synced: number | null;
28
- end_offset: number | null;
29
- }>;
30
-
31
- export type onSyncRequestResponse =
32
- | {
33
- onSyncRequest?: ClientSyncInfo;
34
- }
35
- | {
36
- err: AnyObject | string;
37
- };
38
-
39
- export type ClientExpressData = ClientSyncInfo & {
40
- data?: AnyObject[];
41
- deleted?: AnyObject[];
1
+ import {
2
+ isDefined,
3
+ omitKeys,
4
+ pickKeys,
5
+ type AnyObject,
6
+ type SyncBatchParams,
7
+ } from "prostgles-types";
8
+ import type { PRGLIOSocket } from "../../DboBuilder/DboBuilder";
9
+ import type { TableHandler } from "../../DboBuilder/TableHandler/TableHandler";
10
+ import { getSyncOrderByAndFields } from "./getSyncOrderByAndFields";
11
+ import type { PubSubManager, SyncParams } from "../PubSubManager";
12
+ import { fetchSyncServerData } from "./fetchSyncServerData";
13
+ import type {
14
+ ClientSyncInfo,
15
+ onSyncRequestResponse,
16
+ ServerSyncInfo,
17
+ SyncBatchInfo,
18
+ } from "./syncData";
19
+ import { log } from "../PubSubManagerUtils";
20
+
21
+ type Args = {
22
+ socket: PRGLIOSocket;
23
+ tableHandler: TableHandler;
24
+ sync: SyncParams;
25
+ pubSubManager: PubSubManager;
42
26
  };
43
27
 
44
- function getNumbers(numberArr: (null | undefined | string | number)[]): number[] {
45
- return numberArr.filter((v) => v !== null && v !== undefined && Number.isFinite(+v)) as number[];
46
- }
47
-
48
- /**
49
- * Server or client requested data sync
50
- */
51
- export async function syncData(
52
- this: PubSubManager,
53
- sync: SyncParams,
54
- clientData: ClientExpressData | undefined,
55
- source: "trigger" | "client",
56
- ) {
57
- await this._log({
58
- type: "sync",
59
- command: "syncData",
60
- tableName: sync.table_name,
61
- sid: sync.sid,
62
- source,
63
- ...pickKeys(sync, ["socket_id", "condition", "last_synced", "is_syncing"]),
64
- lr: JSON.stringify(sync.lr),
65
- connectedSocketIds: this.dboBuilder.prostgles.connectedSockets.map((s) => s.id),
66
- localParams: undefined,
67
- duration: -1,
68
- socketId: sync.socket_id,
69
- });
70
-
28
+ export const getSyncUtilFunctions = ({ socket, tableHandler, sync, pubSubManager }: Args) => {
71
29
  const {
30
+ synced_field,
72
31
  socket_id,
73
- channel_name,
74
- table_name,
32
+ id_fields,
75
33
  filter,
76
34
  table_rules,
77
- params,
78
- synced_field,
79
- id_fields = [],
80
35
  batch_size,
81
- wal,
82
- throttle = 0,
36
+ channel_name,
37
+ table_name,
38
+ params,
83
39
  } = sync;
84
40
 
85
- const socket = this.sockets[socket_id];
86
- if (!socket) {
87
- return;
88
- }
89
- const tableHandler = this.dbo[table_name];
90
- if (!tableHandler?.find) {
91
- throw `dbo.${table_name}.find missing or not allowed`;
92
- }
93
-
94
- const sync_fields = [synced_field, ...id_fields.sort()],
95
- orderByAsc: OrderBy = sync_fields.reduce((a, v) => ({ ...a, [v]: true }), {}),
41
+ const { orderByAsc, sync_fields } = getSyncOrderByAndFields({ synced_field, id_fields }),
96
42
  rowsIdsMatch = (a?: AnyObject, b?: AnyObject) => {
97
43
  return a && b && !id_fields.find((key) => a[key].toString() !== b[key].toString());
98
44
  },
@@ -100,30 +46,31 @@ export async function syncData(
100
46
  return rowsIdsMatch(a, b) && a?.[synced_field].toString() === b?.[synced_field].toString();
101
47
  },
102
48
  getServerRowInfo = async (args: SyncBatchParams = {}): Promise<ServerSyncInfo> => {
103
- const { from_synced = null, to_synced = null, offset = 0, limit } = args;
104
- const _filter: AnyObject = { ...filter };
49
+ const { from_synced, to_synced, offset = 0, limit } = args;
50
+ const batchFilter = { ...filter };
105
51
 
106
- if (from_synced || to_synced) {
107
- _filter[synced_field] = {
108
- ...(from_synced ? { $gte: from_synced } : {}),
109
- ...(to_synced ? { $lte: to_synced } : {}),
52
+ if (isDefined(from_synced) || isDefined(to_synced)) {
53
+ batchFilter[synced_field] = {
54
+ ...(isDefined(from_synced) ? { $gte: from_synced } : {}),
55
+ ...(isDefined(to_synced) ? { $lte: to_synced } : {}),
110
56
  };
111
57
  }
112
58
 
113
- const first_rows = await tableHandler.find(
114
- _filter,
59
+ const first_rows = (await tableHandler.find(
60
+ batchFilter,
115
61
  { orderBy: orderByAsc, select: sync_fields, limit, offset },
116
62
  undefined,
117
63
  table_rules,
118
64
  { clientReq: { socket } },
119
- );
65
+ )) as AnyObject[];
66
+
120
67
  const last_rows = first_rows.slice(-1); // Why not logic below?
121
68
  // const last_rows = await _this?.dbo[table_name]?.find?.(_filter, { orderBy: (orderByDesc as OrderBy), select: sync_fields, limit: 1, offset: -offset || 0 }, null, table_rules);
122
- const count = await tableHandler.count(_filter, undefined, undefined, table_rules);
69
+ const count = await tableHandler.count(batchFilter, undefined, undefined, table_rules);
123
70
 
124
71
  return {
125
- s_fr: first_rows[0] || null,
126
- s_lr: last_rows[0] || null,
72
+ s_fr: first_rows[0],
73
+ s_lr: last_rows[0],
127
74
  s_count: count,
128
75
  };
129
76
  },
@@ -183,30 +130,10 @@ export async function syncData(
183
130
  }
184
131
  },
185
132
  getServerData = async (from_synced = 0, offset = 0): Promise<AnyObject[]> => {
186
- const _filter = {
187
- ...filter,
188
- [synced_field]: { $gte: from_synced || 0 },
189
- };
190
-
191
- try {
192
- const res = await tableHandler.find(
193
- _filter,
194
- {
195
- select: params.select,
196
- orderBy: orderByAsc as OrderBy,
197
- offset: offset || 0,
198
- limit: batch_size,
199
- },
200
- undefined,
201
- table_rules,
202
- { clientReq: { socket } },
203
- );
204
-
205
- return res;
206
- } catch (e) {
207
- console.error("Sync getServerData failed: ", e);
208
- throw "INTERNAL ERROR";
209
- }
133
+ return fetchSyncServerData(
134
+ { tableHandler, socket, from_synced, offset },
135
+ { filter, id_fields, params, synced_field, batch_size, table_rules },
136
+ );
210
137
  },
211
138
  deleteData = async (deleted: AnyObject[]) => {
212
139
  // console.log("deleteData deleteData deleteData " + deleted.length);
@@ -215,7 +142,7 @@ export async function syncData(
215
142
  // deleted.map(async (d) => {
216
143
  // const id_filter = pickKeys(d, id_fields);
217
144
  // try {
218
- // await (this.dbo[table_name] as TableHandler).delete(
145
+ // await (pubSubManager.dbo[table_name] as TableHandler).delete(
219
146
  // id_filter,
220
147
  // undefined,
221
148
  // undefined,
@@ -238,66 +165,59 @@ export async function syncData(
238
165
  */
239
166
  upsertData = async (data: AnyObject[]) => {
240
167
  const start = Date.now();
241
- const result = await this.dboBuilder
168
+ const result = await pubSubManager.dboBuilder
242
169
  .getTX(async (dbTX) => {
243
170
  const tableHandlerTx = dbTX[table_name] as TableHandler;
244
171
  const existingData = await tableHandlerTx.find(
245
172
  { $or: data.map((d) => pickKeys(d, id_fields)) },
246
173
  {
247
174
  select: [synced_field, ...id_fields],
248
- orderBy: orderByAsc as OrderBy,
175
+ orderBy: orderByAsc,
249
176
  },
250
177
  undefined,
251
178
  table_rules,
252
179
  { clientReq: { socket } },
253
180
  );
254
- let inserts = data.filter((d) => !existingData.find((ed) => rowsIdsMatch(ed, d)));
255
- let updates = data.filter((d) =>
256
- existingData.find((ed) => rowsIdsMatch(ed, d) && +ed[synced_field] < +d[synced_field]),
181
+ let rowsToInsert = data.filter((d) => !existingData.find((ed) => rowsIdsMatch(ed, d)));
182
+ let rowsToUpdate = data.filter((d) =>
183
+ existingData.find(
184
+ (ed) => rowsIdsMatch(ed, d) && Number(ed[synced_field]) < Number(d[synced_field]),
185
+ ),
257
186
  );
258
- try {
259
- if (!table_rules) throw "table_rules missing";
260
-
261
- if (table_rules.update && updates.length) {
262
- const updateData: [any, any][] = [];
263
- await Promise.all(
264
- updates.map((upd) => {
265
- const id_filter = pickKeys(upd, id_fields);
266
- const syncSafeFilter = {
267
- $and: [id_filter, { [synced_field]: { "<": upd[synced_field] } }],
268
- };
269
-
270
- updateData.push([syncSafeFilter, omitKeys(upd, id_fields)]);
271
- }),
272
- );
273
- await tableHandlerTx.updateBatch(
274
- updateData,
275
- { removeDisallowedFields: true },
276
- undefined,
277
- table_rules,
278
- { clientReq: { socket } },
279
- );
280
- } else {
281
- updates = [];
282
- }
283
-
284
- if (table_rules.insert && inserts.length) {
285
- await tableHandlerTx.insert(
286
- inserts,
287
- { removeDisallowedFields: true },
288
- undefined,
289
- table_rules,
290
- { clientReq: { socket } },
291
- );
292
- } else {
293
- inserts = [];
294
- }
295
-
296
- return { inserts, updates };
297
- } catch (e) {
298
- console.trace(e);
299
- throw e;
187
+
188
+ if (table_rules.update && rowsToUpdate.length) {
189
+ const batchUpdates: [AnyObject, AnyObject][] = rowsToUpdate.map((rowToUpdate) => {
190
+ const id_filter = pickKeys(rowToUpdate, id_fields);
191
+ const syncSafeFilter = {
192
+ $and: [id_filter, { [synced_field]: { "<": rowToUpdate[synced_field] } }],
193
+ };
194
+
195
+ return [syncSafeFilter, omitKeys(rowToUpdate, id_fields)];
196
+ });
197
+ await tableHandlerTx.updateBatch(
198
+ batchUpdates,
199
+ { removeDisallowedFields: true },
200
+ undefined,
201
+ table_rules,
202
+ { clientReq: { socket } },
203
+ );
204
+ } else {
205
+ rowsToUpdate = [];
206
+ }
207
+
208
+ if (table_rules.insert && rowsToInsert.length) {
209
+ await tableHandlerTx.insert(
210
+ rowsToInsert,
211
+ { removeDisallowedFields: true },
212
+ undefined,
213
+ table_rules,
214
+ { clientReq: { socket } },
215
+ );
216
+ } else {
217
+ rowsToInsert = [];
300
218
  }
219
+
220
+ return { inserts: rowsToInsert, updates: rowsToUpdate };
301
221
  })
302
222
  .then(({ inserts, updates }) => {
303
223
  log(
@@ -318,15 +238,17 @@ export async function syncData(
318
238
  return Promise.reject(new Error("Something went wrong with syncing to server: "));
319
239
  });
320
240
 
321
- await this._log({
241
+ await pubSubManager._log({
322
242
  type: "sync",
323
243
  command: "upsertData",
244
+ channelName: channel_name,
324
245
  tableName: sync.table_name,
325
246
  rows: data.length,
326
247
  socketId: socket_id,
327
248
  sid: sync.sid,
328
249
  duration: Date.now() - start,
329
- connectedSocketIds: this.dboBuilder.prostgles.connectedSockets.map((s) => s.id),
250
+ connectedSocketIds: pubSubManager.dboBuilder.prostgles.connectedSockets.map((s) => s.id),
251
+ syncParams: sync,
330
252
  });
331
253
 
332
254
  return result;
@@ -335,13 +257,18 @@ export async function syncData(
335
257
  * Pushes the given data to client
336
258
  * @param isSynced = true if
337
259
  */
338
- pushData = async (data?: AnyObject[], isSynced = false, err: unknown = null) => {
260
+ pushData = async (data: AnyObject[], isSynced = false) => {
339
261
  const start = Date.now();
340
- const result = await new Promise((resolve, reject) => {
262
+ const result = await new Promise<{
263
+ pushed: number;
264
+ resp: {
265
+ ok: boolean;
266
+ };
267
+ }>((resolve, reject) => {
341
268
  socket.emit(channel_name, { data, isSynced }, (resp?: { ok: boolean }) => {
342
269
  if (resp && resp.ok) {
343
270
  // console.log("PUSHED to client: fr/lr", data[0], data[data.length - 1]);
344
- resolve({ pushed: data?.length, resp });
271
+ resolve({ pushed: data.length, resp });
345
272
  } else {
346
273
  reject(resp);
347
274
  console.error("Unexpected response");
@@ -349,15 +276,17 @@ export async function syncData(
349
276
  });
350
277
  });
351
278
 
352
- await this._log({
279
+ await pubSubManager._log({
353
280
  type: "sync",
354
281
  command: "pushData",
355
282
  tableName: sync.table_name,
356
- rows: data?.length ?? 0,
283
+ rows: data.length,
357
284
  socketId: socket_id,
358
285
  duration: Date.now() - start,
359
286
  sid: sync.sid,
360
- connectedSocketIds: this.dboBuilder.prostgles.connectedSockets.map((s) => s.id),
287
+ connectedSocketIds: pubSubManager.dboBuilder.prostgles.connectedSockets.map((s) => s.id),
288
+ channelName: channel_name,
289
+ syncParams: sync,
361
290
  });
362
291
 
363
292
  return result;
@@ -416,7 +345,7 @@ export async function syncData(
416
345
  sync_fields.map((key) => {
417
346
  _filter[key] = c_lr[key];
418
347
  });
419
- server_row = await this.dbo[table_name]?.find(
348
+ server_row = await tableHandler.find(
420
349
  _filter,
421
350
  { select: sync_fields, limit: 1 },
422
351
  undefined,
@@ -443,20 +372,21 @@ export async function syncData(
443
372
 
444
373
  return result;
445
374
  },
446
- updateSyncLR = (data: AnyObject) => {
447
- if (data.length) {
448
- const lastRow = data[data.length - 1];
449
- if (sync.lr?.[synced_field] && +sync.lr[synced_field] > +lastRow[synced_field]) {
450
- console.error(
451
- {
452
- syncIssue: "sync.lr[synced_field] is greater than lastRow[synced_field]",
453
- },
454
- sync.table_name,
455
- );
456
- }
457
- sync.lr = lastRow;
458
- sync.last_synced = +sync.lr?.[synced_field];
375
+ updateSyncLR = (data: AnyObject[]) => {
376
+ const lastRow = data.at(-1);
377
+ if (!lastRow) {
378
+ return;
379
+ }
380
+ if (sync.lr?.[synced_field] && +sync.lr[synced_field] > +lastRow[synced_field]) {
381
+ console.error(
382
+ {
383
+ syncIssue: "sync.lr[synced_field] is greater than lastRow[synced_field]",
384
+ },
385
+ sync.table_name,
386
+ );
459
387
  }
388
+ sync.lr = lastRow;
389
+ sync.last_synced = +sync.lr[synced_field];
460
390
  },
461
391
  /**
462
392
  * Will push pull sync between client and server from a given from_synced value
@@ -465,8 +395,7 @@ export async function syncData(
465
395
  let offset = 0,
466
396
  canContinue = true;
467
397
  const limit = batch_size,
468
- min_synced = from_synced || 0,
469
- max_synced = from_synced;
398
+ min_synced = from_synced || 0;
470
399
 
471
400
  let inserted = 0,
472
401
  updated = 0,
@@ -490,7 +419,7 @@ export async function syncData(
490
419
  serverData = await getServerData(min_synced, offset);
491
420
  } catch (e) {
492
421
  console.trace("sync getServerData err", e);
493
- await pushData(undefined, undefined, "Internal error. Check server logs");
422
+ // await pushData(undefined, undefined, "Internal error. Check server logs");
494
423
  throw " d";
495
424
  }
496
425
 
@@ -503,7 +432,7 @@ export async function syncData(
503
432
  // await Promise.all(
504
433
  // to_delete.map((d) => {
505
434
  // deleted++;
506
- // return (this.dbo[table_name] as TableHandler).delete(
435
+ // return (pubSubManager.dbo[table_name] as TableHandler).delete(
507
436
  // pickKeys(d, id_fields),
508
437
  // {},
509
438
  // undefined,
@@ -520,7 +449,7 @@ export async function syncData(
520
449
  );
521
450
  });
522
451
  if (forClient.length) {
523
- const res: any = await pushData(
452
+ const res = await pushData(
524
453
  forClient.filter((d) => !sync.wal || !sync.wal.isInHistory(d)),
525
454
  );
526
455
  pushed += res.pushed;
@@ -532,9 +461,7 @@ export async function syncData(
532
461
  }
533
462
  offset += serverData.length;
534
463
 
535
- // canContinue = offset >= limit;
536
464
  canContinue = serverData.length >= limit;
537
- // console.log(`sData ${sData.length} limit ${limit}`);
538
465
  }
539
466
  log(
540
467
  `server.syncBatch ${table_name}: inserted( ${inserted} ) updated( ${updated} ) deleted( ${deleted} ) pushed to client( ${pushed} ) total( ${total} )`,
@@ -544,115 +471,22 @@ export async function syncData(
544
471
  return true;
545
472
  };
546
473
 
547
- if (!wal) {
548
- /* Used to throttle and merge incomming updates */
549
- sync.wal = new WAL({
550
- id_fields,
551
- synced_field,
552
- throttle,
553
- batch_size,
554
- DEBUG_MODE: this.dboBuilder.prostgles.opts.DEBUG_MODE,
555
- onSendStart: () => {
556
- sync.is_syncing = true;
557
- },
558
- onSend: async (data) => {
559
- // console.log("WAL upsertData START", data)
560
- const res = await upsertData(data);
561
- // const max_incoming_synced = Math.max(...data.map(d => +d[synced_field]));
562
- // if(Number.isFinite(max_incoming_synced) && max_incoming_synced > +sync.last_synced){
563
- // sync.last_synced = max_incoming_synced;
564
- // }
565
- // console.log("WAL upsertData END")
566
-
567
- /******** */
568
- /* TO DO -> Store and push patch updates instead of full data if and where possible */
569
- /******** */
570
- // 1. Store successfully upserted wal items for a couple of seconds
571
- // 2. When pushing data to clients check if any matching wal items exist
572
- // 3. Replace text fields with matching patched data
573
-
574
- return res;
575
- },
576
- onSendEnd: (batch) => {
577
- updateSyncLR(batch);
578
- sync.is_syncing = false;
579
- // console.log("syncData from WAL.onSendEnd")
580
-
581
- /**
582
- * After all data was inserted request SyncInfo from client and sync again if necessary
583
- */
584
- void this.syncData(sync, undefined, source);
585
- },
586
- });
587
- }
588
-
589
- /* Debounce sync requests */
590
- if (!sync.wal) throw "sync.wal missing";
591
- if (!sync.wal.isSending() && sync.is_syncing) {
592
- if (!this.syncTimeout) {
593
- this.syncTimeout = setTimeout(() => {
594
- this.syncTimeout = undefined;
595
- // console.log("SYNC FROM TIMEOUT")
596
- void this.syncData(sync, undefined, source);
597
- }, throttle);
598
- }
599
- // console.log("SYNC THROTTLE")
600
- return;
601
- }
602
-
603
- // console.log("syncData", clientData)
604
-
605
- /**
606
- * Express data sent from a client that has already been synced
607
- * Add to WAL manager which will sync at the end
608
- */
609
- if (clientData) {
610
- if (clientData.data && Array.isArray(clientData.data) && clientData.data.length) {
611
- return sync.wal.addData(clientData.data.map((d) => ({ current: d })));
612
-
613
- // await upsertData(clientData.data, true);
614
-
615
- /* Not expecting this anymore. use normal db.table.delete channel */
616
- } else if (
617
- clientData.deleted &&
618
- Array.isArray(clientData.deleted) &&
619
- clientData.deleted.length
620
- ) {
621
- await deleteData(clientData.deleted);
622
- }
623
- } else {
624
- // do nothing
625
- }
626
- if (sync.wal.isSending()) return;
627
-
628
- sync.is_syncing = true;
629
-
630
- // from synced does not make sense. It should be sync.lr only!!!
631
- let from_synced = null;
632
-
633
- /** Sync was already synced */
634
- if (sync.lr) {
635
- const { s_lr } = await getServerRowInfo();
636
-
637
- /* Make sure trigger is not firing on freshly synced data */
638
- if (!rowsFullyMatch(sync.lr, s_lr)) {
639
- from_synced = sync.last_synced;
640
- } else {
641
- // console.log("rowsFullyMatch")
642
- }
643
- // console.log(table_name, sync.lr[synced_field])
644
- } else {
645
- from_synced = await getLastSynced(clientData);
646
- }
647
-
648
- if (from_synced !== null) {
649
- await syncBatch(from_synced);
650
- } else {
651
- // console.log("from_synced is null")
652
- }
653
-
654
- await pushData([], true);
655
-
656
- sync.is_syncing = false;
657
- // console.log(`Finished sync for ${table_name}`, socket._user);
474
+ return {
475
+ rowsIdsMatch,
476
+ rowsFullyMatch,
477
+ getServerRowInfo,
478
+ getClientRowInfo,
479
+ getClientData,
480
+ getServerData,
481
+ deleteData,
482
+ upsertData,
483
+ pushData,
484
+ getLastSynced,
485
+ updateSyncLR,
486
+ syncBatch,
487
+ };
488
+ };
489
+
490
+ function getNumbers(numberArr: (null | undefined | string | number)[]): number[] {
491
+ return numberArr.filter((v) => v !== null && v !== undefined && Number.isFinite(+v)) as number[];
658
492
  }