prostgles-server 4.2.535 → 4.2.538

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 (55) hide show
  1. package/dist/DboBuilder/DboBuilder.d.ts +1 -1
  2. package/dist/DboBuilder/DboBuilderTypes.d.ts +3 -1
  3. package/dist/DboBuilder/DboBuilderTypes.d.ts.map +1 -1
  4. package/dist/DboBuilder/TableHandler/TableHandler.d.ts +3 -1
  5. package/dist/DboBuilder/TableHandler/TableHandler.d.ts.map +1 -1
  6. package/dist/DboBuilder/TableHandler/TableHandler.js +20 -6
  7. package/dist/DboBuilder/TableHandler/TableHandler.js.map +1 -1
  8. package/dist/DboBuilder/runSql/runSqlUtils.d.ts +1 -1
  9. package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.d.ts.map +1 -1
  10. package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.js +0 -4
  11. package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.js.map +1 -1
  12. package/dist/JSONBSchemaValidation/validateJSONBSchemaSQL.d.ts +1 -1
  13. package/dist/Logging.d.ts +4 -1
  14. package/dist/Logging.d.ts.map +1 -1
  15. package/dist/PubSubManager/PubSubManager.d.ts +5 -4
  16. package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
  17. package/dist/PubSubManager/PubSubManager.js +4 -2
  18. package/dist/PubSubManager/PubSubManager.js.map +1 -1
  19. package/dist/PubSubManager/SyncReplication/fetchSyncServerData.d.ts +11 -0
  20. package/dist/PubSubManager/SyncReplication/fetchSyncServerData.d.ts.map +1 -0
  21. package/dist/PubSubManager/SyncReplication/fetchSyncServerData.js +25 -0
  22. package/dist/PubSubManager/SyncReplication/fetchSyncServerData.js.map +1 -0
  23. package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.d.ts +14 -0
  24. package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.d.ts.map +1 -0
  25. package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.js +19 -0
  26. package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.js.map +1 -0
  27. package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.d.ts +8 -0
  28. package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.d.ts.map +1 -0
  29. package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.js +9 -0
  30. package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.js.map +1 -0
  31. package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.d.ts +44 -0
  32. package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.d.ts.map +1 -0
  33. package/dist/{SyncReplication.js → PubSubManager/SyncReplication/getSyncUtilFunctions.js} +101 -232
  34. package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.js.map +1 -0
  35. package/dist/{SyncReplication.d.ts → PubSubManager/SyncReplication/syncData.d.ts} +4 -4
  36. package/dist/PubSubManager/SyncReplication/syncData.d.ts.map +1 -0
  37. package/dist/PubSubManager/SyncReplication/syncData.js +132 -0
  38. package/dist/PubSubManager/SyncReplication/syncData.js.map +1 -0
  39. package/dist/PubSubManager/addSync.d.ts.map +1 -1
  40. package/dist/PubSubManager/addSync.js +10 -9
  41. package/dist/PubSubManager/addSync.js.map +1 -1
  42. package/lib/DboBuilder/DboBuilderTypes.ts +2 -1
  43. package/lib/DboBuilder/TableHandler/TableHandler.ts +26 -8
  44. package/lib/DboBuilder/schema/getTablesForSchemaPostgresSQL.ts +0 -4
  45. package/lib/Logging.ts +16 -1
  46. package/lib/PubSubManager/PubSubManager.ts +7 -5
  47. package/lib/PubSubManager/SyncReplication/fetchSyncServerData.ts +55 -0
  48. package/lib/PubSubManager/SyncReplication/getSyncBatchOptions.ts +31 -0
  49. package/lib/PubSubManager/SyncReplication/getSyncOrderByAndFields.ts +11 -0
  50. package/lib/{SyncReplication.ts → PubSubManager/SyncReplication/getSyncUtilFunctions.ts} +173 -330
  51. package/lib/PubSubManager/SyncReplication/syncData.ts +195 -0
  52. package/lib/PubSubManager/addSync.ts +13 -18
  53. package/package.json +2 -2
  54. package/dist/SyncReplication.d.ts.map +0 -1
  55. package/dist/SyncReplication.js.map +0 -1
@@ -1,98 +1,52 @@
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
+ import type { EventTypes } from "../../Logging";
21
+
22
+ type Args = {
23
+ socket: PRGLIOSocket;
24
+ tableHandler: TableHandler;
25
+ sync: SyncParams;
26
+ pubSubManager: PubSubManager;
27
+ logSyncData: (state: Extract<EventTypes.Sync, { command: "syncData" }>["state"]) => void;
42
28
  };
43
29
 
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
-
30
+ export const getSyncUtilFunctions = ({
31
+ socket,
32
+ tableHandler,
33
+ sync,
34
+ pubSubManager,
35
+ logSyncData,
36
+ }: Args) => {
71
37
  const {
38
+ synced_field,
72
39
  socket_id,
73
- channel_name,
74
- table_name,
40
+ id_fields,
75
41
  filter,
76
42
  table_rules,
77
- params,
78
- synced_field,
79
- id_fields = [],
80
43
  batch_size,
81
- wal,
82
- throttle = 0,
44
+ channel_name,
45
+ table_name,
46
+ params,
83
47
  } = sync;
84
48
 
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 }), {}),
49
+ const { orderByAsc, sync_fields } = getSyncOrderByAndFields({ synced_field, id_fields }),
96
50
  rowsIdsMatch = (a?: AnyObject, b?: AnyObject) => {
97
51
  return a && b && !id_fields.find((key) => a[key].toString() !== b[key].toString());
98
52
  },
@@ -100,30 +54,31 @@ export async function syncData(
100
54
  return rowsIdsMatch(a, b) && a?.[synced_field].toString() === b?.[synced_field].toString();
101
55
  },
102
56
  getServerRowInfo = async (args: SyncBatchParams = {}): Promise<ServerSyncInfo> => {
103
- const { from_synced = null, to_synced = null, offset = 0, limit } = args;
104
- const _filter: AnyObject = { ...filter };
57
+ const { from_synced, to_synced, offset = 0, limit } = args;
58
+ const batchFilter = { ...filter };
105
59
 
106
- if (from_synced || to_synced) {
107
- _filter[synced_field] = {
108
- ...(from_synced ? { $gte: from_synced } : {}),
109
- ...(to_synced ? { $lte: to_synced } : {}),
60
+ if (isDefined(from_synced) || isDefined(to_synced)) {
61
+ batchFilter[synced_field] = {
62
+ ...(isDefined(from_synced) ? { $gte: from_synced } : {}),
63
+ ...(isDefined(to_synced) ? { $lte: to_synced } : {}),
110
64
  };
111
65
  }
112
66
 
113
- const first_rows = await tableHandler.find(
114
- _filter,
67
+ const first_rows = (await tableHandler.find(
68
+ batchFilter,
115
69
  { orderBy: orderByAsc, select: sync_fields, limit, offset },
116
70
  undefined,
117
71
  table_rules,
118
72
  { clientReq: { socket } },
119
- );
73
+ )) as AnyObject[];
74
+
120
75
  const last_rows = first_rows.slice(-1); // Why not logic below?
121
76
  // 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);
77
+ const count = await tableHandler.count(batchFilter, undefined, undefined, table_rules);
123
78
 
124
79
  return {
125
- s_fr: first_rows[0] || null,
126
- s_lr: last_rows[0] || null,
80
+ s_fr: first_rows[0],
81
+ s_lr: last_rows[0],
127
82
  s_count: count,
128
83
  };
129
84
  },
@@ -147,16 +102,15 @@ export async function syncData(
147
102
 
148
103
  return res;
149
104
  },
150
- getClientData = (from_synced = 0, offset = 0): Promise<AnyObject[]> => {
105
+ getClientData = (from_synced: number | undefined, offset = 0): Promise<AnyObject[]> => {
151
106
  return new Promise((resolve, reject) => {
152
107
  const onPullRequest = {
153
- from_synced: from_synced || 0,
108
+ from_synced: from_synced,
154
109
  offset: offset || 0,
155
110
  limit: batch_size,
156
111
  };
157
112
  socket.emit(channel_name, { onPullRequest }, (resp?: { data?: AnyObject[] }) => {
158
113
  if (resp && resp.data && Array.isArray(resp.data)) {
159
- // console.log({ onPullRequest, resp }, socket._user)
160
114
  resolve(sortClientData(resp.data));
161
115
  } else {
162
116
  reject("unexpected onPullRequest response: " + JSON.stringify(resp));
@@ -182,31 +136,11 @@ export async function syncData(
182
136
  });
183
137
  }
184
138
  },
185
- 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
- }
139
+ getServerData = async (from_synced: number | undefined, offset = 0): Promise<AnyObject[]> => {
140
+ return fetchSyncServerData(
141
+ { tableHandler, socket, from_synced, offset },
142
+ { filter, id_fields, params, synced_field, batch_size, table_rules },
143
+ );
210
144
  },
211
145
  deleteData = async (deleted: AnyObject[]) => {
212
146
  // console.log("deleteData deleteData deleteData " + deleted.length);
@@ -215,7 +149,7 @@ export async function syncData(
215
149
  // deleted.map(async (d) => {
216
150
  // const id_filter = pickKeys(d, id_fields);
217
151
  // try {
218
- // await (this.dbo[table_name] as TableHandler).delete(
152
+ // await (pubSubManager.dbo[table_name] as TableHandler).delete(
219
153
  // id_filter,
220
154
  // undefined,
221
155
  // undefined,
@@ -238,66 +172,59 @@ export async function syncData(
238
172
  */
239
173
  upsertData = async (data: AnyObject[]) => {
240
174
  const start = Date.now();
241
- const result = await this.dboBuilder
175
+ const result = await pubSubManager.dboBuilder
242
176
  .getTX(async (dbTX) => {
243
177
  const tableHandlerTx = dbTX[table_name] as TableHandler;
244
178
  const existingData = await tableHandlerTx.find(
245
179
  { $or: data.map((d) => pickKeys(d, id_fields)) },
246
180
  {
247
181
  select: [synced_field, ...id_fields],
248
- orderBy: orderByAsc as OrderBy,
182
+ orderBy: orderByAsc,
249
183
  },
250
184
  undefined,
251
185
  table_rules,
252
186
  { clientReq: { socket } },
253
187
  );
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]),
188
+ let rowsToInsert = data.filter((d) => !existingData.find((ed) => rowsIdsMatch(ed, d)));
189
+ let rowsToUpdate = data.filter((d) =>
190
+ existingData.find(
191
+ (ed) => rowsIdsMatch(ed, d) && Number(ed[synced_field]) < Number(d[synced_field]),
192
+ ),
257
193
  );
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;
194
+
195
+ if (table_rules.update && rowsToUpdate.length) {
196
+ const batchUpdates: [AnyObject, AnyObject][] = rowsToUpdate.map((rowToUpdate) => {
197
+ const id_filter = pickKeys(rowToUpdate, id_fields);
198
+ const syncSafeFilter = {
199
+ $and: [id_filter, { [synced_field]: { "<": rowToUpdate[synced_field] } }],
200
+ };
201
+
202
+ return [syncSafeFilter, omitKeys(rowToUpdate, id_fields)];
203
+ });
204
+ await tableHandlerTx.updateBatch(
205
+ batchUpdates,
206
+ { removeDisallowedFields: true },
207
+ undefined,
208
+ table_rules,
209
+ { clientReq: { socket } },
210
+ );
211
+ } else {
212
+ rowsToUpdate = [];
213
+ }
214
+
215
+ if (table_rules.insert && rowsToInsert.length) {
216
+ await tableHandlerTx.insert(
217
+ rowsToInsert,
218
+ { removeDisallowedFields: true },
219
+ undefined,
220
+ table_rules,
221
+ { clientReq: { socket } },
222
+ );
223
+ } else {
224
+ rowsToInsert = [];
300
225
  }
226
+
227
+ return { inserts: rowsToInsert, updates: rowsToUpdate };
301
228
  })
302
229
  .then(({ inserts, updates }) => {
303
230
  log(
@@ -318,15 +245,17 @@ export async function syncData(
318
245
  return Promise.reject(new Error("Something went wrong with syncing to server: "));
319
246
  });
320
247
 
321
- await this._log({
248
+ await pubSubManager._log({
322
249
  type: "sync",
323
250
  command: "upsertData",
251
+ channelName: channel_name,
324
252
  tableName: sync.table_name,
325
253
  rows: data.length,
326
254
  socketId: socket_id,
327
255
  sid: sync.sid,
328
256
  duration: Date.now() - start,
329
- connectedSocketIds: this.dboBuilder.prostgles.connectedSockets.map((s) => s.id),
257
+ connectedSocketIds: pubSubManager.dboBuilder.prostgles.connectedSockets.map((s) => s.id),
258
+ syncParams: sync,
330
259
  });
331
260
 
332
261
  return result;
@@ -335,13 +264,18 @@ export async function syncData(
335
264
  * Pushes the given data to client
336
265
  * @param isSynced = true if
337
266
  */
338
- pushData = async (data?: AnyObject[], isSynced = false, err: unknown = null) => {
267
+ pushData = async (data: AnyObject[], isSynced = false) => {
339
268
  const start = Date.now();
340
- const result = await new Promise((resolve, reject) => {
269
+ const result = await new Promise<{
270
+ pushed: number;
271
+ resp: {
272
+ ok: boolean;
273
+ };
274
+ }>((resolve, reject) => {
341
275
  socket.emit(channel_name, { data, isSynced }, (resp?: { ok: boolean }) => {
342
276
  if (resp && resp.ok) {
343
277
  // console.log("PUSHED to client: fr/lr", data[0], data[data.length - 1]);
344
- resolve({ pushed: data?.length, resp });
278
+ resolve({ pushed: data.length, resp });
345
279
  } else {
346
280
  reject(resp);
347
281
  console.error("Unexpected response");
@@ -349,15 +283,17 @@ export async function syncData(
349
283
  });
350
284
  });
351
285
 
352
- await this._log({
286
+ await pubSubManager._log({
353
287
  type: "sync",
354
288
  command: "pushData",
355
289
  tableName: sync.table_name,
356
- rows: data?.length ?? 0,
290
+ rows: data.length,
357
291
  socketId: socket_id,
358
292
  duration: Date.now() - start,
359
293
  sid: sync.sid,
360
- connectedSocketIds: this.dboBuilder.prostgles.connectedSockets.map((s) => s.id),
294
+ connectedSocketIds: pubSubManager.dboBuilder.prostgles.connectedSockets.map((s) => s.id),
295
+ channelName: channel_name,
296
+ syncParams: sync,
361
297
  });
362
298
 
363
299
  return result;
@@ -374,20 +310,24 @@ export async function syncData(
374
310
 
375
311
  // console.log("getLastSynced", clientData, socket._user )
376
312
 
377
- let result = null;
313
+ let result: number | null = null;
378
314
 
379
315
  /* Nothing to sync */
380
- if ((!c_fr && !s_fr) || rowsFullyMatch(c_lr, s_lr)) {
381
- // c_count === s_count &&
382
- // sync.last_synced = null;
383
- result = null;
316
+ if (!c_fr && !s_fr) {
317
+ logSyncData("getLastSynced.nothingToSync");
318
+ return null;
319
+ }
320
+
321
+ if (rowsFullyMatch(c_lr, s_lr)) {
322
+ logSyncData("getLastSynced.rowsFullyMatch(lr)");
323
+ return null;
324
+ }
384
325
 
385
- /* Sync Everything */
386
- } else if (!rowsFullyMatch(c_fr, s_fr)) {
326
+ if (!rowsFullyMatch(c_fr, s_fr)) {
387
327
  if (c_fr && s_fr) {
388
328
  result = Math.min(c_fr[synced_field], s_fr[synced_field]);
389
- } else if (c_fr || s_fr) {
390
- result = (c_fr || s_fr)![synced_field];
329
+ } else {
330
+ result = (c_fr ?? s_fr)![synced_field];
391
331
  }
392
332
 
393
333
  /* Sync from last matching synced value */
@@ -408,15 +348,15 @@ export async function syncData(
408
348
  to_synced: result,
409
349
  end_offset,
410
350
  });
411
- // console.log("getLastSynced... end_offset > " + end_offset);
412
- let server_row;
351
+
352
+ let server_rows: AnyObject[] | undefined;
413
353
 
414
354
  if (c_lr) {
415
355
  const _filter: AnyObject = {};
416
356
  sync_fields.map((key) => {
417
357
  _filter[key] = c_lr[key];
418
358
  });
419
- server_row = await this.dbo[table_name]?.find(
359
+ server_rows = await tableHandler.find(
420
360
  _filter,
421
361
  { select: sync_fields, limit: 1 },
422
362
  undefined,
@@ -425,11 +365,9 @@ export async function syncData(
425
365
  );
426
366
  }
427
367
 
428
- // if(rowsFullyMatch(c_lr, s_lr)){ //c_count === s_count &&
429
- if (server_row && server_row.length) {
430
- server_row = server_row[0];
431
-
432
- result = +server_row[synced_field];
368
+ const first_server_row = server_rows?.[0];
369
+ if (first_server_row) {
370
+ result = +first_server_row[synced_field];
433
371
  end_offset = min_count;
434
372
  // console.log(`getLastSynced found for ${table_name} -> ${result}`);
435
373
  } else {
@@ -443,20 +381,21 @@ export async function syncData(
443
381
 
444
382
  return result;
445
383
  },
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];
384
+ updateSyncLR = (data: AnyObject[]) => {
385
+ const lastRow = data.at(-1);
386
+ if (!lastRow) {
387
+ return;
459
388
  }
389
+ if (sync.lr?.[synced_field] && +sync.lr[synced_field] > +lastRow[synced_field]) {
390
+ console.error(
391
+ {
392
+ syncIssue: "sync.lr[synced_field] is greater than lastRow[synced_field]",
393
+ },
394
+ sync.table_name,
395
+ );
396
+ }
397
+ sync.lr = lastRow;
398
+ sync.last_synced = +sync.lr[synced_field];
460
399
  },
461
400
  /**
462
401
  * Will push pull sync between client and server from a given from_synced value
@@ -465,8 +404,7 @@ export async function syncData(
465
404
  let offset = 0,
466
405
  canContinue = true;
467
406
  const limit = batch_size,
468
- min_synced = from_synced || 0,
469
- max_synced = from_synced;
407
+ min_synced = from_synced ?? undefined;
470
408
 
471
409
  let inserted = 0,
472
410
  updated = 0,
@@ -490,7 +428,7 @@ export async function syncData(
490
428
  serverData = await getServerData(min_synced, offset);
491
429
  } catch (e) {
492
430
  console.trace("sync getServerData err", e);
493
- await pushData(undefined, undefined, "Internal error. Check server logs");
431
+ // await pushData(undefined, undefined, "Internal error. Check server logs");
494
432
  throw " d";
495
433
  }
496
434
 
@@ -503,7 +441,7 @@ export async function syncData(
503
441
  // await Promise.all(
504
442
  // to_delete.map((d) => {
505
443
  // deleted++;
506
- // return (this.dbo[table_name] as TableHandler).delete(
444
+ // return (pubSubManager.dbo[table_name] as TableHandler).delete(
507
445
  // pickKeys(d, id_fields),
508
446
  // {},
509
447
  // undefined,
@@ -520,7 +458,7 @@ export async function syncData(
520
458
  );
521
459
  });
522
460
  if (forClient.length) {
523
- const res: any = await pushData(
461
+ const res = await pushData(
524
462
  forClient.filter((d) => !sync.wal || !sync.wal.isInHistory(d)),
525
463
  );
526
464
  pushed += res.pushed;
@@ -532,9 +470,7 @@ export async function syncData(
532
470
  }
533
471
  offset += serverData.length;
534
472
 
535
- // canContinue = offset >= limit;
536
473
  canContinue = serverData.length >= limit;
537
- // console.log(`sData ${sData.length} limit ${limit}`);
538
474
  }
539
475
  log(
540
476
  `server.syncBatch ${table_name}: inserted( ${inserted} ) updated( ${updated} ) deleted( ${deleted} ) pushed to client( ${pushed} ) total( ${total} )`,
@@ -544,115 +480,22 @@ export async function syncData(
544
480
  return true;
545
481
  };
546
482
 
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);
483
+ return {
484
+ rowsIdsMatch,
485
+ rowsFullyMatch,
486
+ getServerRowInfo,
487
+ getClientRowInfo,
488
+ getClientData,
489
+ getServerData,
490
+ deleteData,
491
+ upsertData,
492
+ pushData,
493
+ getLastSynced,
494
+ updateSyncLR,
495
+ syncBatch,
496
+ };
497
+ };
498
+
499
+ function getNumbers(numberArr: (null | undefined | string | number)[]): number[] {
500
+ return numberArr.filter((v) => v !== null && v !== undefined && Number.isFinite(+v)) as number[];
658
501
  }