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.
- package/dist/DboBuilder/DboBuilder.d.ts +1 -1
- package/dist/DboBuilder/DboBuilderTypes.d.ts +3 -1
- package/dist/DboBuilder/DboBuilderTypes.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/TableHandler.d.ts +3 -1
- package/dist/DboBuilder/TableHandler/TableHandler.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/TableHandler.js +20 -6
- package/dist/DboBuilder/TableHandler/TableHandler.js.map +1 -1
- package/dist/DboBuilder/runSql/runSqlUtils.d.ts +1 -1
- package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.d.ts.map +1 -1
- package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.js +0 -4
- package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.js.map +1 -1
- package/dist/JSONBSchemaValidation/validateJSONBSchemaSQL.d.ts +1 -1
- package/dist/Logging.d.ts +4 -1
- package/dist/Logging.d.ts.map +1 -1
- package/dist/PubSubManager/PubSubManager.d.ts +5 -4
- package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/PubSubManager.js +4 -2
- package/dist/PubSubManager/PubSubManager.js.map +1 -1
- package/dist/PubSubManager/SyncReplication/fetchSyncServerData.d.ts +11 -0
- package/dist/PubSubManager/SyncReplication/fetchSyncServerData.d.ts.map +1 -0
- package/dist/PubSubManager/SyncReplication/fetchSyncServerData.js +25 -0
- package/dist/PubSubManager/SyncReplication/fetchSyncServerData.js.map +1 -0
- package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.d.ts +14 -0
- package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.d.ts.map +1 -0
- package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.js +19 -0
- package/dist/PubSubManager/SyncReplication/getSyncBatchOptions.js.map +1 -0
- package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.d.ts +8 -0
- package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.d.ts.map +1 -0
- package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.js +9 -0
- package/dist/PubSubManager/SyncReplication/getSyncOrderByAndFields.js.map +1 -0
- package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.d.ts +44 -0
- package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.d.ts.map +1 -0
- package/dist/{SyncReplication.js → PubSubManager/SyncReplication/getSyncUtilFunctions.js} +101 -232
- package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.js.map +1 -0
- package/dist/{SyncReplication.d.ts → PubSubManager/SyncReplication/syncData.d.ts} +4 -4
- package/dist/PubSubManager/SyncReplication/syncData.d.ts.map +1 -0
- package/dist/PubSubManager/SyncReplication/syncData.js +132 -0
- package/dist/PubSubManager/SyncReplication/syncData.js.map +1 -0
- package/dist/PubSubManager/addSync.d.ts.map +1 -1
- package/dist/PubSubManager/addSync.js +10 -9
- package/dist/PubSubManager/addSync.js.map +1 -1
- package/lib/DboBuilder/DboBuilderTypes.ts +2 -1
- package/lib/DboBuilder/TableHandler/TableHandler.ts +26 -8
- package/lib/DboBuilder/schema/getTablesForSchemaPostgresSQL.ts +0 -4
- package/lib/Logging.ts +16 -1
- package/lib/PubSubManager/PubSubManager.ts +7 -5
- package/lib/PubSubManager/SyncReplication/fetchSyncServerData.ts +55 -0
- package/lib/PubSubManager/SyncReplication/getSyncBatchOptions.ts +31 -0
- package/lib/PubSubManager/SyncReplication/getSyncOrderByAndFields.ts +11 -0
- package/lib/{SyncReplication.ts → PubSubManager/SyncReplication/getSyncUtilFunctions.ts} +173 -330
- package/lib/PubSubManager/SyncReplication/syncData.ts +195 -0
- package/lib/PubSubManager/addSync.ts +13 -18
- package/package.json +2 -2
- package/dist/SyncReplication.d.ts.map +0 -1
- package/dist/SyncReplication.js.map +0 -1
|
@@ -1,98 +1,52 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
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
|
-
|
|
82
|
-
|
|
44
|
+
channel_name,
|
|
45
|
+
table_name,
|
|
46
|
+
params,
|
|
83
47
|
} = sync;
|
|
84
48
|
|
|
85
|
-
const
|
|
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
|
|
104
|
-
const
|
|
57
|
+
const { from_synced, to_synced, offset = 0, limit } = args;
|
|
58
|
+
const batchFilter = { ...filter };
|
|
105
59
|
|
|
106
|
-
if (from_synced || to_synced) {
|
|
107
|
-
|
|
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
|
-
|
|
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(
|
|
77
|
+
const count = await tableHandler.count(batchFilter, undefined, undefined, table_rules);
|
|
123
78
|
|
|
124
79
|
return {
|
|
125
|
-
s_fr: first_rows[0]
|
|
126
|
-
s_lr: last_rows[0]
|
|
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
|
|
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
|
|
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
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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 (
|
|
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
|
|
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
|
|
182
|
+
orderBy: orderByAsc,
|
|
249
183
|
},
|
|
250
184
|
undefined,
|
|
251
185
|
table_rules,
|
|
252
186
|
{ clientReq: { socket } },
|
|
253
187
|
);
|
|
254
|
-
let
|
|
255
|
-
let
|
|
256
|
-
existingData.find(
|
|
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
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
|
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:
|
|
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
|
|
267
|
+
pushData = async (data: AnyObject[], isSynced = false) => {
|
|
339
268
|
const start = Date.now();
|
|
340
|
-
const result = await new Promise
|
|
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
|
|
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
|
|
286
|
+
await pubSubManager._log({
|
|
353
287
|
type: "sync",
|
|
354
288
|
command: "pushData",
|
|
355
289
|
tableName: sync.table_name,
|
|
356
|
-
rows: data
|
|
290
|
+
rows: data.length,
|
|
357
291
|
socketId: socket_id,
|
|
358
292
|
duration: Date.now() - start,
|
|
359
293
|
sid: sync.sid,
|
|
360
|
-
connectedSocketIds:
|
|
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 (
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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
|
-
|
|
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
|
|
390
|
-
result = (c_fr
|
|
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
|
-
|
|
412
|
-
let
|
|
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
|
-
|
|
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
|
-
|
|
429
|
-
if (
|
|
430
|
-
|
|
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
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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
|
|
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 (
|
|
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
|
|
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
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
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
|
}
|