corebasic 1.0.230 → 1.0.232
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/libs/auth.js +5 -4
- package/dist/libs/compression.js +1 -7
- package/dist/libs/dip/suffix/index.js +8 -6
- package/dist/libs/dip/suffix/policy.js +6 -4
- package/dist/libs/dip/suffix/query.js +290 -279
- package/dist/libs/dip/suffix/suffix.js +17 -13
- package/dist/libs/dip/suffix/tests/date.test.js +21 -34
- package/dist/libs/dip/suffix/tests/policy.test.js +41 -80
- package/dist/libs/dip.js +29 -26
- package/dist/libs/dipper.js +0 -1
- package/dist/libs/elabase.js +1 -1
- package/dist/libs/features.js +110 -60
- package/dist/libs/kafka.js +6 -5
- package/dist/libs/messaging.js +7 -4
- package/dist/libs/session.js +2 -2
- package/libs/auth.ts +48 -9
- package/libs/compression.ts +6 -1
- package/libs/cpp.ts +15 -13
- package/libs/dip/suffix/date.ts +6 -6
- package/libs/dip/suffix/index.ts +41 -26
- package/libs/dip/suffix/policy.ts +16 -13
- package/libs/dip/suffix/query.ts +289 -289
- package/libs/dip/suffix/suffix.ts +26 -20
- package/libs/dip/suffix/tests/date.test.ts +32 -64
- package/libs/dip/suffix/tests/policy.applySuffixPolicy.test.ts +20 -20
- package/libs/dip/suffix/tests/policy.test.ts +41 -109
- package/libs/dip/suffix/tests/suffix.test.ts +2 -2
- package/libs/dip.ts +61 -33
- package/libs/dipper.ts +25 -10
- package/libs/elabase.ts +1 -1
- package/libs/features.ts +232 -95
- package/libs/kafka.ts +75 -14
- package/libs/messaging.ts +80 -19
- package/libs/session.ts +21 -10
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import { describe, test } from "node:test";
|
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
import {matchPolicy, overlaps, contains, intersects, applySuffixPolicy} from "../policy.ts";
|
|
4
4
|
|
|
5
|
+
const defaultBounds = {values: [], from: -Infinity, to: Infinity, fromOp: "$gte", toOp: "$lte"}
|
|
5
6
|
|
|
6
7
|
/* ============================================================
|
|
7
8
|
* overlaps()
|
|
@@ -10,35 +11,35 @@ describe("overlaps()", () => {
|
|
|
10
11
|
|
|
11
12
|
test("overlaps: identical ranges", () => {
|
|
12
13
|
assert.equal(
|
|
13
|
-
overlaps({ from: 10, to: 20 }, { from: 10, to: 20 }),
|
|
14
|
+
overlaps({ ...defaultBounds, from: 10, to: 20 }, { ...defaultBounds, from: 10, to: 20 }),
|
|
14
15
|
true
|
|
15
16
|
);
|
|
16
17
|
});
|
|
17
18
|
|
|
18
19
|
test("overlaps: partial overlap", () => {
|
|
19
20
|
assert.equal(
|
|
20
|
-
overlaps({ from: 10, to: 20 }, { from: 15, to: 25 }),
|
|
21
|
+
overlaps({ ...defaultBounds, from: 10, to: 20 }, { ...defaultBounds, from: 15, to: 25 }),
|
|
21
22
|
true
|
|
22
23
|
);
|
|
23
24
|
});
|
|
24
25
|
|
|
25
26
|
test("overlaps: no overlap", () => {
|
|
26
27
|
assert.equal(
|
|
27
|
-
overlaps({ from: 10, to: 20 }, { from: 21, to: 30 }),
|
|
28
|
+
overlaps({ ...defaultBounds, from: 10, to: 20 }, { ...defaultBounds, from: 21, to: 30 }),
|
|
28
29
|
false
|
|
29
30
|
);
|
|
30
31
|
});
|
|
31
32
|
|
|
32
33
|
test("overlaps: open ended lower", () => {
|
|
33
34
|
assert.equal(
|
|
34
|
-
overlaps({ to: 10 }, { from: 5 }),
|
|
35
|
+
overlaps({ ...defaultBounds, to: 10 }, { ...defaultBounds, from: 5 }),
|
|
35
36
|
true
|
|
36
37
|
);
|
|
37
38
|
});
|
|
38
39
|
|
|
39
40
|
test("overlaps: open ended upper", () => {
|
|
40
41
|
assert.equal(
|
|
41
|
-
overlaps({ from: 20 }, { to: 10 }),
|
|
42
|
+
overlaps({ ...defaultBounds, from: 20 }, { ...defaultBounds, to: 10 }),
|
|
42
43
|
false
|
|
43
44
|
);
|
|
44
45
|
});
|
|
@@ -48,39 +49,28 @@ describe("overlaps()", () => {
|
|
|
48
49
|
|
|
49
50
|
test("touching: open/open does not overlap", () => {
|
|
50
51
|
assert.equal(
|
|
51
|
-
overlaps(
|
|
52
|
-
{ to: 10, toOp: "$lt" },
|
|
53
|
-
{ from: 10, fromOp: "$gt" }
|
|
54
|
-
),
|
|
52
|
+
overlaps({ ...defaultBounds, to: 10, toOp: "$lt" }, { ...defaultBounds, from: 10, fromOp: "$gt" }),
|
|
55
53
|
false
|
|
56
54
|
);
|
|
57
55
|
});
|
|
58
56
|
|
|
59
57
|
test("touching: closed/closed overlaps", () => {
|
|
60
58
|
assert.equal(
|
|
61
|
-
overlaps(
|
|
62
|
-
{ to: 10, toOp: "$lte" },
|
|
63
|
-
{ from: 10, fromOp: "$gte" }
|
|
64
|
-
),
|
|
59
|
+
overlaps({ ...defaultBounds, to: 10, toOp: "$lte" }, { ...defaultBounds, from: 10, fromOp: "$gte" }),
|
|
65
60
|
true
|
|
66
61
|
);
|
|
67
62
|
});
|
|
68
63
|
|
|
69
64
|
test("touching: closed/open does not overlap", () => {
|
|
70
65
|
assert.equal(
|
|
71
|
-
overlaps(
|
|
72
|
-
{ to: 10, toOp: "$lte" },
|
|
73
|
-
{ from: 10, fromOp: "$gt" }
|
|
74
|
-
),
|
|
66
|
+
overlaps({ ...defaultBounds, to: 10, toOp: "$lte" }, { ...defaultBounds, from: 10, fromOp: "$gt" }),
|
|
75
67
|
false
|
|
76
68
|
);
|
|
77
69
|
});
|
|
78
70
|
|
|
79
71
|
test("touching: open/closed does not overlap", () => {
|
|
80
72
|
assert.equal(
|
|
81
|
-
overlaps(
|
|
82
|
-
{ to: 10, toOp: "$lt" },
|
|
83
|
-
{ from: 10, fromOp: "$gte" }
|
|
73
|
+
overlaps({ ...defaultBounds, to: 10, toOp: "$lt" }, { ...defaultBounds, from: 10, fromOp: "$gte" }
|
|
84
74
|
),
|
|
85
75
|
false
|
|
86
76
|
);
|
|
@@ -88,80 +78,42 @@ describe("overlaps()", () => {
|
|
|
88
78
|
|
|
89
79
|
test("touching: reverse order closed/closed overlaps", () => {
|
|
90
80
|
assert.equal(
|
|
91
|
-
overlaps(
|
|
92
|
-
{ from: 10, fromOp: "$gte" },
|
|
93
|
-
{ to: 10, toOp: "$lte" }
|
|
94
|
-
),
|
|
81
|
+
overlaps({ ...defaultBounds, from: 10, fromOp: "$gte" }, { ...defaultBounds, to: 10, toOp: "$lte" }),
|
|
95
82
|
true
|
|
96
83
|
);
|
|
97
84
|
});
|
|
98
85
|
|
|
99
86
|
test("touching: reverse order open/open does not overlap", () => {
|
|
100
87
|
assert.equal(
|
|
101
|
-
overlaps(
|
|
102
|
-
{ from: 10, fromOp: "$gt" },
|
|
103
|
-
{ to: 10, toOp: "$lt" }
|
|
104
|
-
),
|
|
88
|
+
overlaps({ ...defaultBounds, from: 10, fromOp: "$gt" }, { ...defaultBounds, to: 10, toOp: "$lt" }),
|
|
105
89
|
false
|
|
106
90
|
);
|
|
107
91
|
});
|
|
108
92
|
|
|
109
93
|
test("identical single-point closed intervals overlap", () => {
|
|
110
94
|
assert.equal(
|
|
111
|
-
overlaps(
|
|
112
|
-
{
|
|
113
|
-
from: 10,
|
|
114
|
-
to: 10,
|
|
115
|
-
fromOp: "$gte",
|
|
116
|
-
toOp: "$lte"
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
from: 10,
|
|
120
|
-
to: 10,
|
|
121
|
-
fromOp: "$gte",
|
|
122
|
-
toOp: "$lte"
|
|
123
|
-
}
|
|
124
|
-
),
|
|
95
|
+
overlaps({ ...defaultBounds, from: 10, to: 10, fromOp: "$gte", toOp: "$lte" }, { ...defaultBounds, from: 10, to: 10, fromOp: "$gte", toOp: "$lte" }),
|
|
125
96
|
true
|
|
126
97
|
);
|
|
127
98
|
});
|
|
128
99
|
|
|
129
100
|
test("identical single-point open intervals do not overlap", () => {
|
|
130
101
|
assert.equal(
|
|
131
|
-
overlaps(
|
|
132
|
-
{
|
|
133
|
-
from: 10,
|
|
134
|
-
to: 10,
|
|
135
|
-
fromOp: "$gt",
|
|
136
|
-
toOp: "$lt"
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
from: 10,
|
|
140
|
-
to: 10,
|
|
141
|
-
fromOp: "$gt",
|
|
142
|
-
toOp: "$lt"
|
|
143
|
-
}
|
|
144
|
-
),
|
|
102
|
+
overlaps({ ...defaultBounds, from: 10, to: 10, fromOp: "$gt", toOp: "$lt" }, { ...defaultBounds, from: 10, to: 10, fromOp: "$gt", toOp: "$lt" }),
|
|
145
103
|
false
|
|
146
104
|
);
|
|
147
105
|
});
|
|
148
106
|
|
|
149
107
|
test("infinite lower bound with touching closed endpoint overlaps", () => {
|
|
150
108
|
assert.equal(
|
|
151
|
-
overlaps(
|
|
152
|
-
{ to: 5, toOp: "$lte" },
|
|
153
|
-
{ from: 5, fromOp: "$gte" }
|
|
154
|
-
),
|
|
109
|
+
overlaps({ ...defaultBounds, to: 5, toOp: "$lte" }, { ...defaultBounds, from: 5, fromOp: "$gte" }),
|
|
155
110
|
true
|
|
156
111
|
);
|
|
157
112
|
});
|
|
158
113
|
|
|
159
114
|
test("infinite lower bound with touching open endpoint does not overlap", () => {
|
|
160
115
|
assert.equal(
|
|
161
|
-
overlaps(
|
|
162
|
-
{ to: 5, toOp: "$lt" },
|
|
163
|
-
{ from: 5, fromOp: "$gt" }
|
|
164
|
-
),
|
|
116
|
+
overlaps({ ...defaultBounds, to: 5, toOp: "$lt" }, { ...defaultBounds, from: 5, fromOp: "$gt" }),
|
|
165
117
|
false
|
|
166
118
|
);
|
|
167
119
|
});
|
|
@@ -178,35 +130,35 @@ describe("contains()", () => {
|
|
|
178
130
|
|
|
179
131
|
test("contains: inside", () => {
|
|
180
132
|
assert.equal(
|
|
181
|
-
contains({ from: 10, to: 20 }, 15),
|
|
133
|
+
contains({ ...defaultBounds, from: 10, to: 20 }, 15),
|
|
182
134
|
true
|
|
183
135
|
);
|
|
184
136
|
});
|
|
185
137
|
|
|
186
138
|
test("contains: below", () => {
|
|
187
139
|
assert.equal(
|
|
188
|
-
contains({ from: 10, to: 20 }, 5),
|
|
140
|
+
contains({ ...defaultBounds, from: 10, to: 20 }, 5),
|
|
189
141
|
false
|
|
190
142
|
);
|
|
191
143
|
});
|
|
192
144
|
|
|
193
145
|
test("contains: above", () => {
|
|
194
146
|
assert.equal(
|
|
195
|
-
contains({ from: 10, to: 20 }, 25),
|
|
147
|
+
contains({ ...defaultBounds, from: 10, to: 20 }, 25),
|
|
196
148
|
false
|
|
197
149
|
);
|
|
198
150
|
});
|
|
199
151
|
|
|
200
152
|
test("contains: lower bound", () => {
|
|
201
153
|
assert.equal(
|
|
202
|
-
contains({ from: 10, to: 20 }, 10),
|
|
154
|
+
contains({ ...defaultBounds, from: 10, to: 20 }, 10),
|
|
203
155
|
true
|
|
204
156
|
);
|
|
205
157
|
});
|
|
206
158
|
|
|
207
159
|
test("contains: upper bound", () => {
|
|
208
160
|
assert.equal(
|
|
209
|
-
contains({ from: 10, to: 20 }, 20),
|
|
161
|
+
contains({ ...defaultBounds, from: 10, to: 20 }, 20),
|
|
210
162
|
true
|
|
211
163
|
);
|
|
212
164
|
});
|
|
@@ -214,39 +166,34 @@ describe("contains()", () => {
|
|
|
214
166
|
|
|
215
167
|
test("contains: gt excludes lower bound", () => {
|
|
216
168
|
assert.equal(
|
|
217
|
-
contains({ from: 5, fromOp: "$gt" }, 5),
|
|
169
|
+
contains({ ...defaultBounds, from: 5, fromOp: "$gt" }, 5),
|
|
218
170
|
false
|
|
219
171
|
);
|
|
220
172
|
});
|
|
221
173
|
|
|
222
174
|
test("contains: gte includes lower bound", () => {
|
|
223
175
|
assert.equal(
|
|
224
|
-
contains({ from: 5, fromOp: "$gte" }, 5),
|
|
176
|
+
contains({ ...defaultBounds, from: 5, fromOp: "$gte" }, 5),
|
|
225
177
|
true
|
|
226
178
|
);
|
|
227
179
|
});
|
|
228
180
|
|
|
229
181
|
test("contains: lt excludes upper bound", () => {
|
|
230
182
|
assert.equal(
|
|
231
|
-
contains({ to: 10, toOp: "$lt" }, 10),
|
|
183
|
+
contains({ ...defaultBounds, to: 10, toOp: "$lt" }, 10),
|
|
232
184
|
false
|
|
233
185
|
);
|
|
234
186
|
});
|
|
235
187
|
|
|
236
188
|
test("contains: lte includes upper bound", () => {
|
|
237
189
|
assert.equal(
|
|
238
|
-
contains({ to: 10, toOp: "$lte" }, 10),
|
|
190
|
+
contains({ ...defaultBounds, to: 10, toOp: "$lte" }, 10),
|
|
239
191
|
true
|
|
240
192
|
);
|
|
241
193
|
});
|
|
242
194
|
|
|
243
195
|
test("contains: gt/lt excludes both endpoints", () => {
|
|
244
|
-
const bounds = {
|
|
245
|
-
from: 5,
|
|
246
|
-
fromOp: "$gt",
|
|
247
|
-
to: 10,
|
|
248
|
-
toOp: "$lt"
|
|
249
|
-
};
|
|
196
|
+
const bounds = { ...defaultBounds, from: 5, fromOp: "$gt", to: 10, toOp: "$lt"};
|
|
250
197
|
|
|
251
198
|
assert.equal(contains(bounds, 5), false);
|
|
252
199
|
assert.equal(contains(bounds, 10), false);
|
|
@@ -254,12 +201,7 @@ describe("contains()", () => {
|
|
|
254
201
|
});
|
|
255
202
|
|
|
256
203
|
test("contains: gte/lte includes both endpoints", () => {
|
|
257
|
-
const bounds = {
|
|
258
|
-
from: 5,
|
|
259
|
-
fromOp: "$gte",
|
|
260
|
-
to: 10,
|
|
261
|
-
toOp: "$lte"
|
|
262
|
-
};
|
|
204
|
+
const bounds = { ...defaultBounds, from: 5, fromOp: "$gte", to: 10, toOp: "$lte" };
|
|
263
205
|
|
|
264
206
|
assert.equal(contains(bounds, 5), true);
|
|
265
207
|
assert.equal(contains(bounds, 10), true);
|
|
@@ -267,24 +209,14 @@ describe("contains()", () => {
|
|
|
267
209
|
});
|
|
268
210
|
|
|
269
211
|
test("contains: gt/lte mixed", () => {
|
|
270
|
-
const bounds = {
|
|
271
|
-
from: 5,
|
|
272
|
-
fromOp: "$gt",
|
|
273
|
-
to: 10,
|
|
274
|
-
toOp: "$lte"
|
|
275
|
-
};
|
|
212
|
+
const bounds = { ...defaultBounds, from: 5, fromOp: "$gt", to: 10, toOp: "$lte" };
|
|
276
213
|
|
|
277
214
|
assert.equal(contains(bounds, 5), false);
|
|
278
215
|
assert.equal(contains(bounds, 10), true);
|
|
279
216
|
});
|
|
280
217
|
|
|
281
218
|
test("contains: gte/lt mixed", () => {
|
|
282
|
-
const bounds = {
|
|
283
|
-
from: 5,
|
|
284
|
-
fromOp: "$gte",
|
|
285
|
-
to: 10,
|
|
286
|
-
toOp: "$lt"
|
|
287
|
-
};
|
|
219
|
+
const bounds = { ...defaultBounds, from: 5, fromOp: "$gte", to: 10, toOp: "$lt" };
|
|
288
220
|
|
|
289
221
|
assert.equal(contains(bounds, 5), true);
|
|
290
222
|
assert.equal(contains(bounds, 10), false);
|
|
@@ -292,39 +224,39 @@ describe("contains()", () => {
|
|
|
292
224
|
|
|
293
225
|
test("contains: value below lower bound", () => {
|
|
294
226
|
assert.equal(
|
|
295
|
-
contains({ from: 5, fromOp: "$gte" }, 4),
|
|
227
|
+
contains({ ...defaultBounds, from: 5, fromOp: "$gte" }, 4),
|
|
296
228
|
false
|
|
297
229
|
);
|
|
298
230
|
});
|
|
299
231
|
|
|
300
232
|
test("contains: value above upper bound", () => {
|
|
301
233
|
assert.equal(
|
|
302
|
-
contains({ to: 10, toOp: "$lte" }, 11),
|
|
234
|
+
contains({ ...defaultBounds, to: 10, toOp: "$lte" }, 11),
|
|
303
235
|
false
|
|
304
236
|
);
|
|
305
237
|
});
|
|
306
238
|
|
|
307
239
|
test("contains: open lower bound", () => {
|
|
308
240
|
assert.equal(
|
|
309
|
-
contains({ to: 10, toOp: "$lte" }, -1000),
|
|
241
|
+
contains({ ...defaultBounds, to: 10, toOp: "$lte" }, -1000),
|
|
310
242
|
true
|
|
311
243
|
);
|
|
312
244
|
});
|
|
313
245
|
|
|
314
246
|
test("contains: open upper bound", () => {
|
|
315
247
|
assert.equal(
|
|
316
|
-
contains({ from: 5, fromOp: "$gte" }, 1000),
|
|
248
|
+
contains({ ...defaultBounds, from: 5, fromOp: "$gte" }, 1000),
|
|
317
249
|
true
|
|
318
250
|
);
|
|
319
251
|
});
|
|
320
252
|
|
|
321
253
|
test("contains: completely unbounded", () => {
|
|
322
254
|
assert.equal(
|
|
323
|
-
contains({}, -100),
|
|
255
|
+
contains({ ...defaultBounds, }, -100),
|
|
324
256
|
true
|
|
325
257
|
);
|
|
326
258
|
assert.equal(
|
|
327
|
-
contains({}, 100),
|
|
259
|
+
contains({ ...defaultBounds, }, 100),
|
|
328
260
|
true
|
|
329
261
|
);
|
|
330
262
|
});
|
|
@@ -353,42 +285,42 @@ describe("intersects()", () => {
|
|
|
353
285
|
|
|
354
286
|
test("intersects: value ↔ range", () => {
|
|
355
287
|
assert.equal(
|
|
356
|
-
intersects([10], null, [], { from: 5 }),
|
|
288
|
+
intersects([10], null, [], { ...defaultBounds, from: 5 }),
|
|
357
289
|
true
|
|
358
290
|
);
|
|
359
291
|
});
|
|
360
292
|
|
|
361
293
|
test("intersects: value ↔ range miss", () => {
|
|
362
294
|
assert.equal(
|
|
363
|
-
intersects([2], null, [], { from: 5 }),
|
|
295
|
+
intersects([2], null, [], { ...defaultBounds, from: 5 }),
|
|
364
296
|
false
|
|
365
297
|
);
|
|
366
298
|
});
|
|
367
299
|
|
|
368
300
|
test("intersects: range ↔ value", () => {
|
|
369
301
|
assert.equal(
|
|
370
|
-
intersects([], { from: 5 }, [10], null),
|
|
302
|
+
intersects([], { ...defaultBounds, from: 5 }, [10], null),
|
|
371
303
|
true
|
|
372
304
|
);
|
|
373
305
|
});
|
|
374
306
|
|
|
375
307
|
test("intersects: range ↔ value miss", () => {
|
|
376
308
|
assert.equal(
|
|
377
|
-
intersects([], { from: 5 }, [2], null),
|
|
309
|
+
intersects([], { ...defaultBounds, from: 5 }, [2], null),
|
|
378
310
|
false
|
|
379
311
|
);
|
|
380
312
|
});
|
|
381
313
|
|
|
382
314
|
test("intersects: range ↔ range", () => {
|
|
383
315
|
assert.equal(
|
|
384
|
-
intersects([], { from: 10 }, [], { from: 20 }),
|
|
316
|
+
intersects([], { ...defaultBounds, from: 10 }, [], { ...defaultBounds, from: 20 }),
|
|
385
317
|
true
|
|
386
318
|
);
|
|
387
319
|
});
|
|
388
320
|
|
|
389
321
|
test("intersects: range ↔ range miss", () => {
|
|
390
322
|
assert.equal(
|
|
391
|
-
intersects([], { to: 5 }, [], { from: 10 }),
|
|
323
|
+
intersects([], { ...defaultBounds, to: 5 }, [], { ...defaultBounds, from: 10 }),
|
|
392
324
|
false
|
|
393
325
|
);
|
|
394
326
|
});
|
|
@@ -229,7 +229,7 @@ describe("suffix()", () => {
|
|
|
229
229
|
{
|
|
230
230
|
type: "boolean",
|
|
231
231
|
value: true
|
|
232
|
-
}
|
|
232
|
+
} as any
|
|
233
233
|
],
|
|
234
234
|
true,
|
|
235
235
|
arg
|
|
@@ -249,7 +249,7 @@ describe("suffix()", () => {
|
|
|
249
249
|
[
|
|
250
250
|
{
|
|
251
251
|
key: "id"
|
|
252
|
-
}
|
|
252
|
+
} as any
|
|
253
253
|
],
|
|
254
254
|
true,
|
|
255
255
|
arg
|
package/libs/dip.ts
CHANGED
|
@@ -18,6 +18,8 @@ export const companyMeta = Elabase.companyMeta
|
|
|
18
18
|
export const outletMeta = Elabase.outletMeta
|
|
19
19
|
export const customMeta = Elabase.customMeta
|
|
20
20
|
export const schema = Elabase.schema
|
|
21
|
+
export type DipMeta = Elabase.DipMeta;
|
|
22
|
+
export const DipMeta = Elabase.DipMeta;
|
|
21
23
|
export const isDipMeta = Elabase.isDipMeta
|
|
22
24
|
export const excludeCollectionConfig = Elabase.excludeCollectionConfig
|
|
23
25
|
export const includeCollectionConfig = Elabase.includeCollectionConfig
|
|
@@ -25,7 +27,21 @@ export const includeCollectionConfig = Elabase.includeCollectionConfig
|
|
|
25
27
|
export const shard_stats = Elabase.shard_stats
|
|
26
28
|
export let config = Elabase.config
|
|
27
29
|
|
|
28
|
-
|
|
30
|
+
|
|
31
|
+
type DipQuery = Parameters<typeof Elabase.update>[2]
|
|
32
|
+
type DipUpdate = Parameters<typeof Elabase.update>[3]
|
|
33
|
+
|
|
34
|
+
type IdempotentDip = {
|
|
35
|
+
new: (meta: Elabase.DipMeta, txn: string, blank?: { blank: boolean }) => Promise<IdempotentDip | false>
|
|
36
|
+
insert: (collection: string, query: DipQuery, data: DipUpdate) => Promise<void>
|
|
37
|
+
update: (collection: string, query: DipQuery, data: DipUpdate, rollback?: boolean) => Promise<boolean | number>
|
|
38
|
+
upsert: (collection: string, query: DipQuery, data: DipUpdate, rollback?: boolean) => Promise<boolean | number>
|
|
39
|
+
cleanup: (collection: string, query: DipQuery) => Promise<void>
|
|
40
|
+
finish: () => Promise<unknown>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
export async function insertSync(meta: Elabase.DipMeta, feature: string, date: number, uid: string, ref: unknown, type: "REMOVE" | "UPSERT") {
|
|
29
45
|
let stamp = new Date(date).toISOString()
|
|
30
46
|
let _id = `${meta.outlet}_${stamp}_${uid}`
|
|
31
47
|
let data = { _id, ref, type: type === "REMOVE" ? type : "UPSERT" }
|
|
@@ -33,44 +49,56 @@ export async function insertSync(meta, feature, date, uid, ref, type) {
|
|
|
33
49
|
await Elabase.insert(meta, collection, data)
|
|
34
50
|
}
|
|
35
51
|
|
|
36
|
-
export const IdempotentDip = () => {
|
|
37
|
-
|
|
52
|
+
export const IdempotentDip = (): IdempotentDip => {
|
|
53
|
+
const state = {
|
|
38
54
|
txn: '',
|
|
39
|
-
meta: undefined,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}),
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
55
|
+
meta: undefined as Elabase.DipMeta | undefined,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const idip = {} as IdempotentDip
|
|
59
|
+
|
|
60
|
+
idip.new = async function (meta: Elabase.DipMeta, txn: string, blank?: {blank: boolean}) {
|
|
61
|
+
state.txn = txn
|
|
62
|
+
state.meta = meta
|
|
63
|
+
return blank ? idip : ((await Elabase.query(state.meta, "txns",{_id: state.txn})).length ? false : idip)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
idip.insert = async function (collection, query, data) {
|
|
67
|
+
await Elabase.update(state.meta, collection, query, { $setOnInsert: data }, {upsert: true})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
idip.update = async function (collection, query, data, rollback) {
|
|
71
|
+
let token = { [state.txn]: true }
|
|
72
|
+
let idempotent = { [state.txn]: { $exists: rollback ?? false } }
|
|
73
|
+
let result = await Elabase.update(state.meta, collection, {...query, ...idempotent}, {...data, $setOnInsert: undefined, $set: {...(data.$set ?? {}), ...token} })
|
|
74
|
+
return result.count ? true : (await Elabase.query(state.meta, collection, {...query, ...idempotent})).length
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
idip.upsert = async function (collection, query, data, rollback) {
|
|
78
|
+
await idip.insert(collection, query, data.$setOnInsert)
|
|
79
|
+
return await idip.update(collection, query, data, rollback)
|
|
64
80
|
}
|
|
81
|
+
|
|
82
|
+
idip.cleanup = async function (collection, query) {
|
|
83
|
+
await Elabase.update(state.meta, collection, query, { $unset: { [state.txn]: true } })
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
idip.finish = async function () {
|
|
87
|
+
return await Elabase.update(state.meta, "txns",{_id: state.txn}, {}, {upsert: true})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return idip
|
|
65
91
|
}
|
|
66
92
|
|
|
93
|
+
type DipMessage = { meta: {staff: string; user: string}; txn: string; date: number }
|
|
94
|
+
type IdipCleanup = Record<string, string[]> | ((idip: IdempotentDip) => Promise<void>)
|
|
67
95
|
|
|
68
|
-
export const idip = async (message,
|
|
96
|
+
export const idip = async (message: {meta: Elabase.DipMeta, txn: string}, callback: (idip: IdempotentDip) => Promise<void>, cleanup: IdipCleanup) => {
|
|
69
97
|
if (!callback)
|
|
70
98
|
throw new Error("Dip.idip() callback argument undefined")
|
|
71
99
|
if (!cleanup)
|
|
72
100
|
throw new Error("Dip.idip() cleanup argument undefined")
|
|
73
|
-
async function doCleanup(IDip) {
|
|
101
|
+
async function doCleanup(IDip: IdempotentDip) {
|
|
74
102
|
if (typeof cleanup === 'object') {
|
|
75
103
|
for (let collection in cleanup)
|
|
76
104
|
await IDip.cleanup(collection, { _id: {$in: cleanup[collection]} })
|
|
@@ -81,7 +109,7 @@ export const idip = async (message, callback, cleanup) => {
|
|
|
81
109
|
let IDip = await IdempotentDip().new(message.meta, message.txn)
|
|
82
110
|
if (!IDip) {
|
|
83
111
|
IDip = await IdempotentDip().new(message.meta, message.txn, {blank: true})
|
|
84
|
-
await doCleanup(IDip)
|
|
112
|
+
await doCleanup(IDip as IdempotentDip)
|
|
85
113
|
return
|
|
86
114
|
}
|
|
87
115
|
await callback(IDip)
|
|
@@ -90,7 +118,7 @@ export const idip = async (message, callback, cleanup) => {
|
|
|
90
118
|
}
|
|
91
119
|
|
|
92
120
|
|
|
93
|
-
export const insertKeys = (message, meta) => {
|
|
121
|
+
export const insertKeys = (message: DipMessage, meta: Elabase.DipMeta) => {
|
|
94
122
|
if (!isDipMeta(meta)) throw new Error('Error: Provided meta is not an instance of DipMeta in Dip.insertKeys()')
|
|
95
123
|
return {
|
|
96
124
|
"created": message.date, "updated": message.date,
|
|
@@ -102,7 +130,7 @@ export const insertKeys = (message, meta) => {
|
|
|
102
130
|
...(meta?.outlet ? {"outlet": meta.outlet} : {}),
|
|
103
131
|
}
|
|
104
132
|
}
|
|
105
|
-
export const updateKeys = message => {
|
|
133
|
+
export const updateKeys = (message: DipMessage) => {
|
|
106
134
|
return {
|
|
107
135
|
"updated": message.date,
|
|
108
136
|
"updatedBy": message.meta.staff,
|
package/libs/dipper.ts
CHANGED
|
@@ -2,7 +2,21 @@
|
|
|
2
2
|
import axios from 'axios'
|
|
3
3
|
// import {curly} from 'node-libcurl'
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
type DipperIdQuery = string | string[] | { $in: string[] }
|
|
7
|
+
|
|
8
|
+
type DipperArg = {
|
|
9
|
+
mode: string
|
|
10
|
+
query?: {
|
|
11
|
+
_id?: DipperIdQuery
|
|
12
|
+
}
|
|
13
|
+
insert?: {
|
|
14
|
+
_id?: DipperIdQuery
|
|
15
|
+
}
|
|
16
|
+
[key: string]: unknown
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function hashStr(str: string) {
|
|
6
20
|
let hash = 0;
|
|
7
21
|
for (let i = 0; i < str.length; i++) {
|
|
8
22
|
let charCode = str.charCodeAt(i);
|
|
@@ -11,7 +25,7 @@ function hashStr(str) {
|
|
|
11
25
|
return hash;
|
|
12
26
|
}
|
|
13
27
|
|
|
14
|
-
function hash(string, digits) {
|
|
28
|
+
function hash(string: string, digits: number) {
|
|
15
29
|
digits = digits || 6;
|
|
16
30
|
var m = Math.pow(10, digits+1) - 1;
|
|
17
31
|
var phi = Math.pow(10, digits) / 2 - 1;
|
|
@@ -21,7 +35,7 @@ function hash(string, digits) {
|
|
|
21
35
|
}
|
|
22
36
|
return n.toString();
|
|
23
37
|
}
|
|
24
|
-
let shards = []
|
|
38
|
+
let shards: string[] = []
|
|
25
39
|
let shardCount = 20
|
|
26
40
|
|
|
27
41
|
for (let i = 1; i <= shardCount; i++)
|
|
@@ -31,13 +45,13 @@ for (let i = 1; i <= shardCount; i++)
|
|
|
31
45
|
// function shard(key) {
|
|
32
46
|
// return hash(key,1) % shardCount
|
|
33
47
|
// }
|
|
34
|
-
function shard(key) {
|
|
48
|
+
function shard(key: string) {
|
|
35
49
|
return hashStr(key) % shardCount
|
|
36
50
|
}
|
|
37
51
|
|
|
38
|
-
export let shard_hits = {}
|
|
52
|
+
export let shard_hits: Record<string, number> = {}
|
|
39
53
|
|
|
40
|
-
async function postDip(url, arg) {
|
|
54
|
+
async function postDip(url: string | URL, arg: unknown) {
|
|
41
55
|
return (await axios.post(url, arg)).data
|
|
42
56
|
// curl
|
|
43
57
|
// -----
|
|
@@ -51,7 +65,7 @@ async function postDip(url, arg) {
|
|
|
51
65
|
// return data
|
|
52
66
|
}
|
|
53
67
|
|
|
54
|
-
export default async function dipper(arg) {
|
|
68
|
+
export default async function dipper(arg: DipperArg) {
|
|
55
69
|
|
|
56
70
|
let result = []
|
|
57
71
|
|
|
@@ -66,11 +80,12 @@ export default async function dipper(arg) {
|
|
|
66
80
|
|
|
67
81
|
} else {
|
|
68
82
|
|
|
69
|
-
|
|
83
|
+
type InList = {$in: string[]}
|
|
84
|
+
let ids = typeof _id == "object" ? (_id as InList).$in : [_id]
|
|
70
85
|
for (let id of ids) {
|
|
71
86
|
let key = shard(id)
|
|
72
87
|
let url = shards[key]
|
|
73
|
-
shard_hits[url] = (shard_hits[url] ?? 0) + 1
|
|
88
|
+
shard_hits[url!] = (shard_hits[url!] ?? 0) + 1
|
|
74
89
|
result.push(await postDip(`http://${url}/execute`, arg))
|
|
75
90
|
}
|
|
76
91
|
}
|
|
@@ -86,7 +101,7 @@ export default async function dipper(arg) {
|
|
|
86
101
|
|
|
87
102
|
export const shard_stats = () => {
|
|
88
103
|
let total: number = (Object.values(shard_hits) as number[]).reduce( (partial: number, value: number) => partial + value, 0)
|
|
89
|
-
let result = {}
|
|
104
|
+
let result: Record<string, string> = {}
|
|
90
105
|
Object.entries(shard_hits).forEach( ([key, value]) => result[key] = ((value as number) * 100 / total).toFixed(2) )
|
|
91
106
|
return result
|
|
92
107
|
}
|