prostgles-types 4.0.113 → 4.0.115
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/.vscode/settings.json +10 -1
- package/dist/auth.d.ts +21 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/files.d.ts +5 -5
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +13 -1
- package/dist/files.js.map +1 -1
- package/dist/filters.d.ts +82 -14
- package/dist/filters.d.ts.map +1 -1
- package/dist/filters.js +90 -45
- package/dist/filters.js.map +1 -1
- package/dist/index.d.ts +335 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +124 -59
- package/dist/index.js.map +1 -1
- package/dist/insertUpdateUtils.d.ts.map +1 -1
- package/dist/insertUpdateUtils.js +2 -0
- package/dist/insertUpdateUtils.js.map +1 -1
- package/dist/jsonb.d.ts +33 -10
- package/dist/jsonb.d.ts.map +1 -1
- package/dist/jsonb.js +50 -38
- package/dist/jsonb.js.map +1 -1
- package/dist/md5.d.ts.map +1 -1
- package/dist/md5.js +52 -19
- package/dist/md5.js.map +1 -1
- package/dist/replication.d.ts +47 -0
- package/dist/replication.d.ts.map +1 -1
- package/dist/util.d.ts +47 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +122 -65
- package/dist/util.js.map +1 -1
- package/lib/auth.ts +11 -13
- package/lib/files.ts +87 -75
- package/lib/filters.ts +228 -193
- package/lib/index.ts +604 -466
- package/lib/insertUpdateUtils.ts +10 -10
- package/lib/jsonb.ts +242 -205
- package/lib/md5.ts +31 -28
- package/lib/replication.ts +39 -33
- package/lib/util.ts +217 -175
- package/package.json +2 -1
- package/tsconfig.json +1 -1
package/lib/util.ts
CHANGED
|
@@ -2,20 +2,24 @@ import { AnyObject, JoinMaker, JoinPath, TS_COLUMN_DATA_TYPES } from ".";
|
|
|
2
2
|
import { md5 } from "./md5";
|
|
3
3
|
|
|
4
4
|
export function asName(str: string) {
|
|
5
|
-
if (str === null || str === undefined || !str.toString || !str.toString())
|
|
5
|
+
if (str === null || str === undefined || !str.toString || !str.toString())
|
|
6
|
+
throw "Expecting a non empty string";
|
|
6
7
|
|
|
7
8
|
return `"${str.toString().replace(/"/g, `""`)}"`;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
export const pickKeys = <T extends AnyObject, Include extends keyof T>(
|
|
11
|
+
export const pickKeys = <T extends AnyObject, Include extends keyof T>(
|
|
12
|
+
obj: T,
|
|
13
|
+
keys: Include[] = [],
|
|
14
|
+
onlyIfDefined = true
|
|
15
|
+
): Pick<T, Include> => {
|
|
11
16
|
if (!keys.length) {
|
|
12
17
|
return {} as T;
|
|
13
18
|
}
|
|
14
19
|
if (obj && keys.length) {
|
|
15
20
|
let res = {} as T;
|
|
16
|
-
keys.forEach(k => {
|
|
17
|
-
if(onlyIfDefined && obj[k] === undefined){
|
|
18
|
-
|
|
21
|
+
keys.forEach((k) => {
|
|
22
|
+
if (onlyIfDefined && obj[k] === undefined) {
|
|
19
23
|
} else {
|
|
20
24
|
res[k] = obj[k];
|
|
21
25
|
}
|
|
@@ -24,104 +28,120 @@ export const pickKeys = <T extends AnyObject, Include extends keyof T>(obj: T, k
|
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
return obj;
|
|
27
|
-
}
|
|
31
|
+
};
|
|
28
32
|
|
|
29
|
-
export function omitKeys<T extends AnyObject, Exclude extends keyof T>(
|
|
30
|
-
|
|
33
|
+
export function omitKeys<T extends AnyObject, Exclude extends keyof T>(
|
|
34
|
+
obj: T,
|
|
35
|
+
exclude: Exclude[]
|
|
36
|
+
): Omit<T, Exclude> {
|
|
37
|
+
return pickKeys(
|
|
38
|
+
obj,
|
|
39
|
+
getKeys(obj).filter((k) => !exclude.includes(k as any))
|
|
40
|
+
);
|
|
31
41
|
}
|
|
32
42
|
|
|
33
|
-
export function filter<T extends AnyObject, ArrFilter extends Partial<T>>(
|
|
34
|
-
|
|
43
|
+
export function filter<T extends AnyObject, ArrFilter extends Partial<T>>(
|
|
44
|
+
array: T[],
|
|
45
|
+
arrFilter: ArrFilter
|
|
46
|
+
): T[] {
|
|
47
|
+
return array.filter((d) => Object.entries(arrFilter).every(([k, v]) => d[k] === v));
|
|
35
48
|
}
|
|
36
|
-
export function find<T extends AnyObject, ArrFilter extends Partial<T>>(
|
|
49
|
+
export function find<T extends AnyObject, ArrFilter extends Partial<T>>(
|
|
50
|
+
array: T[],
|
|
51
|
+
arrFilter: ArrFilter
|
|
52
|
+
): T | undefined {
|
|
37
53
|
return filter(array, arrFilter)[0];
|
|
38
54
|
}
|
|
39
|
-
export function includes<Arr extends any[] | readonly any[], Elem extends Arr[number]>(
|
|
40
|
-
|
|
55
|
+
export function includes<Arr extends any[] | readonly any[], Elem extends Arr[number]>(
|
|
56
|
+
array: Arr,
|
|
57
|
+
elem: Elem
|
|
58
|
+
): boolean {
|
|
59
|
+
return array.some((v) => v === elem);
|
|
41
60
|
}
|
|
42
61
|
|
|
43
62
|
export function stableStringify(data: AnyObject, opts: any) {
|
|
44
63
|
if (!opts) opts = {};
|
|
45
|
-
if (typeof opts ===
|
|
46
|
-
var cycles =
|
|
47
|
-
|
|
48
|
-
var cmp =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
if (typeof opts === "function") opts = { cmp: opts };
|
|
65
|
+
var cycles = typeof opts.cycles === "boolean" ? opts.cycles : false;
|
|
66
|
+
|
|
67
|
+
var cmp =
|
|
68
|
+
opts.cmp &&
|
|
69
|
+
(function (f) {
|
|
70
|
+
return function (node: any) {
|
|
71
|
+
return function (a: any, b: any) {
|
|
72
|
+
var aobj = { key: a, value: node[a] };
|
|
73
|
+
var bobj = { key: b, value: node[b] };
|
|
74
|
+
return f(aobj, bobj);
|
|
75
|
+
};
|
|
54
76
|
};
|
|
55
|
-
};
|
|
56
|
-
})(opts.cmp);
|
|
77
|
+
})(opts.cmp);
|
|
57
78
|
|
|
58
79
|
var seen: any[] = [];
|
|
59
80
|
return (function stringify(node) {
|
|
60
|
-
if (node && node.toJSON && typeof node.toJSON ===
|
|
81
|
+
if (node && node.toJSON && typeof node.toJSON === "function") {
|
|
61
82
|
node = node.toJSON();
|
|
62
83
|
}
|
|
63
84
|
|
|
64
85
|
if (node === undefined) return;
|
|
65
|
-
if (typeof node ==
|
|
66
|
-
if (typeof node !==
|
|
86
|
+
if (typeof node == "number") return isFinite(node) ? "" + node : "null";
|
|
87
|
+
if (typeof node !== "object") return JSON.stringify(node);
|
|
67
88
|
|
|
68
89
|
var i, out;
|
|
69
90
|
if (Array.isArray(node)) {
|
|
70
|
-
out =
|
|
91
|
+
out = "[";
|
|
71
92
|
for (i = 0; i < node.length; i++) {
|
|
72
|
-
if (i) out +=
|
|
73
|
-
out += stringify(node[i]) ||
|
|
93
|
+
if (i) out += ",";
|
|
94
|
+
out += stringify(node[i]) || "null";
|
|
74
95
|
}
|
|
75
|
-
return out +
|
|
96
|
+
return out + "]";
|
|
76
97
|
}
|
|
77
98
|
|
|
78
|
-
if (node === null) return
|
|
99
|
+
if (node === null) return "null";
|
|
79
100
|
|
|
80
101
|
if (seen.indexOf(node) !== -1) {
|
|
81
|
-
if (cycles) return JSON.stringify(
|
|
82
|
-
throw new TypeError(
|
|
102
|
+
if (cycles) return JSON.stringify("__cycle__");
|
|
103
|
+
throw new TypeError("Converting circular structure to JSON");
|
|
83
104
|
}
|
|
84
105
|
|
|
85
106
|
var seenIndex = seen.push(node) - 1;
|
|
86
107
|
var keys = Object.keys(node).sort(cmp && cmp(node));
|
|
87
|
-
out =
|
|
108
|
+
out = "";
|
|
88
109
|
for (i = 0; i < keys.length; i++) {
|
|
89
110
|
var key = keys[i]!;
|
|
90
111
|
var value = stringify(node[key]);
|
|
91
112
|
|
|
92
113
|
if (!value) continue;
|
|
93
|
-
if (out) out +=
|
|
94
|
-
out += JSON.stringify(key) +
|
|
114
|
+
if (out) out += ",";
|
|
115
|
+
out += JSON.stringify(key) + ":" + value;
|
|
95
116
|
}
|
|
96
117
|
seen.splice(seenIndex, 1);
|
|
97
|
-
return
|
|
118
|
+
return "{" + out + "}";
|
|
98
119
|
})(data);
|
|
99
|
-
}
|
|
100
|
-
|
|
120
|
+
}
|
|
101
121
|
|
|
102
122
|
export type TextPatch = {
|
|
103
123
|
from: number;
|
|
104
124
|
to: number;
|
|
105
125
|
text: string;
|
|
106
126
|
md5: string;
|
|
107
|
-
}
|
|
127
|
+
};
|
|
108
128
|
|
|
109
129
|
export function getTextPatch(oldStr: string, newStr: string): TextPatch | string {
|
|
110
|
-
|
|
111
130
|
/* Big change, no point getting diff */
|
|
112
131
|
if (!oldStr || !newStr || !oldStr.trim().length || !newStr.trim().length) return newStr;
|
|
113
132
|
|
|
114
133
|
/* Return no change if matching */
|
|
115
|
-
if (oldStr === newStr)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
134
|
+
if (oldStr === newStr)
|
|
135
|
+
return {
|
|
136
|
+
from: 0,
|
|
137
|
+
to: 0,
|
|
138
|
+
text: "",
|
|
139
|
+
md5: md5(newStr),
|
|
140
|
+
};
|
|
121
141
|
|
|
122
142
|
function findLastIdx(direction = 1) {
|
|
123
|
-
|
|
124
|
-
|
|
143
|
+
let idx = direction < 1 ? -1 : 0,
|
|
144
|
+
found = false;
|
|
125
145
|
while (!found && Math.abs(idx) <= newStr.length) {
|
|
126
146
|
const args = direction < 1 ? [idx] : [0, idx];
|
|
127
147
|
|
|
@@ -142,21 +162,22 @@ export function getTextPatch(oldStr: string, newStr: string): TextPatch | string
|
|
|
142
162
|
from,
|
|
143
163
|
to,
|
|
144
164
|
text: newStr.slice(from, toNew),
|
|
145
|
-
md5: md5(newStr)
|
|
146
|
-
}
|
|
165
|
+
md5: md5(newStr),
|
|
166
|
+
};
|
|
147
167
|
}
|
|
148
168
|
|
|
149
|
-
|
|
150
169
|
export function unpatchText(original: string | null, patch: TextPatch): string {
|
|
151
|
-
if (!patch || typeof patch === "string") return
|
|
170
|
+
if (!patch || typeof patch === "string") return patch as unknown as string;
|
|
152
171
|
const { from, to, text, md5: md5Hash } = patch;
|
|
153
172
|
if (text === null || original === null) return text;
|
|
154
173
|
let res = original.slice(0, from) + text + original.slice(to);
|
|
155
|
-
if (md5Hash && md5(res) !== md5Hash)
|
|
174
|
+
if (md5Hash && md5(res) !== md5Hash)
|
|
175
|
+
throw (
|
|
176
|
+
"Patch text error: Could not match md5 hash: (original/result) \n" + original + "\n" + res
|
|
177
|
+
);
|
|
156
178
|
return res;
|
|
157
179
|
}
|
|
158
180
|
|
|
159
|
-
|
|
160
181
|
/* Replication */
|
|
161
182
|
export type SyncTableInfo = {
|
|
162
183
|
id_fields: string[];
|
|
@@ -214,14 +235,13 @@ export type WALItemsObj = Record<string, WALItem>;
|
|
|
214
235
|
* This allows a high rate of optimistic updates on the client
|
|
215
236
|
*/
|
|
216
237
|
export class WAL {
|
|
217
|
-
|
|
218
238
|
/**
|
|
219
239
|
* Instantly merged records for prepared for update
|
|
220
240
|
*/
|
|
221
241
|
private changed: WALItemsObj = {};
|
|
222
242
|
|
|
223
243
|
/**
|
|
224
|
-
* Batch of records (removed from this.changed) that are currently being sent
|
|
244
|
+
* Batch of records (removed from this.changed) that are currently being sent
|
|
225
245
|
*/
|
|
226
246
|
private sending: WALItemsObj = {};
|
|
227
247
|
|
|
@@ -231,18 +251,17 @@ export class WAL {
|
|
|
231
251
|
private sentHistory: Record<string, AnyObject> = {};
|
|
232
252
|
|
|
233
253
|
private options: WALConfig;
|
|
234
|
-
private callbacks: { cb: Function
|
|
254
|
+
private callbacks: { cb: Function; idStrs: string[] }[] = [];
|
|
235
255
|
|
|
236
256
|
constructor(args: WALConfig) {
|
|
237
257
|
this.options = { ...args };
|
|
238
258
|
if (!this.options.orderBy) {
|
|
239
259
|
const { synced_field, id_fields } = args;
|
|
240
|
-
this.options.orderBy = [synced_field, ...id_fields.sort()]
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}));
|
|
260
|
+
this.options.orderBy = [synced_field, ...id_fields.sort()].map((fieldName) => ({
|
|
261
|
+
fieldName,
|
|
262
|
+
tsDataType: fieldName === synced_field ? "number" : "string",
|
|
263
|
+
asc: true,
|
|
264
|
+
}));
|
|
246
265
|
}
|
|
247
266
|
}
|
|
248
267
|
|
|
@@ -250,27 +269,33 @@ export class WAL {
|
|
|
250
269
|
const { orderBy } = this.options;
|
|
251
270
|
if (!orderBy || !a || !b) return 0;
|
|
252
271
|
|
|
253
|
-
return
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
272
|
+
return (
|
|
273
|
+
orderBy
|
|
274
|
+
.map((ob) => {
|
|
275
|
+
/* TODO: add fullData to changed items + ensure orderBy is in select */
|
|
276
|
+
if (!(ob.fieldName in a) || !(ob.fieldName in b)) {
|
|
277
|
+
throw `Replication error: \n some orderBy fields missing from data`;
|
|
278
|
+
}
|
|
279
|
+
let v1 = ob.asc ? a[ob.fieldName] : b[ob.fieldName],
|
|
280
|
+
v2 = ob.asc ? b[ob.fieldName] : a[ob.fieldName];
|
|
281
|
+
|
|
282
|
+
let vNum = +v1 - +v2,
|
|
283
|
+
vStr =
|
|
284
|
+
v1 < v2 ? -1
|
|
285
|
+
: v1 == v2 ? 0
|
|
286
|
+
: 1;
|
|
287
|
+
return ob.tsDataType === "number" && Number.isFinite(vNum) ? vNum : vStr;
|
|
288
|
+
})
|
|
289
|
+
.find((v) => v) || 0
|
|
290
|
+
);
|
|
291
|
+
};
|
|
266
292
|
|
|
267
293
|
isSending(): boolean {
|
|
268
|
-
|
|
269
294
|
const result = this.isOnSending || !(isEmpty(this.sending) && isEmpty(this.changed));
|
|
270
295
|
if (this.options.DEBUG_MODE) {
|
|
271
|
-
console.log(this.options.id, " CHECKING isSending ->", result)
|
|
296
|
+
console.log(this.options.id, " CHECKING isSending ->", result);
|
|
272
297
|
}
|
|
273
|
-
return result
|
|
298
|
+
return result;
|
|
274
299
|
}
|
|
275
300
|
|
|
276
301
|
/**
|
|
@@ -281,33 +306,38 @@ export class WAL {
|
|
|
281
306
|
*/
|
|
282
307
|
isInHistory = (item: AnyObject): boolean => {
|
|
283
308
|
if (!item) throw "Provide item";
|
|
284
|
-
const itemSyncVal = item[this.options.synced_field]
|
|
285
|
-
if (!Number.isFinite(+itemSyncVal))
|
|
309
|
+
const itemSyncVal = item[this.options.synced_field];
|
|
310
|
+
if (!Number.isFinite(+itemSyncVal))
|
|
311
|
+
throw "Provided item Synced field value is missing/invalid ";
|
|
286
312
|
|
|
287
313
|
const existing = this.sentHistory[this.getIdStr(item)];
|
|
288
314
|
const existingSyncVal = existing?.[this.options.synced_field];
|
|
289
315
|
if (existing) {
|
|
290
|
-
if (!Number.isFinite(+existingSyncVal))
|
|
316
|
+
if (!Number.isFinite(+existingSyncVal))
|
|
317
|
+
throw "Provided historic item Synced field value is missing/invalid";
|
|
291
318
|
if (+existingSyncVal === +itemSyncVal) {
|
|
292
|
-
return true
|
|
319
|
+
return true;
|
|
293
320
|
}
|
|
294
321
|
}
|
|
295
322
|
return false;
|
|
296
|
-
}
|
|
323
|
+
};
|
|
297
324
|
|
|
298
325
|
getIdStr(d: AnyObject): string {
|
|
299
|
-
return this.options.id_fields
|
|
326
|
+
return this.options.id_fields
|
|
327
|
+
.sort()
|
|
328
|
+
.map((key) => `${d[key] || ""}`)
|
|
329
|
+
.join(".");
|
|
300
330
|
}
|
|
301
331
|
getIdObj(d: AnyObject): AnyObject {
|
|
302
332
|
let res: AnyObject = {};
|
|
303
|
-
this.options.id_fields.sort().map(key => {
|
|
333
|
+
this.options.id_fields.sort().map((key) => {
|
|
304
334
|
res[key] = d[key];
|
|
305
335
|
});
|
|
306
336
|
return res;
|
|
307
337
|
}
|
|
308
338
|
getDeltaObj(d: AnyObject): AnyObject {
|
|
309
339
|
let res: AnyObject = {};
|
|
310
|
-
Object.keys(d).map(key => {
|
|
340
|
+
Object.keys(d).map((key) => {
|
|
311
341
|
if (!this.options.id_fields.includes(key)) {
|
|
312
342
|
res[key] = d[key];
|
|
313
343
|
}
|
|
@@ -318,7 +348,7 @@ export class WAL {
|
|
|
318
348
|
addData = (data: WALItem[]) => {
|
|
319
349
|
if (isEmpty(this.changed) && this.options.onSendStart) this.options.onSendStart();
|
|
320
350
|
|
|
321
|
-
data.map(d => {
|
|
351
|
+
data.map((d) => {
|
|
322
352
|
const { initial, current, delta } = { ...d };
|
|
323
353
|
if (!current) throw "Expecting { current: object, initial?: object }";
|
|
324
354
|
const idStr = this.getIdStr(current);
|
|
@@ -327,24 +357,31 @@ export class WAL {
|
|
|
327
357
|
this.changed[idStr] ??= { initial, current, delta };
|
|
328
358
|
this.changed[idStr]!.current = {
|
|
329
359
|
...this.changed[idStr]!.current,
|
|
330
|
-
...current
|
|
360
|
+
...current,
|
|
331
361
|
};
|
|
332
362
|
this.changed[idStr]!.delta = {
|
|
333
363
|
...this.changed[idStr]!.delta,
|
|
334
|
-
...delta
|
|
364
|
+
...delta,
|
|
335
365
|
};
|
|
336
366
|
});
|
|
337
367
|
this.sendItems();
|
|
338
|
-
}
|
|
368
|
+
};
|
|
339
369
|
|
|
340
370
|
isOnSending = false;
|
|
341
371
|
isSendingTimeout?: ReturnType<typeof setTimeout> = undefined;
|
|
342
372
|
willDeleteHistory?: ReturnType<typeof setTimeout> = undefined;
|
|
343
373
|
private sendItems = async () => {
|
|
344
|
-
const {
|
|
374
|
+
const {
|
|
375
|
+
DEBUG_MODE,
|
|
376
|
+
onSend,
|
|
377
|
+
onSendEnd,
|
|
378
|
+
batch_size,
|
|
379
|
+
throttle,
|
|
380
|
+
historyAgeSeconds = 2,
|
|
381
|
+
} = this.options;
|
|
345
382
|
|
|
346
383
|
// Sending data. stop here
|
|
347
|
-
if (this.isSendingTimeout || this.sending && !isEmpty(this.sending)) return;
|
|
384
|
+
if (this.isSendingTimeout || (this.sending && !isEmpty(this.sending))) return;
|
|
348
385
|
|
|
349
386
|
// Nothing to send. stop here
|
|
350
387
|
if (!this.changed || isEmpty(this.changed)) return;
|
|
@@ -360,7 +397,7 @@ export class WAL {
|
|
|
360
397
|
Object.keys(this.changed)
|
|
361
398
|
.sort((a, b) => this.sort(this.changed[a]!.current, this.changed[b]!.current))
|
|
362
399
|
.slice(0, batch_size)
|
|
363
|
-
.map(key => {
|
|
400
|
+
.map((key) => {
|
|
364
401
|
let item = { ...this.changed[key] } as WALItem;
|
|
365
402
|
this.sending[key] = { ...item };
|
|
366
403
|
walBatch.push({ ...item });
|
|
@@ -370,24 +407,24 @@ export class WAL {
|
|
|
370
407
|
|
|
371
408
|
delete this.changed[key];
|
|
372
409
|
});
|
|
373
|
-
batchItems = walBatch.map(d => {
|
|
410
|
+
batchItems = walBatch.map((d) => {
|
|
374
411
|
let result: AnyObject = {};
|
|
375
|
-
Object.keys(d.current).map(k => {
|
|
412
|
+
Object.keys(d.current).map((k) => {
|
|
376
413
|
const oldVal = d.initial?.[k];
|
|
377
414
|
const newVal = d.current[k];
|
|
378
415
|
/** Send only id fields and delta */
|
|
379
|
-
if(
|
|
416
|
+
if (
|
|
380
417
|
[this.options.synced_field, ...this.options.id_fields].includes(k) ||
|
|
381
418
|
!areEqual(oldVal, newVal)
|
|
382
|
-
){
|
|
419
|
+
) {
|
|
383
420
|
result[k] = newVal;
|
|
384
421
|
}
|
|
385
|
-
})
|
|
422
|
+
});
|
|
386
423
|
return result;
|
|
387
424
|
});
|
|
388
425
|
|
|
389
426
|
if (DEBUG_MODE) {
|
|
390
|
-
console.log(this.options.id, " SENDING lr->", batchItems[batchItems.length - 1])
|
|
427
|
+
console.log(this.options.id, " SENDING lr->", batchItems[batchItems.length - 1]);
|
|
391
428
|
}
|
|
392
429
|
|
|
393
430
|
// Throttle next data send
|
|
@@ -400,12 +437,11 @@ export class WAL {
|
|
|
400
437
|
}, throttle);
|
|
401
438
|
}
|
|
402
439
|
|
|
403
|
-
|
|
404
440
|
let error: any;
|
|
405
441
|
this.isOnSending = true;
|
|
406
442
|
try {
|
|
407
443
|
/* Deleted data should be sent normally through await db.table.delete(...) */
|
|
408
|
-
await onSend(batchItems, walBatch)
|
|
444
|
+
await onSend(batchItems, walBatch); //, deletedData);
|
|
409
445
|
|
|
410
446
|
/**
|
|
411
447
|
* Keep history if required
|
|
@@ -414,7 +450,7 @@ export class WAL {
|
|
|
414
450
|
this.sentHistory = {
|
|
415
451
|
...this.sentHistory,
|
|
416
452
|
...batchObj,
|
|
417
|
-
}
|
|
453
|
+
};
|
|
418
454
|
/**
|
|
419
455
|
* Delete history after some time
|
|
420
456
|
*/
|
|
@@ -427,7 +463,7 @@ export class WAL {
|
|
|
427
463
|
}
|
|
428
464
|
} catch (err) {
|
|
429
465
|
error = err;
|
|
430
|
-
console.error("WAL onSend failed:", err, batchItems, walBatch)
|
|
466
|
+
console.error("WAL onSend failed:", err, batchItems, walBatch);
|
|
431
467
|
}
|
|
432
468
|
this.isOnSending = false;
|
|
433
469
|
|
|
@@ -435,17 +471,17 @@ export class WAL {
|
|
|
435
471
|
if (this.callbacks.length) {
|
|
436
472
|
const ids = Object.keys(this.sending);
|
|
437
473
|
this.callbacks.forEach((c, i) => {
|
|
438
|
-
c.idStrs = c.idStrs.filter(id => ids.includes(id));
|
|
474
|
+
c.idStrs = c.idStrs.filter((id) => ids.includes(id));
|
|
439
475
|
if (!c.idStrs.length) {
|
|
440
476
|
c.cb(error);
|
|
441
477
|
}
|
|
442
478
|
});
|
|
443
|
-
this.callbacks = this.callbacks.filter(cb => cb.idStrs.length)
|
|
479
|
+
this.callbacks = this.callbacks.filter((cb) => cb.idStrs.length);
|
|
444
480
|
}
|
|
445
481
|
|
|
446
482
|
this.sending = {};
|
|
447
483
|
if (DEBUG_MODE) {
|
|
448
|
-
console.log(this.options.id, " SENT lr->", batchItems[batchItems.length - 1])
|
|
484
|
+
console.log(this.options.id, " SENT lr->", batchItems[batchItems.length - 1]);
|
|
449
485
|
}
|
|
450
486
|
if (!isEmpty(this.changed)) {
|
|
451
487
|
this.sendItems();
|
|
@@ -453,17 +489,15 @@ export class WAL {
|
|
|
453
489
|
if (onSendEnd) onSendEnd(batchItems, walBatch, error);
|
|
454
490
|
}
|
|
455
491
|
};
|
|
456
|
-
}
|
|
492
|
+
}
|
|
457
493
|
|
|
458
494
|
export function isEmpty(obj?: any): boolean {
|
|
459
495
|
for (var v in obj) return false;
|
|
460
496
|
return true;
|
|
461
497
|
}
|
|
462
498
|
|
|
463
|
-
|
|
464
499
|
/* Get nested property from an object */
|
|
465
500
|
export function get(obj: any, propertyPath: string | string[]): any {
|
|
466
|
-
|
|
467
501
|
let p = propertyPath,
|
|
468
502
|
o = obj;
|
|
469
503
|
|
|
@@ -471,84 +505,93 @@ export function get(obj: any, propertyPath: string | string[]): any {
|
|
|
471
505
|
if (typeof p === "string") p = p.split(".");
|
|
472
506
|
return p.reduce((xs, x) => {
|
|
473
507
|
if (xs && xs[x]) {
|
|
474
|
-
return xs[x]
|
|
508
|
+
return xs[x];
|
|
475
509
|
} else {
|
|
476
510
|
return undefined;
|
|
477
511
|
}
|
|
478
512
|
}, o);
|
|
479
513
|
}
|
|
480
514
|
|
|
481
|
-
|
|
482
|
-
|
|
515
|
+
export const getObjectEntries = <T extends Record<string, any>>(
|
|
516
|
+
obj: T
|
|
517
|
+
): [keyof T, T[keyof T]][] => {
|
|
483
518
|
return Object.entries(obj) as [keyof T, T[keyof T]][];
|
|
484
|
-
}
|
|
519
|
+
};
|
|
485
520
|
|
|
486
|
-
function areEqual(a: any, b: any){
|
|
487
|
-
if(a === b) return true;
|
|
488
|
-
if(["number", "string", "boolean"].includes(typeof a)){
|
|
521
|
+
function areEqual(a: any, b: any) {
|
|
522
|
+
if (a === b) return true;
|
|
523
|
+
if (["number", "string", "boolean"].includes(typeof a)) {
|
|
489
524
|
return a === b;
|
|
490
525
|
}
|
|
491
526
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
492
527
|
}
|
|
493
528
|
|
|
494
|
-
|
|
495
529
|
export function isObject(obj: any | undefined): obj is Record<string, any> {
|
|
496
530
|
return Boolean(obj && typeof obj === "object" && !Array.isArray(obj));
|
|
497
531
|
}
|
|
498
|
-
export function isDefined<T>(v: T | undefined | void): v is T {
|
|
532
|
+
export function isDefined<T>(v: T | undefined | void): v is T {
|
|
533
|
+
return v !== undefined && v !== null;
|
|
534
|
+
}
|
|
499
535
|
|
|
500
|
-
export function getKeys<T extends AnyObject>(o: T): Array<keyof T>{
|
|
501
|
-
return Object.keys(o) as any
|
|
536
|
+
export function getKeys<T extends AnyObject>(o: T): Array<keyof T> {
|
|
537
|
+
return Object.keys(o) as any;
|
|
502
538
|
}
|
|
503
539
|
|
|
504
|
-
export type Explode<T> =
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
540
|
+
export type Explode<T> =
|
|
541
|
+
keyof T extends infer K ?
|
|
542
|
+
K extends unknown ?
|
|
543
|
+
{ [I in keyof T]: I extends K ? T[I] : never }
|
|
544
|
+
: never
|
|
508
545
|
: never;
|
|
509
546
|
export type AtMostOne<T> = Explode<Partial<T>>;
|
|
510
|
-
export type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U]
|
|
547
|
+
export type AtLeastOne<T, U = { [K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];
|
|
511
548
|
export type ExactlyOne<T> = AtMostOne<T> & AtLeastOne<T>;
|
|
512
549
|
|
|
513
|
-
|
|
514
550
|
type UnionKeys<T> = T extends T ? keyof T : never;
|
|
515
|
-
type StrictUnionHelper<T, TAll> =
|
|
551
|
+
type StrictUnionHelper<T, TAll> =
|
|
552
|
+
T extends any ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
|
|
516
553
|
export type StrictUnion<T> = StrictUnionHelper<T, T>;
|
|
517
554
|
|
|
518
555
|
/**
|
|
519
556
|
* @deprecated
|
|
520
557
|
* use tryCatchV2 instead
|
|
521
558
|
*/
|
|
522
|
-
export const tryCatch = async <T extends AnyObject>(
|
|
523
|
-
|
|
559
|
+
export const tryCatch = async <T extends AnyObject>(
|
|
560
|
+
func: () => T | Promise<T>
|
|
561
|
+
): Promise<
|
|
562
|
+
| (T & { hasError?: false; error?: undefined; duration: number })
|
|
563
|
+
| (Partial<Record<keyof T, undefined>> & { hasError: true; error: unknown; duration: number })
|
|
564
|
+
> => {
|
|
524
565
|
const startTime = Date.now();
|
|
525
566
|
try {
|
|
526
567
|
const res = await func();
|
|
527
568
|
return {
|
|
528
569
|
...res,
|
|
529
570
|
duration: Date.now() - startTime,
|
|
530
|
-
}
|
|
531
|
-
} catch(error){
|
|
532
|
-
return {
|
|
571
|
+
};
|
|
572
|
+
} catch (error) {
|
|
573
|
+
return {
|
|
533
574
|
error,
|
|
534
575
|
hasError: true,
|
|
535
|
-
duration: Date.now() - startTime,
|
|
576
|
+
duration: Date.now() - startTime,
|
|
536
577
|
} as any;
|
|
537
578
|
}
|
|
538
|
-
}
|
|
579
|
+
};
|
|
539
580
|
|
|
540
|
-
type TryCatchResult<T> =
|
|
541
|
-
| { data: T; hasError?: false; error?: undefined; duration: number
|
|
542
|
-
| { data?: undefined; hasError: true; error: unknown; duration: number
|
|
581
|
+
type TryCatchResult<T> =
|
|
582
|
+
| { data: T; hasError?: false; error?: undefined; duration: number }
|
|
583
|
+
| { data?: undefined; hasError: true; error: unknown; duration: number };
|
|
543
584
|
|
|
544
|
-
export const tryCatchV2 = <T
|
|
585
|
+
export const tryCatchV2 = <T>(
|
|
586
|
+
func: () => T | Promise<T>
|
|
587
|
+
): T extends Promise<T> ? Promise<TryCatchResult<Awaited<T>>> : TryCatchResult<T> => {
|
|
545
588
|
const startTime = Date.now();
|
|
546
589
|
try {
|
|
547
590
|
const dataOrResult = func();
|
|
548
|
-
if(dataOrResult instanceof Promise){
|
|
591
|
+
if (dataOrResult instanceof Promise) {
|
|
549
592
|
return new Promise(async (resolve, reject) => {
|
|
550
593
|
const duration = Date.now() - startTime;
|
|
551
|
-
const data = await dataOrResult
|
|
594
|
+
const data = await dataOrResult;
|
|
552
595
|
resolve({
|
|
553
596
|
data,
|
|
554
597
|
duration,
|
|
@@ -559,48 +602,47 @@ export const tryCatchV2 = <T,>(func: () => T | Promise<T>): T extends Promise<T>
|
|
|
559
602
|
data: dataOrResult,
|
|
560
603
|
duration: Date.now() - startTime,
|
|
561
604
|
} as any;
|
|
562
|
-
} catch(error){
|
|
605
|
+
} catch (error) {
|
|
563
606
|
console.error(error);
|
|
564
|
-
return {
|
|
607
|
+
return {
|
|
565
608
|
error,
|
|
566
609
|
hasError: true,
|
|
567
|
-
duration: Date.now() - startTime,
|
|
610
|
+
duration: Date.now() - startTime,
|
|
568
611
|
} as any;
|
|
569
612
|
}
|
|
570
|
-
}
|
|
613
|
+
};
|
|
571
614
|
|
|
572
615
|
export const getJoinHandlers = (tableName: string) => {
|
|
573
616
|
const getJoinFunc = (isLeft: boolean, expectsOne: boolean): JoinMaker => {
|
|
574
|
-
return (
|
|
617
|
+
return (
|
|
618
|
+
filter: Parameters<JoinMaker<AnyObject>>[0],
|
|
619
|
+
select: Parameters<JoinMaker<AnyObject>>[1],
|
|
620
|
+
options: Parameters<JoinMaker<AnyObject>>[2] = {}
|
|
621
|
+
) => {
|
|
575
622
|
// return makeJoin(isLeft, filter, select, expectsOne? { ...options, limit: 1 } : options);
|
|
576
623
|
return {
|
|
577
624
|
[isLeft ? "$leftJoin" : "$innerJoin"]: options.path ?? tableName,
|
|
578
625
|
filter,
|
|
579
|
-
...
|
|
626
|
+
...omitKeys(options, ["path", "select"]),
|
|
580
627
|
select,
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
}
|
|
628
|
+
};
|
|
629
|
+
};
|
|
630
|
+
};
|
|
584
631
|
|
|
585
632
|
return {
|
|
586
633
|
innerJoin: getJoinFunc(false, false),
|
|
587
634
|
leftJoin: getJoinFunc(true, false),
|
|
588
635
|
innerJoinOne: getJoinFunc(false, true),
|
|
589
636
|
leftJoinOne: getJoinFunc(true, true),
|
|
590
|
-
}
|
|
591
|
-
}
|
|
637
|
+
};
|
|
638
|
+
};
|
|
592
639
|
|
|
593
640
|
export type ParsedJoinPath = Required<JoinPath>;
|
|
594
641
|
export const reverseJoinOn = (on: ParsedJoinPath["on"]) => {
|
|
595
|
-
return on.map(constraint =>
|
|
596
|
-
Object.fromEntries(
|
|
597
|
-
Object.entries(constraint)
|
|
598
|
-
.map(([left, right]) =>
|
|
599
|
-
[right, left]
|
|
600
|
-
)
|
|
601
|
-
)
|
|
642
|
+
return on.map((constraint) =>
|
|
643
|
+
Object.fromEntries(Object.entries(constraint).map(([left, right]) => [right, left]))
|
|
602
644
|
);
|
|
603
|
-
}
|
|
645
|
+
};
|
|
604
646
|
|
|
605
647
|
/**
|
|
606
648
|
* result = [
|
|
@@ -609,16 +651,16 @@ export const reverseJoinOn = (on: ParsedJoinPath["on"]) => {
|
|
|
609
651
|
* ]
|
|
610
652
|
*/
|
|
611
653
|
export const reverseParsedPath = (parsedPath: ParsedJoinPath[], table: string) => {
|
|
612
|
-
const newPPath: ParsedJoinPath[] = [
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
}
|
|
654
|
+
const newPPath: ParsedJoinPath[] = [{ table, on: [{}] }, ...(parsedPath ?? [])];
|
|
655
|
+
return newPPath
|
|
656
|
+
.map((pp, i) => {
|
|
657
|
+
const nextPath = newPPath[i + 1];
|
|
658
|
+
if (!nextPath) return undefined;
|
|
659
|
+
return {
|
|
660
|
+
table: pp.table,
|
|
661
|
+
on: reverseJoinOn(nextPath.on),
|
|
662
|
+
};
|
|
663
|
+
})
|
|
664
|
+
.filter(isDefined)
|
|
665
|
+
.reverse();
|
|
666
|
+
};
|