corebasic 1.0.232 → 1.0.233
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 +3 -3
- package/dist/libs/dip/suffix/index.js +1 -1
- package/dist/libs/dip/suffix/suffix.js +2 -3
- package/dist/libs/dip/suffix/tests/policy.applySuffixPolicy.test.js +26 -99
- package/dist/libs/dip/suffix/tests/policy.test.js +1 -1
- package/dist/libs/dipper.js +13 -12
- package/dist/libs/elabase.js +36 -45
- package/dist/libs/features.js +5 -4
- package/dist/libs/kafka.js +2 -3
- package/dist/libs/messaging.js +1 -1
- package/dist/libs/utils.js +1 -1
- package/libs/auth.ts +3 -3
- package/libs/dip/suffix/index.ts +1 -1
- package/libs/dip/suffix/policy.ts +1 -1
- package/libs/dip/suffix/suffix.ts +3 -4
- package/libs/dip/suffix/tests/policy.applySuffixPolicy.test.ts +26 -180
- package/libs/dip/suffix/tests/policy.test.ts +1 -1
- package/libs/dip.ts +5 -5
- package/libs/dipper.ts +14 -13
- package/libs/elabase.ts +172 -126
- package/libs/features.ts +10 -9
- package/libs/kafka.ts +3 -3
- package/libs/messaging.ts +1 -1
- package/libs/utils.ts +1 -1
- package/package.json +1 -1
- package/tsconfig.json +16 -1
package/libs/elabase.ts
CHANGED
|
@@ -15,7 +15,7 @@ export const shard_stats = ShardStats
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
let Events = {
|
|
18
|
-
send: function(
|
|
18
|
+
send: function(_topic?: string, _data?: any) { }
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
|
|
@@ -24,7 +24,7 @@ let Events = {
|
|
|
24
24
|
const url = process.env.DIP_URL || "http://127.0.0.1"; // Set DIP_URL to "http://dip" (Prod) or http://dip-dev (Dev) in CI/CD
|
|
25
25
|
let port = process.env.DIP_PORT || 9401
|
|
26
26
|
let api = 'execute'
|
|
27
|
-
let fullurl = `${url}:${port}/${api}`
|
|
27
|
+
// let fullurl = `${url}:${port}/${api}`
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
let Elabase = {
|
|
@@ -38,8 +38,10 @@ let Elabase = {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
type Internal = {db: undefined | string, engineName: "lmdb" | "sled" | "sanakirja"}
|
|
42
|
+
|
|
41
43
|
let engine = Elabase.Engine.Lmdb
|
|
42
|
-
let internal = {
|
|
44
|
+
let internal: Internal = {
|
|
43
45
|
db: undefined,
|
|
44
46
|
engineName: engine === Elabase.Engine.Lmdb ? "lmdb" : (engine === Elabase.Engine.Sled ? "sled" : engine === Elabase.Engine.Sanakirja ? "sanakirja" : "lmdb")
|
|
45
47
|
}
|
|
@@ -47,14 +49,14 @@ let internal = {
|
|
|
47
49
|
let db = internal.db // default database
|
|
48
50
|
|
|
49
51
|
|
|
50
|
-
export function start(dbName) {
|
|
52
|
+
export function start(dbName: string) {
|
|
51
53
|
if (!Utils.isEmpty(dbName) && Utils.isEmpty(db)) {
|
|
52
54
|
internal.db = "data/" + dbName
|
|
53
55
|
db = "data/" + dbName
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
function deepFreeze(obj) {
|
|
59
|
+
function deepFreeze(obj: Record<string, any>) {
|
|
58
60
|
if (obj && typeof obj === "object" && !Object.isFrozen(obj)) {
|
|
59
61
|
Object.freeze(obj);
|
|
60
62
|
|
|
@@ -65,20 +67,28 @@ function deepFreeze(obj) {
|
|
|
65
67
|
return obj;
|
|
66
68
|
}
|
|
67
69
|
export class DipMeta {
|
|
68
|
-
declare company?: string;
|
|
69
|
-
declare outlet?: string;
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
declare company?: string | string[];
|
|
71
|
+
declare outlet?: string | string[];
|
|
72
|
+
declare suffix?: string | string[];
|
|
73
|
+
declare syncMode?: boolean;
|
|
74
|
+
declare db?: string;
|
|
75
|
+
declare DIP_DB?: string;
|
|
76
|
+
declare DIP_URL?: string;
|
|
77
|
+
declare executor?: "native" | "raw";
|
|
78
|
+
declare batch?: string;
|
|
79
|
+
declare allowDangerousRemove?: boolean;
|
|
80
|
+
|
|
81
|
+
constructor(obj: Record<string, unknown>) {
|
|
72
82
|
Object.assign(this, deepFreeze(obj));
|
|
73
83
|
Object.freeze(this);
|
|
74
84
|
}
|
|
75
85
|
}
|
|
76
|
-
export const isDipMeta = meta => meta instanceof DipMeta
|
|
86
|
+
export const isDipMeta = (meta: DipMeta) => meta instanceof DipMeta
|
|
77
87
|
|
|
78
88
|
export const globalMeta = (args?: any) => {
|
|
79
89
|
return new DipMeta({ ...args, company: "GLOBAL", outlet: "GLOBAL" })
|
|
80
90
|
}
|
|
81
|
-
export const companyMeta = (company, args?: any) => {
|
|
91
|
+
export const companyMeta = (company: string | string[], args?: any) => {
|
|
82
92
|
if (typeof company !== "string" && !Array.isArray(company))
|
|
83
93
|
throw new Error("Error: Invalid company provided in Dip.companyMeta()")
|
|
84
94
|
if (!company || (typeof company === "string" && company.trim() === "") || company === "GLOBAL" || (Array.isArray(company) && (!company.length || company.some(item => typeof item !== "string" || item.trim() === "" || item === "GLOBAL")) ))
|
|
@@ -86,7 +96,7 @@ export const companyMeta = (company, args?: any) => {
|
|
|
86
96
|
|
|
87
97
|
return new DipMeta({...args, outlet: "GLOBAL", company})
|
|
88
98
|
}
|
|
89
|
-
export const outletMeta = (outlet, args?: any) => {
|
|
99
|
+
export const outletMeta = (outlet: string | string[], args?: any) => {
|
|
90
100
|
if (typeof outlet !== "string" && !Array.isArray(outlet))
|
|
91
101
|
throw new Error("Error: Invalid outlet provided in Dip.outletMeta()")
|
|
92
102
|
if (!outlet || (typeof outlet === "string" && outlet.trim() === "") || outlet === "GLOBAL" || (Array.isArray(outlet) && (!outlet.length || outlet.some(item => typeof item !== "string" || item.trim() === "" || item === "GLOBAL")) ))
|
|
@@ -95,7 +105,7 @@ export const outletMeta = (outlet, args?: any) => {
|
|
|
95
105
|
return new DipMeta({...args, company: "GLOBAL", outlet})
|
|
96
106
|
}
|
|
97
107
|
|
|
98
|
-
export const customMeta = (company, outlet, args?: any) => {
|
|
108
|
+
export const customMeta = (company: string | string[], outlet: string | string[], args?: any) => {
|
|
99
109
|
|
|
100
110
|
if (typeof company !== "string" && !Array.isArray(company))
|
|
101
111
|
throw new Error("Error: Invalid company provided in Dip.customMeta()")
|
|
@@ -110,13 +120,13 @@ export const customMeta = (company, outlet, args?: any) => {
|
|
|
110
120
|
return new DipMeta({...args, company, outlet})
|
|
111
121
|
}
|
|
112
122
|
|
|
113
|
-
function validate_collection(collection, fn_name) {
|
|
123
|
+
function validate_collection(collection: string | string[], fn_name: string) {
|
|
114
124
|
if ((typeof collection === 'string' && collection.trim() === "") || (typeof collection !== 'string' && !Array.isArray(collection)) || (Array.isArray(collection) && (!collection.length || collection.some(item => typeof item !== "string" || item.trim() === "")))) {
|
|
115
125
|
throw new Error(`Error: Invalid collection ${fn_name}`)
|
|
116
126
|
}
|
|
117
127
|
}
|
|
118
128
|
|
|
119
|
-
function validate_meta(meta, fn_name) {
|
|
129
|
+
function validate_meta(meta: DipMeta, fn_name: string) {
|
|
120
130
|
if (!meta || typeof meta !== 'object') {
|
|
121
131
|
throw new Error(`Error: Invalid meta ${fn_name}`)
|
|
122
132
|
}
|
|
@@ -132,7 +142,7 @@ function validate_meta(meta, fn_name) {
|
|
|
132
142
|
throw new Error(`Error: Invalid meta.suffix ${fn_name}`)
|
|
133
143
|
}
|
|
134
144
|
|
|
135
|
-
function generate_suffix(meta) {
|
|
145
|
+
function generate_suffix(meta: DipMeta) {
|
|
136
146
|
|
|
137
147
|
// Assuming validate_meta() is called before reaching here. If not then this is intentional validation bypass
|
|
138
148
|
|
|
@@ -148,9 +158,9 @@ function generate_suffix(meta) {
|
|
|
148
158
|
outlet = outlet.length ? outlet : [""]
|
|
149
159
|
suffix = suffix.length ? suffix : [""]
|
|
150
160
|
|
|
151
|
-
company = new Set(company)
|
|
152
|
-
outlet = new Set(outlet)
|
|
153
|
-
suffix = new Set(suffix)
|
|
161
|
+
company = [...new Set(company)]
|
|
162
|
+
outlet = [...new Set(outlet)]
|
|
163
|
+
suffix = [...new Set(suffix)]
|
|
154
164
|
|
|
155
165
|
// console.log(company, outlet, suffix)
|
|
156
166
|
let suffixes = []
|
|
@@ -170,21 +180,36 @@ function generate_suffix(meta) {
|
|
|
170
180
|
|
|
171
181
|
// Ported
|
|
172
182
|
let BATCH_COUNTER = 0n;
|
|
173
|
-
let batches = {}
|
|
183
|
+
let batches: Record<string, (InsertRequest | QueryRequest | UpdateRequest | RemoveRequest)[]> = {}
|
|
174
184
|
|
|
175
185
|
// Ported
|
|
176
|
-
export function batchBegin() { // Manual Lifecycle. If you forget to batchSubmit() or batchAbort(), then memory leak due to dangling batch
|
|
177
|
-
const uid = ++BATCH_COUNTER; // Safe. No skew in async ++BATCH_COUNTER
|
|
178
|
-
batches[uid
|
|
186
|
+
export function batchBegin(): string { // Manual Lifecycle. If you forget to batchSubmit() or batchAbort(), then memory leak due to dangling batch
|
|
187
|
+
const uid = (++BATCH_COUNTER).toString(); // Safe. No skew in async ++BATCH_COUNTER. Single thread ++COUNTER is atomic in event loop sense. ⚠️ Breaks on worker_threads or cluster (multi-process)
|
|
188
|
+
batches[uid] = []
|
|
179
189
|
return uid
|
|
180
190
|
}
|
|
181
191
|
// Ported
|
|
182
|
-
export function batchAbort(batch_id) { // Mandatory to prevent meory leak due to dangling batch if batchBegin() is called without batchSubmit()
|
|
192
|
+
export function batchAbort(batch_id: string) { // Mandatory to prevent meory leak due to dangling batch if batchBegin() is called without batchSubmit()
|
|
183
193
|
delete batches[batch_id]
|
|
184
194
|
}
|
|
185
195
|
|
|
196
|
+
|
|
197
|
+
type BufferItem = {buf: Buffer | Uint8Array; vlq: Uint8Array}
|
|
198
|
+
type HashItem = {buf: Buffer | Uint8Array; offset: number}
|
|
199
|
+
type RawManager = {
|
|
200
|
+
buffers: BufferItem[];
|
|
201
|
+
size: number;
|
|
202
|
+
hashes: Map<bigint, HashItem[]>;
|
|
203
|
+
add: (value: Buffer | string | number | any) => number | undefined;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
type BatchArg = {
|
|
207
|
+
db?: string, collection?: string | string[], suffix?: string | string[],
|
|
208
|
+
executor?: "native" | "raw" | undefined, syncMode?: false | undefined, raw?: RawManager | undefined, engine?: string | undefined, port?: number | undefined, timeout?: number | undefined, version?: boolean | undefined, compression?: boolean | undefined
|
|
209
|
+
}
|
|
210
|
+
|
|
186
211
|
// Ported
|
|
187
|
-
export const batch = async (callback
|
|
212
|
+
export const batch = async (callback: (batch_id: string) => Promise<void>, arg: BatchArg) => { // Convenience function with auto lifecyle management and auto submit when callback returns. abort is called appropriately.
|
|
188
213
|
/**
|
|
189
214
|
* Usage:
|
|
190
215
|
* const result = await Dip.batch(async batch => {
|
|
@@ -205,8 +230,9 @@ export const batch = async (callback, arg) => { // Convenience function with aut
|
|
|
205
230
|
}
|
|
206
231
|
}
|
|
207
232
|
|
|
233
|
+
|
|
208
234
|
// Ported
|
|
209
|
-
export function batchSubmit(batch_id, arg) {
|
|
235
|
+
export function batchSubmit(batch_id: string, arg: BatchArg) {
|
|
210
236
|
if (!batch_id || !batches[batch_id] || !batches[batch_id].length)
|
|
211
237
|
throw new Error(`Error: Invalid batch in Dip.batchSubmit()`)
|
|
212
238
|
let txns = batches[batch_id]
|
|
@@ -217,8 +243,8 @@ export function batchSubmit(batch_id, arg) {
|
|
|
217
243
|
const port = arg?.port
|
|
218
244
|
const timeout = arg?.timeout
|
|
219
245
|
delete batches[batch_id]
|
|
220
|
-
return new Promise<void>((resolve,
|
|
221
|
-
.then(() => execute({ "batch": txns, version: arg?.version, raw, engine, compression: arg?.compression, executor, syncMode, port, timeout }))
|
|
246
|
+
return new Promise<void>((resolve, _reject) => resolve())
|
|
247
|
+
.then(() => execute({ "batch": txns, version: arg?.version, raw, engine, compression: arg?.compression, executor: executor ?? "native", syncMode: syncMode ?? false, port, timeout }))
|
|
222
248
|
.then (result => {
|
|
223
249
|
Events.send("Dip.batchSubmit", { response: result })
|
|
224
250
|
return result
|
|
@@ -229,8 +255,8 @@ let PROJECT_ROOT_URL = new URL('../../..', import.meta.url)
|
|
|
229
255
|
if (String(PROJECT_ROOT_URL).endsWith('node_modules/'))
|
|
230
256
|
PROJECT_ROOT_URL = new URL('..', PROJECT_ROOT_URL)
|
|
231
257
|
|
|
232
|
-
const SCHEMAS_JSON_PROMISES = {}
|
|
233
|
-
export const schema = async (name) => {
|
|
258
|
+
const SCHEMAS_JSON_PROMISES: Record<string, Promise<unknown>> = {}
|
|
259
|
+
export const schema = async (name: string) => {
|
|
234
260
|
// Cache the loading promise right away so parallel requests share it
|
|
235
261
|
if (!SCHEMAS_JSON_PROMISES[name])
|
|
236
262
|
SCHEMAS_JSON_PROMISES[name] = Utils.fileToJson(PROJECT_ROOT_URL, `schemas/${name}.json`)
|
|
@@ -245,18 +271,26 @@ export const schema = async (name) => {
|
|
|
245
271
|
}
|
|
246
272
|
}
|
|
247
273
|
|
|
248
|
-
|
|
274
|
+
|
|
275
|
+
type CoreConfig = { company?: string | {}, outlet?: string | {}, }
|
|
276
|
+
type CollectionConfig = CoreConfig & { suffix?: Record<string, CoreConfig> }
|
|
277
|
+
|
|
278
|
+
type SuffixItem = { key?: string; value?: string; type: string; ls_threshold?: number; min?: number; max?: number }
|
|
279
|
+
type CollectionsJsonType = Record<string, CollectionConfig & {policy?: {when: object, suffix: SuffixItem[]}[]}>
|
|
280
|
+
|
|
281
|
+
const COLLECTIONS_JSON: CollectionsJsonType = await (async () => {
|
|
249
282
|
try {
|
|
250
|
-
return await Utils.fileToJson(PROJECT_ROOT_URL, 'collections.json')
|
|
283
|
+
return await Utils.fileToJson(PROJECT_ROOT_URL, 'collections.json') as CollectionsJsonType
|
|
251
284
|
} catch(e) {
|
|
252
285
|
console.error(e)
|
|
253
286
|
console.warn("Warn: Dip Failed to load collections.json. Semantics, topology and legality enforcement is not active")
|
|
254
287
|
}
|
|
288
|
+
return {}
|
|
255
289
|
})();
|
|
256
290
|
|
|
257
291
|
function init_collections_config() {
|
|
258
292
|
for (let collection in COLLECTIONS_JSON) {
|
|
259
|
-
let config = COLLECTIONS_JSON[collection]
|
|
293
|
+
let config = COLLECTIONS_JSON[collection]!
|
|
260
294
|
if (config.suffix !== undefined && (typeof config.suffix !== "object" || Array.isArray(config.suffix)) ) {
|
|
261
295
|
throw new Error(`Error: Initiating collection configs failed. Invalid suffix in collection: ${collection}`)
|
|
262
296
|
}
|
|
@@ -265,15 +299,16 @@ function init_collections_config() {
|
|
|
265
299
|
if (COLLECTIONS_JSON)
|
|
266
300
|
init_collections_config()
|
|
267
301
|
|
|
268
|
-
const EXCLUDED_COLLECTIONS_CONFIG = {}
|
|
269
|
-
export function excludeCollectionConfig(collection) {
|
|
302
|
+
const EXCLUDED_COLLECTIONS_CONFIG: Record<string, boolean> = {}
|
|
303
|
+
export function excludeCollectionConfig(collection: string) {
|
|
270
304
|
EXCLUDED_COLLECTIONS_CONFIG[collection] = true
|
|
271
305
|
}
|
|
272
|
-
export function includeCollectionConfig(collection) {
|
|
306
|
+
export function includeCollectionConfig(collection: string) {
|
|
273
307
|
delete EXCLUDED_COLLECTIONS_CONFIG[collection]
|
|
274
308
|
}
|
|
275
309
|
|
|
276
|
-
function validate_topology(meta,
|
|
310
|
+
function validate_topology(meta: DipMeta, cols: string | string[], fn_name: string) {
|
|
311
|
+
const collection = typeof cols === "string" ? cols : cols[0]! // TODO: arrays
|
|
277
312
|
|
|
278
313
|
let new_meta = meta
|
|
279
314
|
|
|
@@ -284,7 +319,7 @@ function validate_topology(meta, collection, fn_name) {
|
|
|
284
319
|
return new_meta
|
|
285
320
|
}
|
|
286
321
|
|
|
287
|
-
function check_core_meta(config, meta, suffix?: string) {
|
|
322
|
+
function check_core_meta(config: CoreConfig, meta: DipMeta, suffix?: string) {
|
|
288
323
|
if (config.company !== meta.company && typeof config.company !== "object")
|
|
289
324
|
throw new Error(`Error: Incompatible meta.company config for collection: ${collection}${suffix ? ' suffix: ' + suffix : ''}${fn_name ? ` ${fn_name}` : ''}`)
|
|
290
325
|
if (config.outlet !== meta.outlet && typeof config.outlet !== "object")
|
|
@@ -293,13 +328,14 @@ function validate_topology(meta, collection, fn_name) {
|
|
|
293
328
|
|
|
294
329
|
check_core_meta(config, meta)
|
|
295
330
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
331
|
+
const meta_suffix = meta.suffix as string // TODO: use loop
|
|
332
|
+
if (config.suffix && meta_suffix) {
|
|
333
|
+
if (!config.suffix[meta_suffix]) {
|
|
334
|
+
console.warn(`Warn: Missing suffix config for collection: ${collection} suffix:${meta_suffix}${fn_name ? ` ${fn_name}` : ''}`)
|
|
299
335
|
return new_meta
|
|
300
336
|
}
|
|
301
|
-
check_core_meta(config.suffix[
|
|
302
|
-
new_meta = Object.assign({}, {...config, suffix: undefined, company: undefined, outlet: undefined}, {...config.suffix[
|
|
337
|
+
check_core_meta(config.suffix[meta_suffix], meta, meta_suffix)
|
|
338
|
+
new_meta = Object.assign({}, {...config, suffix: undefined, company: undefined, outlet: undefined}, {...config.suffix[meta_suffix], company: undefined, outlet: undefined}, meta)
|
|
303
339
|
} else {
|
|
304
340
|
new_meta = Object.assign({}, {...config, suffix: undefined, company: undefined, outlet: undefined}, {company: undefined, outlet: undefined}, meta)
|
|
305
341
|
}
|
|
@@ -308,7 +344,7 @@ function validate_topology(meta, collection, fn_name) {
|
|
|
308
344
|
}
|
|
309
345
|
|
|
310
346
|
// Ported
|
|
311
|
-
export const operation = async (name, extras) => {
|
|
347
|
+
export const operation = async (name: string, extras: BatchArg) => {
|
|
312
348
|
return execute({ operation: name, ...extras })
|
|
313
349
|
}
|
|
314
350
|
|
|
@@ -318,6 +354,8 @@ type Options = {
|
|
|
318
354
|
idempotent: boolean;
|
|
319
355
|
$orderby: any;
|
|
320
356
|
$fields: any;
|
|
357
|
+
$rangeFrom: any;
|
|
358
|
+
$rangeTo: any;
|
|
321
359
|
_id?: string | number;
|
|
322
360
|
}
|
|
323
361
|
type InsertRequest = {
|
|
@@ -325,11 +363,11 @@ type InsertRequest = {
|
|
|
325
363
|
executor: "native" | "raw";
|
|
326
364
|
collection: string[];
|
|
327
365
|
suffix: string | string[];
|
|
328
|
-
_id?: string | number;
|
|
366
|
+
_id?: string | number | undefined;
|
|
329
367
|
insert: number | any;
|
|
330
368
|
options: Options;
|
|
331
|
-
syncMode
|
|
332
|
-
DIP_URL?: string;
|
|
369
|
+
syncMode?: boolean;
|
|
370
|
+
DIP_URL?: string | undefined;
|
|
333
371
|
DIP_DB?: string;
|
|
334
372
|
}
|
|
335
373
|
|
|
@@ -337,8 +375,22 @@ type QueryRequest = Omit<InsertRequest, "_id" | "insert"> & { query: any }
|
|
|
337
375
|
type UpdateRequest = Omit<InsertRequest, "insert"> & { query: any, update: any }
|
|
338
376
|
type RemoveRequest = QueryRequest & { delete: true }
|
|
339
377
|
|
|
378
|
+
type BatchItem = (InsertRequest | QueryRequest | UpdateRequest | RemoveRequest)
|
|
379
|
+
type DipRequest = Omit<BatchItem, "syncMode" | "collection" | "suffix" | "options" | "executor" | "db" | "_id"> &
|
|
380
|
+
Omit<BatchArg, "syncMode" | "collection" | "suffix" | "options" | "executor" | "db" | "_id"> & {
|
|
381
|
+
batch?: BatchItem[],
|
|
382
|
+
syncMode?: boolean | undefined,
|
|
383
|
+
operation?: string,
|
|
384
|
+
options?: Options,
|
|
385
|
+
executor?: "native" | "raw" | undefined,
|
|
386
|
+
db?: string,
|
|
387
|
+
collection?: string | string[],
|
|
388
|
+
suffix?: string | string[],
|
|
389
|
+
_id?: string | number | undefined,
|
|
390
|
+
}
|
|
391
|
+
|
|
340
392
|
// Ported
|
|
341
|
-
export const insert = async (meta, collection, value, options?: any, extras?: any) => {
|
|
393
|
+
export const insert = async (meta: DipMeta, collection: string | string[], value: any, options?: any, extras?: any) => {
|
|
342
394
|
|
|
343
395
|
if (!(meta instanceof DipMeta)) console.warn('Warn: Provided meta is not an instance of DipMeta in Dip.insert()') // TODO: throw error once review completes
|
|
344
396
|
|
|
@@ -352,7 +404,7 @@ export const insert = async (meta, collection, value, options?: any, extras?: an
|
|
|
352
404
|
collection: typeof collection === "string" ? [collection] : collection,
|
|
353
405
|
insert: value,
|
|
354
406
|
options: options ? options : {},
|
|
355
|
-
syncMode: meta.syncMode,
|
|
407
|
+
syncMode: meta.syncMode ?? false,
|
|
356
408
|
db: extras?.db ?? meta?.db ?? db,
|
|
357
409
|
...(meta.DIP_URL ? {DIP_URL: meta.DIP_URL} : {}),
|
|
358
410
|
...(meta.DIP_DB ? {db: meta.DIP_DB} : {}),
|
|
@@ -373,10 +425,10 @@ export const insert = async (meta, collection, value, options?: any, extras?: an
|
|
|
373
425
|
if (meta.batch) {
|
|
374
426
|
if (!batches[meta.batch])
|
|
375
427
|
throw new Error('Error: Invalid batch in Dip.insert()')
|
|
376
|
-
batches[meta.batch]
|
|
428
|
+
batches[meta.batch]!.push(arg)
|
|
377
429
|
return
|
|
378
430
|
}
|
|
379
|
-
return new Promise<void>((resolve,
|
|
431
|
+
return new Promise<void>((resolve, _reject) => resolve())
|
|
380
432
|
.then(() => execute(arg))
|
|
381
433
|
.then(result => {
|
|
382
434
|
Events.send("Dip.insert", { collection: collectionArray(collection), response: result })
|
|
@@ -385,7 +437,7 @@ export const insert = async (meta, collection, value, options?: any, extras?: an
|
|
|
385
437
|
}
|
|
386
438
|
|
|
387
439
|
// Ported
|
|
388
|
-
export const query = async (meta, collection, query, options?: any, extras?: any) => {
|
|
440
|
+
export const query = async (meta: DipMeta, collection: string | string[], query: any, options?: any, extras?: any) => {
|
|
389
441
|
|
|
390
442
|
if (!(meta instanceof DipMeta)) console.warn('Warn: Provided meta is not an instance of DipMeta in Dip.query()') // TODO: throw error once review completes
|
|
391
443
|
|
|
@@ -399,7 +451,7 @@ export const query = async (meta, collection, query, options?: any, extras?: any
|
|
|
399
451
|
collection: typeof collection === "string" ? [collection] : collection,
|
|
400
452
|
query: query,
|
|
401
453
|
options: options ? options : {},
|
|
402
|
-
syncMode: meta.syncMode,
|
|
454
|
+
syncMode: meta.syncMode ?? false,
|
|
403
455
|
db: extras?.db ?? meta?.db ?? db,
|
|
404
456
|
...(meta.DIP_URL ? {DIP_URL: meta.DIP_URL} : {}),
|
|
405
457
|
...(meta.DIP_DB ? {db: meta.DIP_DB} : {}),
|
|
@@ -415,32 +467,21 @@ export const query = async (meta, collection, query, options?: any, extras?: any
|
|
|
415
467
|
if (meta.batch) {
|
|
416
468
|
if (!batches[meta.batch])
|
|
417
469
|
throw new Error('Error: Invalid batch in Dip.query()')
|
|
418
|
-
batches[meta.batch]
|
|
470
|
+
batches[meta.batch]!.push(arg)
|
|
419
471
|
return
|
|
420
472
|
}
|
|
421
|
-
return new Promise<void>((resolve,
|
|
473
|
+
return new Promise<void>((resolve, _reject) => resolve())
|
|
422
474
|
.then(() => execute(arg))
|
|
423
475
|
}
|
|
424
476
|
|
|
425
477
|
|
|
426
|
-
function collectionArray(col) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
let newcol = []
|
|
430
|
-
for (let i in col) {
|
|
431
|
-
if (!Utils.isEmpty(col[i]))
|
|
432
|
-
newcol.push(col[i])
|
|
433
|
-
}
|
|
434
|
-
return newcol
|
|
435
|
-
} else if (type === '[object String]') {
|
|
436
|
-
if (!Utils.isEmpty(col))
|
|
437
|
-
return [col]
|
|
438
|
-
}
|
|
439
|
-
return []
|
|
478
|
+
function collectionArray(col: string | string[]) {
|
|
479
|
+
const collections = typeof col === 'string' ? [col] : Array.isArray(col) ? col : []
|
|
480
|
+
return collections.filter(collection => collection.trim())
|
|
440
481
|
}
|
|
441
482
|
|
|
442
483
|
// Ported
|
|
443
|
-
export const update = async (meta, collection, query, update, options?: any, extras?: any) => {
|
|
484
|
+
export const update = async (meta: DipMeta, collection: string | string[], query: any, update: any, options?: any, extras?: any) => {
|
|
444
485
|
|
|
445
486
|
if (!(meta instanceof DipMeta)) console.warn('Warn: Provided meta is not an instance of DipMeta in Dip.update()') // TODO: throw error once review completes
|
|
446
487
|
|
|
@@ -455,7 +496,7 @@ export const update = async (meta, collection, query, update, options?: any, ext
|
|
|
455
496
|
query: query,
|
|
456
497
|
update: update,
|
|
457
498
|
options: options ? options : {},
|
|
458
|
-
syncMode: meta.syncMode,
|
|
499
|
+
syncMode: meta.syncMode ?? false,
|
|
459
500
|
db: extras?.db ?? meta?.db ?? db,
|
|
460
501
|
...(meta.DIP_URL ? {DIP_URL: meta.DIP_URL} : {}),
|
|
461
502
|
...(meta.DIP_DB ? {db: meta.DIP_DB} : {}),
|
|
@@ -471,10 +512,10 @@ export const update = async (meta, collection, query, update, options?: any, ext
|
|
|
471
512
|
if (meta.batch) {
|
|
472
513
|
if (!batches[meta.batch])
|
|
473
514
|
throw new Error('Error: Invalid batch in Dip.update()')
|
|
474
|
-
batches[meta.batch]
|
|
515
|
+
batches[meta.batch]!.push(arg)
|
|
475
516
|
return
|
|
476
517
|
}
|
|
477
|
-
return new Promise<void>((resolve,
|
|
518
|
+
return new Promise<void>((resolve, _reject) => resolve())
|
|
478
519
|
.then(() => execute(arg))
|
|
479
520
|
.then (result => {
|
|
480
521
|
Events.send("Dip.update", { collection: collectionArray(collection), response: result })
|
|
@@ -483,7 +524,7 @@ export const update = async (meta, collection, query, update, options?: any, ext
|
|
|
483
524
|
}
|
|
484
525
|
|
|
485
526
|
// Ported
|
|
486
|
-
export const remove = async (meta, collection, query, options?: any, extras?: any) => {
|
|
527
|
+
export const remove = async (meta: DipMeta, collection: string | string[], query: any, options?: any, extras?: any) => {
|
|
487
528
|
|
|
488
529
|
if (!(meta instanceof DipMeta)) console.warn('Warn: Provided meta is not an instance of DipMeta in Dip.remove()') // TODO: throw error once review completes
|
|
489
530
|
|
|
@@ -501,7 +542,7 @@ export const remove = async (meta, collection, query, options?: any, extras?: an
|
|
|
501
542
|
query: query,
|
|
502
543
|
options: options ? options : {},
|
|
503
544
|
delete: true,
|
|
504
|
-
syncMode: meta.syncMode,
|
|
545
|
+
syncMode: meta.syncMode ?? false,
|
|
505
546
|
db: extras?.db ?? meta?.db ?? db,
|
|
506
547
|
...(meta.DIP_URL ? {DIP_URL: meta.DIP_URL} : {}),
|
|
507
548
|
...(meta.DIP_DB ? {db: meta.DIP_DB} : {}),
|
|
@@ -517,10 +558,10 @@ export const remove = async (meta, collection, query, options?: any, extras?: an
|
|
|
517
558
|
if (meta.batch) {
|
|
518
559
|
if (!batches[meta.batch])
|
|
519
560
|
throw new Error('Error: Invalid batch in Dip.query()')
|
|
520
|
-
batches[meta.batch]
|
|
561
|
+
batches[meta.batch]!.push(arg)
|
|
521
562
|
return
|
|
522
563
|
}
|
|
523
|
-
return new Promise<void>((resolve,
|
|
564
|
+
return new Promise<void>((resolve, _reject) => resolve())
|
|
524
565
|
.then(() => execute(arg))
|
|
525
566
|
.then(result => {
|
|
526
567
|
Events.send("Dip.remove", { collection: collectionArray(collection), response: result })
|
|
@@ -528,13 +569,19 @@ export const remove = async (meta, collection, query, options?: any, extras?: an
|
|
|
528
569
|
})
|
|
529
570
|
}
|
|
530
571
|
|
|
531
|
-
|
|
572
|
+
type BinaryResponse = {metadata: any, content: any}
|
|
573
|
+
type DipResponse = AxiosResponse & {
|
|
574
|
+
body: any;
|
|
575
|
+
getSliceAsText(offset: number, length: number): string;
|
|
576
|
+
getSliceAsArrayBuffer(offset: number, length: number): Buffer;
|
|
577
|
+
"Content-Type"?: string;
|
|
578
|
+
};
|
|
532
579
|
|
|
533
580
|
export let config = {
|
|
534
581
|
useDipper: false
|
|
535
582
|
}
|
|
536
583
|
|
|
537
|
-
function execute(arg) {
|
|
584
|
+
function execute(arg: DipRequest) {
|
|
538
585
|
// arg example
|
|
539
586
|
// {
|
|
540
587
|
// db: "middle-earth",
|
|
@@ -546,7 +593,7 @@ function execute(arg) {
|
|
|
546
593
|
|
|
547
594
|
// _id: 1 // Optional. Used with insert
|
|
548
595
|
// }
|
|
549
|
-
arg.db = arg.db
|
|
596
|
+
arg.db = arg.db ? arg.db : db ? db : ''
|
|
550
597
|
arg.executor = arg.executor ?? "native"
|
|
551
598
|
arg.engine = arg.engine ?? internal.engineName
|
|
552
599
|
if (arg.compression === undefined)
|
|
@@ -559,20 +606,14 @@ function execute(arg) {
|
|
|
559
606
|
delete arg.timeout
|
|
560
607
|
|
|
561
608
|
|
|
562
|
-
return config.useDipper
|
|
609
|
+
return config.useDipper ? dipper(arg)
|
|
563
610
|
: axios
|
|
564
611
|
.post(arg.DIP_URL ?? fullurl, buildHybridRequest({...arg, DIP_URL: undefined}), { responseType: 'arraybuffer', timeout: timeout ?? 5000, headers: {"Content-Type": "application/dip"} })
|
|
565
|
-
.then(dip_result => {
|
|
612
|
+
.then((dip_result: AxiosResponse) => {
|
|
566
613
|
// console.log(res.status);
|
|
567
614
|
// console.log(JSON.stringify(res.header, null, 4));
|
|
568
615
|
// console.log(JSON.stringify(res.body, null, 4));
|
|
569
616
|
|
|
570
|
-
type DipResponse = AxiosResponse & {
|
|
571
|
-
body: any;
|
|
572
|
-
getSliceAsText(offset: number, length: number): string;
|
|
573
|
-
getSliceAsArrayBuffer(offset: number, length: number): Buffer;
|
|
574
|
-
"Content-Type"?: string;
|
|
575
|
-
};
|
|
576
617
|
|
|
577
618
|
const result = dip_result as DipResponse
|
|
578
619
|
|
|
@@ -608,7 +649,7 @@ let Essentials = {
|
|
|
608
649
|
|
|
609
650
|
|
|
610
651
|
|
|
611
|
-
function prepareResult(result) {
|
|
652
|
+
function prepareResult(result: BinaryResponse) {
|
|
612
653
|
let res = result.content?.length === 1 ? result.content[0].items : result.content // For raw, this resolves to result.content which is ArrayBuffer
|
|
613
654
|
res.metadata = () => result.metadata
|
|
614
655
|
if (result.metadata.executor === "raw")
|
|
@@ -616,7 +657,7 @@ function prepareResult(result) {
|
|
|
616
657
|
return res
|
|
617
658
|
}
|
|
618
659
|
|
|
619
|
-
function parseBinaryResponse(result) {
|
|
660
|
+
function parseBinaryResponse(result: DipResponse): BinaryResponse {
|
|
620
661
|
const contentType = (result["Content-Type"] || "").toLowerCase()
|
|
621
662
|
if (contentType.includes("application/json")) {
|
|
622
663
|
return {metadata: result.body, content: result.body.items}
|
|
@@ -639,7 +680,7 @@ function parseBinaryResponse(result) {
|
|
|
639
680
|
|
|
640
681
|
// parseWireFormat() equivalent
|
|
641
682
|
// =============================
|
|
642
|
-
let dataView = new DataView(arrayBuffer.buffer, arrayBuffer.byteOffset, arrayBuffer.byteLength);
|
|
683
|
+
// let dataView = new DataView(arrayBuffer.buffer, arrayBuffer.byteOffset, arrayBuffer.byteLength);
|
|
643
684
|
let offset = 0;
|
|
644
685
|
|
|
645
686
|
// 1. Read the metadata size header
|
|
@@ -659,9 +700,20 @@ function parseBinaryResponse(result) {
|
|
|
659
700
|
return { metadata: nativeResponse, content: content }
|
|
660
701
|
}
|
|
661
702
|
|
|
703
|
+
type RawBatchBuffer = Uint8Array & {
|
|
704
|
+
metadata(): {
|
|
705
|
+
items: {
|
|
706
|
+
offset: number
|
|
707
|
+
size: number
|
|
708
|
+
count: number
|
|
709
|
+
kv: () => void
|
|
710
|
+
}[]
|
|
711
|
+
}
|
|
712
|
+
items?: unknown
|
|
713
|
+
}
|
|
662
714
|
|
|
663
|
-
function setRawBatchIterator(arrayBuffer) {
|
|
664
|
-
arrayBuffer.metadata().items.forEach(batch => {
|
|
715
|
+
function setRawBatchIterator(arrayBuffer: RawBatchBuffer) {
|
|
716
|
+
arrayBuffer.metadata().items.forEach((batch: {offset: number, size: number, count: number, kv: () => void}) => {
|
|
665
717
|
batch.kv = () => {
|
|
666
718
|
const batchItem = {
|
|
667
719
|
count: batch.count,
|
|
@@ -695,7 +747,7 @@ function setRawBatchIterator(arrayBuffer) {
|
|
|
695
747
|
|
|
696
748
|
|
|
697
749
|
|
|
698
|
-
function convert_to_array_buffer(value) {
|
|
750
|
+
function convert_to_array_buffer(value: ArrayBuffer | string | number | any) {
|
|
699
751
|
if (typeof value === "string")
|
|
700
752
|
return Essentials.stringToUtf8ArrayBuffer(value)
|
|
701
753
|
else if (typeof value === "number")
|
|
@@ -703,20 +755,12 @@ function convert_to_array_buffer(value) {
|
|
|
703
755
|
return Essentials.stringToUtf8ArrayBuffer(JSON.stringify(value))
|
|
704
756
|
}
|
|
705
757
|
|
|
706
|
-
export function newRaw() {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
type RawManager = {
|
|
710
|
-
buffers: BufferItem[];
|
|
711
|
-
size: number;
|
|
712
|
-
hashes: Map<bigint, HashItem[]>;
|
|
713
|
-
add: (value: ArrayBuffer | string | number | any) => number;
|
|
714
|
-
}
|
|
715
|
-
let obj: RawManager = {buffers: [], size: 0, hashes: new Map()} as RawManager
|
|
716
|
-
obj.add = (value: ArrayBuffer | string | number | any): number => {
|
|
758
|
+
export function newRaw(): RawManager {
|
|
759
|
+
let obj: RawManager = {buffers: [], size: 0, hashes: new Map(), add: (_value: Buffer | string | number | any) => 0} as RawManager
|
|
760
|
+
obj.add = (value: Buffer | string | number | any): number | undefined => {
|
|
717
761
|
if (value === undefined)
|
|
718
762
|
return undefined
|
|
719
|
-
const buf = (value instanceof
|
|
763
|
+
const buf = (value instanceof Buffer) ? value : convert_to_array_buffer(value);
|
|
720
764
|
|
|
721
765
|
const hash = Essentials.defaultHash(buf)
|
|
722
766
|
for (const item of obj.hashes.get(hash) ?? []) { // Conflict. Fallback to verify
|
|
@@ -732,14 +776,16 @@ export function newRaw() {
|
|
|
732
776
|
|
|
733
777
|
if (!obj.hashes.get(hash))
|
|
734
778
|
obj.hashes.set(hash, [])
|
|
735
|
-
obj.hashes.get(hash)
|
|
779
|
+
obj.hashes.get(hash)!.push({offset, buf})
|
|
736
780
|
|
|
737
781
|
return offset
|
|
738
782
|
}
|
|
739
783
|
return obj
|
|
740
784
|
}
|
|
741
785
|
|
|
742
|
-
|
|
786
|
+
|
|
787
|
+
|
|
788
|
+
function buildHybridRequest(request: DipRequest) {
|
|
743
789
|
const batch = request.batch ?? [request];
|
|
744
790
|
|
|
745
791
|
let raw = request.raw ?? newRaw()
|
|
@@ -747,23 +793,23 @@ function buildHybridRequest(request) {
|
|
|
747
793
|
|
|
748
794
|
// Pass 1: Direct offset assignment & exact size calculation (Zero allocation)
|
|
749
795
|
for (let i = 0; i < batch.length; i++) {
|
|
750
|
-
const item = batch[i]
|
|
751
|
-
delete item.batch
|
|
752
|
-
if (item.update) {
|
|
753
|
-
if ( item._id === undefined && item.options?.upsert && item.query?._id !== undefined)
|
|
754
|
-
item._id = item.query._id
|
|
755
|
-
item.update = raw.add(item.update)
|
|
756
|
-
} else if (item.insert) {
|
|
757
|
-
if (item._id === undefined && item.insert?._id !== undefined)
|
|
758
|
-
item._id = item.insert._id
|
|
759
|
-
item.insert = raw.add(item.insert)
|
|
796
|
+
const item = batch[i]!;
|
|
797
|
+
delete (item as DipRequest).batch
|
|
798
|
+
if ((item as UpdateRequest).update) {
|
|
799
|
+
if ( (item as UpdateRequest)._id === undefined && (item as UpdateRequest).options?.upsert && (item as UpdateRequest).query?._id !== undefined)
|
|
800
|
+
(item as UpdateRequest)._id = (item as UpdateRequest).query._id;
|
|
801
|
+
(item as UpdateRequest).update = raw.add((item as UpdateRequest).update)
|
|
802
|
+
} else if ((item as InsertRequest).insert) {
|
|
803
|
+
if ((item as InsertRequest)._id === undefined && (item as InsertRequest).insert?._id !== undefined)
|
|
804
|
+
(item as InsertRequest)._id = (item as InsertRequest).insert._id;
|
|
805
|
+
(item as InsertRequest).insert = raw.add((item as InsertRequest).insert)
|
|
760
806
|
}
|
|
761
|
-
item._id = raw.add(item._id)
|
|
807
|
+
(item as InsertRequest | UpdateRequest)._id = raw.add((item as InsertRequest | UpdateRequest)._id)
|
|
762
808
|
|
|
763
809
|
if (item.options?.$rangeFrom !== undefined)
|
|
764
810
|
item.options.$rangeFrom = raw.add(item.options.$rangeFrom)
|
|
765
|
-
|
|
766
|
-
|
|
811
|
+
if (item.options?.$rangeTo !== undefined)
|
|
812
|
+
item.options.$rangeTo = raw.add(item.options.$rangeTo)
|
|
767
813
|
}
|
|
768
814
|
|
|
769
815
|
// Pass 2: Generate the final JSON payload string
|
|
@@ -815,12 +861,12 @@ function buildHybridRequest(request) {
|
|
|
815
861
|
|
|
816
862
|
|
|
817
863
|
|
|
818
|
-
function bufferToString(arrayBuffer) {
|
|
819
|
-
return Essentials.arrayBufferToString(arrayBuffer)
|
|
864
|
+
function bufferToString(arrayBuffer: string | undefined | ArrayBuffer | SharedArrayBuffer | Buffer) {
|
|
865
|
+
return Essentials.arrayBufferToString(arrayBuffer as Buffer)
|
|
820
866
|
}
|
|
821
867
|
|
|
822
|
-
function getRawKeyValue(arrayBuffer, offset) {
|
|
823
|
-
let dataView = new DataView(arrayBuffer.buffer, arrayBuffer.byteOffset, arrayBuffer.byteLength);
|
|
868
|
+
function getRawKeyValue(arrayBuffer: Uint8Array, offset: number) {
|
|
869
|
+
// let dataView = new DataView(arrayBuffer.buffer, arrayBuffer.byteOffset, arrayBuffer.byteLength);
|
|
824
870
|
let masterView = new Uint8Array(arrayBuffer);
|
|
825
871
|
|
|
826
872
|
// 1. Extract Key Size and Key
|
|
@@ -834,7 +880,7 @@ function getRawKeyValue(arrayBuffer, offset) {
|
|
|
834
880
|
|
|
835
881
|
// Zero-copy view window bounded strictly to the key bytes
|
|
836
882
|
let _id = masterView.subarray(offset, offset + keySize) as EnhancedUint8Array;
|
|
837
|
-
let _id_string
|
|
883
|
+
let _id_string: string | undefined | ArrayBuffer | SharedArrayBuffer
|
|
838
884
|
_id.toText = () => {
|
|
839
885
|
// Fix: Pass the typed array view itself, NOT the underlying root buffer
|
|
840
886
|
_id_string = _id_string === undefined ? _id.buffer.slice(_id.byteOffset, _id.byteOffset + _id.byteLength) : _id_string
|