inibase 1.0.0-rc.61 → 1.0.0-rc.63
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/cli.js +12 -9
- package/dist/file.js +88 -114
- package/dist/index.d.ts +101 -1
- package/dist/index.js +56 -22
- package/dist/utils.d.ts +25 -0
- package/dist/utils.js +25 -0
- package/package.json +1 -5
- package/dist/config.d.ts +0 -3
- package/dist/config.js +0 -3
package/dist/cli.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import "dotenv/config";
|
|
3
3
|
import { createInterface } from "node:readline/promises";
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
|
-
import Inibase from "./index.js";
|
|
6
5
|
import { basename } from "node:path";
|
|
7
|
-
import { isJSON, isNumber } from "./utils.js";
|
|
8
6
|
import Inison from "inison";
|
|
7
|
+
import Inibase from "./index.js";
|
|
8
|
+
import { isJSON, isNumber } from "./utils.js";
|
|
9
9
|
const { path } = parseArgs({
|
|
10
10
|
options: {
|
|
11
11
|
path: { type: "string", short: "p" },
|
|
@@ -17,18 +17,18 @@ const db = new Inibase(basename(path));
|
|
|
17
17
|
const rl = createInterface({
|
|
18
18
|
input: process.stdin,
|
|
19
19
|
output: process.stdout,
|
|
20
|
+
prompt: "\u001b[1;36m> \u001b[0m",
|
|
20
21
|
});
|
|
22
|
+
console.clear();
|
|
21
23
|
rl.prompt();
|
|
22
24
|
rl.on("line", async (input) => {
|
|
23
25
|
const trimedInput = input.trim();
|
|
24
26
|
if (trimedInput === "clear") {
|
|
25
|
-
|
|
27
|
+
process.stdout.write("\x1Bc");
|
|
26
28
|
rl.prompt();
|
|
27
29
|
}
|
|
28
|
-
if (trimedInput === "
|
|
29
|
-
|
|
30
|
-
console.error("err");
|
|
31
|
-
}
|
|
30
|
+
if (trimedInput === "exit")
|
|
31
|
+
process.exit();
|
|
32
32
|
const splitedInput = trimedInput.match(/[^\s"']+|"([^"]*)"|'([^']*)'/g);
|
|
33
33
|
if (["get", "post", "delete", "put"].includes(splitedInput[0].toLocaleLowerCase())) {
|
|
34
34
|
const table = splitedInput[1];
|
|
@@ -45,14 +45,16 @@ rl.on("line", async (input) => {
|
|
|
45
45
|
},
|
|
46
46
|
}).values;
|
|
47
47
|
if (where) {
|
|
48
|
-
if (
|
|
48
|
+
if (where === "'-1'" || where === '"-1"')
|
|
49
|
+
where = -1;
|
|
50
|
+
else if (isNumber(where))
|
|
49
51
|
where = Number(where);
|
|
50
52
|
else if (isJSON(where))
|
|
51
53
|
where = Inison.unstringify(where);
|
|
52
54
|
}
|
|
53
55
|
if (data) {
|
|
54
56
|
if (isJSON(data))
|
|
55
|
-
|
|
57
|
+
data = Inison.unstringify(data);
|
|
56
58
|
else
|
|
57
59
|
data = undefined;
|
|
58
60
|
}
|
|
@@ -85,4 +87,5 @@ rl.on("line", async (input) => {
|
|
|
85
87
|
break;
|
|
86
88
|
}
|
|
87
89
|
}
|
|
90
|
+
rl.prompt();
|
|
88
91
|
});
|
package/dist/file.js
CHANGED
|
@@ -178,11 +178,9 @@ export const decode = (input, fieldType, fieldChildrenType, secretKey) => {
|
|
|
178
178
|
};
|
|
179
179
|
export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, secretKey, readWholeFile = false) {
|
|
180
180
|
let fileHandle = null;
|
|
181
|
-
let rl = null;
|
|
182
181
|
try {
|
|
183
182
|
fileHandle = await open(filePath, "r");
|
|
184
|
-
rl = createReadLineInternface(filePath, fileHandle);
|
|
185
|
-
const lines = {};
|
|
183
|
+
const rl = createReadLineInternface(filePath, fileHandle), lines = {};
|
|
186
184
|
let linesCount = 0;
|
|
187
185
|
if (!lineNumbers) {
|
|
188
186
|
for await (const line of rl) {
|
|
@@ -225,7 +223,6 @@ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, s
|
|
|
225
223
|
}
|
|
226
224
|
finally {
|
|
227
225
|
// Ensure that file handles are closed, even if an error occurred
|
|
228
|
-
rl?.close();
|
|
229
226
|
await fileHandle?.close();
|
|
230
227
|
}
|
|
231
228
|
}
|
|
@@ -244,12 +241,11 @@ export const replace = async (filePath, replacements) => {
|
|
|
244
241
|
if (await isExists(filePath)) {
|
|
245
242
|
let fileHandle = null;
|
|
246
243
|
let fileTempHandle = null;
|
|
247
|
-
let rl = null;
|
|
248
244
|
try {
|
|
249
245
|
let linesCount = 0;
|
|
250
246
|
fileHandle = await open(filePath, "r");
|
|
251
247
|
fileTempHandle = await open(fileTempPath, "w");
|
|
252
|
-
rl = createReadLineInternface(filePath, fileHandle);
|
|
248
|
+
const rl = createReadLineInternface(filePath, fileHandle);
|
|
253
249
|
await _pipeline(filePath, rl, fileTempHandle.createWriteStream(), new Transform({
|
|
254
250
|
transform(line, encoding, callback) {
|
|
255
251
|
linesCount++;
|
|
@@ -265,7 +261,6 @@ export const replace = async (filePath, replacements) => {
|
|
|
265
261
|
}
|
|
266
262
|
finally {
|
|
267
263
|
// Ensure that file handles are closed, even if an error occurred
|
|
268
|
-
rl?.close();
|
|
269
264
|
await fileHandle?.close();
|
|
270
265
|
await fileTempHandle?.close();
|
|
271
266
|
}
|
|
@@ -303,11 +298,10 @@ export const append = async (filePath, data, prepend) => {
|
|
|
303
298
|
else {
|
|
304
299
|
let fileHandle = null;
|
|
305
300
|
let fileTempHandle = null;
|
|
306
|
-
let rl = null;
|
|
307
301
|
try {
|
|
308
302
|
fileHandle = await open(filePath, "r");
|
|
309
303
|
fileTempHandle = await open(fileTempPath, "w");
|
|
310
|
-
rl = createReadLineInternface(filePath, fileHandle);
|
|
304
|
+
const rl = createReadLineInternface(filePath, fileHandle);
|
|
311
305
|
let isAppended = false;
|
|
312
306
|
await _pipeline(filePath, rl, fileTempHandle.createWriteStream(), new Transform({
|
|
313
307
|
transform(line, _, callback) {
|
|
@@ -321,7 +315,6 @@ export const append = async (filePath, data, prepend) => {
|
|
|
321
315
|
}
|
|
322
316
|
finally {
|
|
323
317
|
// Ensure that file handles are closed, even if an error occurred
|
|
324
|
-
rl?.close();
|
|
325
318
|
await fileHandle?.close();
|
|
326
319
|
await fileTempHandle?.close();
|
|
327
320
|
}
|
|
@@ -347,37 +340,10 @@ export const remove = async (filePath, linesToDelete) => {
|
|
|
347
340
|
if (linesToDelete.some(Number.isNaN))
|
|
348
341
|
throw new Error("UNVALID_LINE_NUMBERS");
|
|
349
342
|
const fileTempPath = filePath.replace(/([^/]+)\/?$/, ".tmp/$1");
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
await exec(command);
|
|
355
|
-
}
|
|
356
|
-
else {
|
|
357
|
-
let linesCount = 0;
|
|
358
|
-
let deletedCount = 0;
|
|
359
|
-
const fileHandle = await open(filePath, "r");
|
|
360
|
-
const fileTempHandle = await open(fileTempPath, "w");
|
|
361
|
-
const linesToDeleteArray = new Set(linesToDelete);
|
|
362
|
-
const rl = createReadLineInternface(filePath, fileHandle);
|
|
363
|
-
await _pipeline(filePath, rl, fileTempHandle.createWriteStream(), new Transform({
|
|
364
|
-
transform(line, _, callback) {
|
|
365
|
-
linesCount++;
|
|
366
|
-
if (linesToDeleteArray.has(linesCount)) {
|
|
367
|
-
deletedCount++;
|
|
368
|
-
return callback();
|
|
369
|
-
}
|
|
370
|
-
return callback(null, `${line}\n`);
|
|
371
|
-
},
|
|
372
|
-
final(callback) {
|
|
373
|
-
if (deletedCount === linesCount)
|
|
374
|
-
this.push("\n");
|
|
375
|
-
return callback();
|
|
376
|
-
},
|
|
377
|
-
}));
|
|
378
|
-
await fileTempHandle.close();
|
|
379
|
-
await fileHandle.close();
|
|
380
|
-
}
|
|
343
|
+
const command = filePath.endsWith(".gz")
|
|
344
|
+
? `zcat ${filePath} | sed "${linesToDelete.join("d;")}d" | gzip > ${fileTempPath}`
|
|
345
|
+
: `sed "${linesToDelete.join("d;")}d" ${filePath} > ${fileTempPath}`;
|
|
346
|
+
await exec(command);
|
|
381
347
|
return [fileTempPath, filePath];
|
|
382
348
|
};
|
|
383
349
|
/**
|
|
@@ -407,12 +373,11 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
|
|
|
407
373
|
let foundItems = 0;
|
|
408
374
|
const linesNumbers = new Set();
|
|
409
375
|
let fileHandle = null;
|
|
410
|
-
let rl = null;
|
|
411
376
|
try {
|
|
412
377
|
// Open the file for reading.
|
|
413
378
|
fileHandle = await open(filePath, "r");
|
|
414
379
|
// Create a Readline interface to read the file line by line.
|
|
415
|
-
rl = createReadLineInternface(filePath, fileHandle);
|
|
380
|
+
const rl = createReadLineInternface(filePath, fileHandle);
|
|
416
381
|
// Iterate through each line in the file.
|
|
417
382
|
for await (const line of rl) {
|
|
418
383
|
// Increment the line count for each line.
|
|
@@ -452,7 +417,6 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
|
|
|
452
417
|
}
|
|
453
418
|
finally {
|
|
454
419
|
// Close the file handle in the finally block to ensure it is closed even if an error occurs.
|
|
455
|
-
rl?.close();
|
|
456
420
|
await fileHandle?.close();
|
|
457
421
|
}
|
|
458
422
|
};
|
|
@@ -469,15 +433,13 @@ export const count = async (filePath) => {
|
|
|
469
433
|
let linesCount = 0;
|
|
470
434
|
if (await isExists(filePath)) {
|
|
471
435
|
let fileHandle = null;
|
|
472
|
-
let rl = null;
|
|
473
436
|
try {
|
|
474
437
|
fileHandle = await open(filePath, "r");
|
|
475
|
-
rl = createReadLineInternface(filePath, fileHandle);
|
|
438
|
+
const rl = createReadLineInternface(filePath, fileHandle);
|
|
476
439
|
for await (const _ of rl)
|
|
477
440
|
linesCount++;
|
|
478
441
|
}
|
|
479
442
|
finally {
|
|
480
|
-
rl?.close();
|
|
481
443
|
await fileHandle?.close();
|
|
482
444
|
}
|
|
483
445
|
}
|
|
@@ -493,27 +455,31 @@ export const count = async (filePath) => {
|
|
|
493
455
|
* Note: Decodes each line as a number using the 'decode' function. Non-numeric lines contribute 0 to the sum.
|
|
494
456
|
*/
|
|
495
457
|
export const sum = async (filePath, lineNumbers) => {
|
|
496
|
-
let sum = 0;
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
458
|
+
let sum = 0, fileHandle = null;
|
|
459
|
+
try {
|
|
460
|
+
fileHandle = await open(filePath, "r");
|
|
461
|
+
const rl = createReadLineInternface(filePath, fileHandle);
|
|
462
|
+
if (lineNumbers) {
|
|
463
|
+
let linesCount = 0;
|
|
464
|
+
const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
465
|
+
for await (const line of rl) {
|
|
466
|
+
linesCount++;
|
|
467
|
+
if (!lineNumbersArray.has(linesCount))
|
|
468
|
+
continue;
|
|
469
|
+
sum += +(decode(line, "number") ?? 0);
|
|
470
|
+
lineNumbersArray.delete(linesCount);
|
|
471
|
+
if (!lineNumbersArray.size)
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
510
474
|
}
|
|
475
|
+
else
|
|
476
|
+
for await (const line of rl)
|
|
477
|
+
sum += +(decode(line, "number") ?? 0);
|
|
478
|
+
return sum;
|
|
479
|
+
}
|
|
480
|
+
finally {
|
|
481
|
+
await fileHandle?.close();
|
|
511
482
|
}
|
|
512
|
-
else
|
|
513
|
-
for await (const line of rl)
|
|
514
|
-
sum += +(decode(line, "number") ?? 0);
|
|
515
|
-
await fileHandle.close();
|
|
516
|
-
return sum;
|
|
517
483
|
};
|
|
518
484
|
/**
|
|
519
485
|
* Asynchronously finds the maximum numerical value from specified lines in a file.
|
|
@@ -525,32 +491,36 @@ export const sum = async (filePath, lineNumbers) => {
|
|
|
525
491
|
* Note: Decodes each line as a number using the 'decode' function. Considers only numerical values for determining the maximum.
|
|
526
492
|
*/
|
|
527
493
|
export const max = async (filePath, lineNumbers) => {
|
|
528
|
-
let max = 0;
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
494
|
+
let max = 0, fileHandle = null, rl = null;
|
|
495
|
+
try {
|
|
496
|
+
fileHandle = await open(filePath, "r");
|
|
497
|
+
rl = createReadLineInternface(filePath, fileHandle);
|
|
498
|
+
if (lineNumbers) {
|
|
499
|
+
let linesCount = 0;
|
|
500
|
+
const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
501
|
+
for await (const line of rl) {
|
|
502
|
+
linesCount++;
|
|
503
|
+
if (!lineNumbersArray.has(linesCount))
|
|
504
|
+
continue;
|
|
505
|
+
const lineContentNum = +(decode(line, "number") ?? 0);
|
|
506
|
+
if (lineContentNum > max)
|
|
507
|
+
max = lineContentNum;
|
|
508
|
+
lineNumbersArray.delete(linesCount);
|
|
509
|
+
if (!lineNumbersArray.size)
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
544
512
|
}
|
|
513
|
+
else
|
|
514
|
+
for await (const line of rl) {
|
|
515
|
+
const lineContentNum = +(decode(line, "number") ?? 0);
|
|
516
|
+
if (lineContentNum > max)
|
|
517
|
+
max = lineContentNum;
|
|
518
|
+
}
|
|
519
|
+
return max;
|
|
520
|
+
}
|
|
521
|
+
finally {
|
|
522
|
+
await fileHandle?.close();
|
|
545
523
|
}
|
|
546
|
-
else
|
|
547
|
-
for await (const line of rl) {
|
|
548
|
-
const lineContentNum = +(decode(line, "number") ?? 0);
|
|
549
|
-
if (lineContentNum > max)
|
|
550
|
-
max = lineContentNum;
|
|
551
|
-
}
|
|
552
|
-
await fileHandle.close();
|
|
553
|
-
return max;
|
|
554
524
|
};
|
|
555
525
|
/**
|
|
556
526
|
* Asynchronously finds the minimum numerical value from specified lines in a file.
|
|
@@ -562,30 +532,34 @@ export const max = async (filePath, lineNumbers) => {
|
|
|
562
532
|
* Note: Decodes each line as a number using the 'decode' function. Considers only numerical values for determining the minimum.
|
|
563
533
|
*/
|
|
564
534
|
export const min = async (filePath, lineNumbers) => {
|
|
565
|
-
let min = 0;
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
535
|
+
let min = 0, fileHandle = null;
|
|
536
|
+
try {
|
|
537
|
+
fileHandle = await open(filePath, "r");
|
|
538
|
+
const rl = createReadLineInternface(filePath, fileHandle);
|
|
539
|
+
if (lineNumbers) {
|
|
540
|
+
let linesCount = 0;
|
|
541
|
+
const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
542
|
+
for await (const line of rl) {
|
|
543
|
+
linesCount++;
|
|
544
|
+
if (!lineNumbersArray.has(linesCount))
|
|
545
|
+
continue;
|
|
546
|
+
const lineContentNum = +(decode(line, "number") ?? 0);
|
|
547
|
+
if (lineContentNum < min)
|
|
548
|
+
min = lineContentNum;
|
|
549
|
+
lineNumbersArray.delete(linesCount);
|
|
550
|
+
if (!lineNumbersArray.size)
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
581
553
|
}
|
|
554
|
+
else
|
|
555
|
+
for await (const line of rl) {
|
|
556
|
+
const lineContentNum = +(decode(line, "number") ?? 0);
|
|
557
|
+
if (lineContentNum < min)
|
|
558
|
+
min = lineContentNum;
|
|
559
|
+
}
|
|
560
|
+
return min;
|
|
561
|
+
}
|
|
562
|
+
finally {
|
|
563
|
+
await fileHandle?.close();
|
|
582
564
|
}
|
|
583
|
-
else
|
|
584
|
-
for await (const line of rl) {
|
|
585
|
-
const lineContentNum = +(decode(line, "number") ?? 0);
|
|
586
|
-
if (lineContentNum < min)
|
|
587
|
-
min = lineContentNum;
|
|
588
|
-
}
|
|
589
|
-
await fileHandle.close();
|
|
590
|
-
return min;
|
|
591
565
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -64,8 +64,28 @@ export default class Inibase {
|
|
|
64
64
|
private throwError;
|
|
65
65
|
private getFileExtension;
|
|
66
66
|
private _schemaToIdsPath;
|
|
67
|
+
/**
|
|
68
|
+
* Create a new table inside database, with predefined schema and config
|
|
69
|
+
*
|
|
70
|
+
* @param {string} tableName
|
|
71
|
+
* @param {Schema} [schema]
|
|
72
|
+
* @param {Config} [config]
|
|
73
|
+
*/
|
|
67
74
|
createTable(tableName: string, schema?: Schema, config?: Config): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Update table schema or config
|
|
77
|
+
*
|
|
78
|
+
* @param {string} tableName
|
|
79
|
+
* @param {Schema} [schema]
|
|
80
|
+
* @param {Config} [config]
|
|
81
|
+
*/
|
|
68
82
|
updateTable(tableName: string, schema?: Schema, config?: Config): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Get table schema and config
|
|
85
|
+
*
|
|
86
|
+
* @param {string} tableName
|
|
87
|
+
* @return {*} {Promise<TableObject>}
|
|
88
|
+
*/
|
|
69
89
|
getTable(tableName: string): Promise<TableObject>;
|
|
70
90
|
getTableSchema(tableName: string, encodeIDs?: boolean): Promise<Schema | undefined>;
|
|
71
91
|
private throwErrorIfTableEmpty;
|
|
@@ -81,25 +101,105 @@ export default class Inibase {
|
|
|
81
101
|
private getItemsFromSchema;
|
|
82
102
|
private applyCriteria;
|
|
83
103
|
private _filterSchemaByColumns;
|
|
84
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Clear table cache
|
|
106
|
+
*
|
|
107
|
+
* @param {string} tableName
|
|
108
|
+
*/
|
|
109
|
+
clearCache(tableName: string): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* Retrieve item(s) from a table
|
|
112
|
+
*
|
|
113
|
+
* @param {string} tableName
|
|
114
|
+
* @param {(string | number | (string | number)[] | Criteria | undefined)} [where]
|
|
115
|
+
* @param {(Options | undefined)} [options]
|
|
116
|
+
* @param {true} [onlyOne]
|
|
117
|
+
* @param {undefined} [onlyLinesNumbers]
|
|
118
|
+
* @param {boolean} [_skipIdColumn]
|
|
119
|
+
* @return {*} {(Promise<Data[] | Data | number[] | null>)}
|
|
120
|
+
*/
|
|
85
121
|
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: true, onlyLinesNumbers?: undefined, _skipIdColumn?: boolean): Promise<Data | null>;
|
|
86
122
|
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: boolean | undefined, onlyLinesNumbers?: true, _skipIdColumn?: boolean): Promise<number[]>;
|
|
123
|
+
/**
|
|
124
|
+
* Create new item(s) in a table
|
|
125
|
+
*
|
|
126
|
+
* @param {string} tableName
|
|
127
|
+
* @param {(Data | Data[])} data Can be array of objects or a single object
|
|
128
|
+
* @param {Options} [options] Pagination options, useful when the returnPostedData param is true
|
|
129
|
+
* @param {boolean} [returnPostedData] By default function returns void, if you want to get the posted data, set this param to true
|
|
130
|
+
* @return {*} {Promise<Data | Data[] | null | void>}
|
|
131
|
+
*/
|
|
87
132
|
post(tableName: string, data: Data | Data[], options?: Options, returnPostedData?: boolean): Promise<void>;
|
|
88
133
|
post(tableName: string, data: Data, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
|
|
89
134
|
post(tableName: string, data: Data[], options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
|
|
135
|
+
/**
|
|
136
|
+
* Update item(s) in a table
|
|
137
|
+
*
|
|
138
|
+
* @param {string} tableName
|
|
139
|
+
* @param {(Data | Data[])} data
|
|
140
|
+
* @param {(number | string | (number | string)[] | Criteria)} [where]
|
|
141
|
+
* @param {Options} [options]
|
|
142
|
+
* @param {false} [returnUpdatedData]
|
|
143
|
+
* @return {*} {Promise<Data | Data[] | null | undefined | void>}
|
|
144
|
+
*/
|
|
90
145
|
put(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria, options?: Options, returnUpdatedData?: false): Promise<void>;
|
|
91
146
|
put(tableName: string, data: Data, where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true): Promise<Data | null>;
|
|
92
147
|
put(tableName: string, data: Data[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true): Promise<Data[] | null>;
|
|
148
|
+
/**
|
|
149
|
+
* Delete item(s) in a table
|
|
150
|
+
*
|
|
151
|
+
* @param {string} tableName
|
|
152
|
+
* @param {(number | string)} [where]
|
|
153
|
+
* @param {(string | string[])} [_id]
|
|
154
|
+
* @return {*} {(Promise<string | number | (string | number)[] | null>)}
|
|
155
|
+
*/
|
|
93
156
|
delete(tableName: string, where?: number | string, _id?: string | string[]): Promise<string | null>;
|
|
94
157
|
delete(tableName: string, where?: (number | string)[] | Criteria, _id?: string | string[]): Promise<string[] | null>;
|
|
95
158
|
delete(tableName: string, where?: number, _id?: string | string[]): Promise<number | null>;
|
|
96
159
|
delete(tableName: string, where?: number[], _id?: string | string[]): Promise<number[] | null>;
|
|
160
|
+
/**
|
|
161
|
+
* Generate sum of column(s) in a table
|
|
162
|
+
*
|
|
163
|
+
* @param {string} tableName
|
|
164
|
+
* @param {string} columns
|
|
165
|
+
* @param {(number | string | (number | string)[] | Criteria)} [where]
|
|
166
|
+
* @return {*} {Promise<number | Record<string, number>>}
|
|
167
|
+
*/
|
|
97
168
|
sum(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
|
|
98
169
|
sum(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
|
|
170
|
+
/**
|
|
171
|
+
* Generate max of column(s) in a table
|
|
172
|
+
*
|
|
173
|
+
* @param {string} tableName
|
|
174
|
+
* @param {string} columns
|
|
175
|
+
* @param {(number | string | (number | string)[] | Criteria)} [where]
|
|
176
|
+
* @return {*} {Promise<number>}
|
|
177
|
+
*/
|
|
99
178
|
max(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
|
|
100
179
|
max(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
|
|
180
|
+
/**
|
|
181
|
+
* Generate min of column(s) in a table
|
|
182
|
+
*
|
|
183
|
+
* @param {string} tableName
|
|
184
|
+
* @param {string} columns
|
|
185
|
+
* @param {(number | string | (number | string)[] | Criteria)} [where]
|
|
186
|
+
* @return {*} {Promise<number>}
|
|
187
|
+
*/
|
|
101
188
|
min(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
|
|
102
189
|
min(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
|
|
190
|
+
/**
|
|
191
|
+
* Sort column(s) of a table
|
|
192
|
+
*
|
|
193
|
+
* @param {string} tableName
|
|
194
|
+
* @param {(string
|
|
195
|
+
* | string[]
|
|
196
|
+
* | Record<string, 1 | -1 | "asc" | "ASC" | "desc" | "DESC">)} columns
|
|
197
|
+
* @param {(string | number | (string | number)[] | Criteria)} [where]
|
|
198
|
+
* @param {Options} [options={
|
|
199
|
+
* page: 1,
|
|
200
|
+
* perPage: 15,
|
|
201
|
+
* }]
|
|
202
|
+
*/
|
|
103
203
|
sort(tableName: string, columns: string | string[] | Record<string, 1 | -1 | "asc" | "ASC" | "desc" | "DESC">, where?: string | number | (string | number)[] | Criteria, options?: Options): Promise<any[]>;
|
|
104
204
|
}
|
|
105
205
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
|
-
import { unlink, rename, mkdir, readdir,
|
|
2
|
+
import { unlink, rename, mkdir, readdir, writeFile, readFile, } from "node:fs/promises";
|
|
3
3
|
import { existsSync, appendFileSync, readFileSync } from "node:fs";
|
|
4
4
|
import { join, parse } from "node:path";
|
|
5
5
|
import { scryptSync, randomBytes } from "node:crypto";
|
|
@@ -81,54 +81,65 @@ export default class Inibase {
|
|
|
81
81
|
RETURN[field.id] = `${(prefix ?? "") + field.key}${this.getFileExtension(tableName)}`;
|
|
82
82
|
return RETURN;
|
|
83
83
|
};
|
|
84
|
+
/**
|
|
85
|
+
* Create a new table inside database, with predefined schema and config
|
|
86
|
+
*
|
|
87
|
+
* @param {string} tableName
|
|
88
|
+
* @param {Schema} [schema]
|
|
89
|
+
* @param {Config} [config]
|
|
90
|
+
*/
|
|
84
91
|
async createTable(tableName, schema, config) {
|
|
85
92
|
const tablePath = join(this.databasePath, tableName);
|
|
86
93
|
if (await File.isExists(tablePath))
|
|
87
94
|
this.throwError("TABLE_EXISTS", tableName);
|
|
88
|
-
await
|
|
89
|
-
|
|
90
|
-
mkdir(join(tablePath, ".tmp")),
|
|
91
|
-
mkdir(join(tablePath, ".cache")),
|
|
92
|
-
]);
|
|
95
|
+
await mkdir(join(tablePath, ".tmp"), { recursive: true });
|
|
96
|
+
await mkdir(join(tablePath, ".cache"));
|
|
93
97
|
if (config) {
|
|
94
98
|
if (config.compression)
|
|
95
|
-
await
|
|
99
|
+
await writeFile(join(tablePath, ".compression.config"), "");
|
|
96
100
|
if (config.cache)
|
|
97
|
-
await
|
|
101
|
+
await writeFile(join(tablePath, ".cache.config"), "");
|
|
98
102
|
if (config.prepend)
|
|
99
|
-
await
|
|
103
|
+
await writeFile(join(tablePath, ".prepend.config"), "");
|
|
100
104
|
}
|
|
101
105
|
if (schema)
|
|
102
106
|
await writeFile(join(tablePath, "schema.json"), JSON.stringify(UtilsServer.addIdToSchema(schema, 0, this.salt, false), null, 2));
|
|
103
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Update table schema or config
|
|
110
|
+
*
|
|
111
|
+
* @param {string} tableName
|
|
112
|
+
* @param {Schema} [schema]
|
|
113
|
+
* @param {Config} [config]
|
|
114
|
+
*/
|
|
104
115
|
async updateTable(tableName, schema, config) {
|
|
105
116
|
const table = await this.getTable(tableName), tablePath = join(this.databasePath, tableName);
|
|
106
117
|
if (config) {
|
|
107
118
|
if (config.compression !== undefined) {
|
|
108
119
|
if (!config.compression && table.config.compression) {
|
|
109
120
|
try {
|
|
110
|
-
await UtilsServer.exec(`gunzip
|
|
121
|
+
await UtilsServer.exec(`gunzip ${tablePath}/*.${this.fileExtension}.gz 2>/dev/null`);
|
|
111
122
|
await unlink(join(tablePath, ".compression.config"));
|
|
112
123
|
}
|
|
113
124
|
catch { }
|
|
114
125
|
}
|
|
115
126
|
else if (config.compression && !table.config.compression) {
|
|
116
127
|
try {
|
|
117
|
-
await UtilsServer.exec(`gzip
|
|
118
|
-
await
|
|
128
|
+
await UtilsServer.exec(`gzip ${tablePath}/*.${this.fileExtension} 2>/dev/null`);
|
|
129
|
+
await writeFile(join(tablePath, ".compression.config"), "");
|
|
119
130
|
}
|
|
120
131
|
catch { }
|
|
121
132
|
}
|
|
122
133
|
}
|
|
123
134
|
if (config.cache !== undefined) {
|
|
124
135
|
if (config.cache && !table.config.cache)
|
|
125
|
-
await
|
|
136
|
+
await writeFile(join(tablePath, ".cache.config"), "");
|
|
126
137
|
else if (!config.cache && table.config.cache)
|
|
127
138
|
await unlink(join(tablePath, ".cache.config"));
|
|
128
139
|
}
|
|
129
140
|
if (config.prepend !== undefined) {
|
|
130
141
|
if (config.prepend && !table.config.prepend)
|
|
131
|
-
await
|
|
142
|
+
await writeFile(join(tablePath, ".prepend.config"), "");
|
|
132
143
|
else if (!config.prepend && table.config.prepend)
|
|
133
144
|
await unlink(join(tablePath, ".prepend.config"));
|
|
134
145
|
}
|
|
@@ -157,6 +168,12 @@ export default class Inibase {
|
|
|
157
168
|
delete this.tables[tableName];
|
|
158
169
|
}
|
|
159
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Get table schema and config
|
|
173
|
+
*
|
|
174
|
+
* @param {string} tableName
|
|
175
|
+
* @return {*} {Promise<TableObject>}
|
|
176
|
+
*/
|
|
160
177
|
async getTable(tableName) {
|
|
161
178
|
const tablePath = join(this.databasePath, tableName);
|
|
162
179
|
if (!(await File.isExists(tablePath)))
|
|
@@ -749,10 +766,13 @@ export default class Inibase {
|
|
|
749
766
|
})
|
|
750
767
|
.filter((i) => i);
|
|
751
768
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
769
|
+
/**
|
|
770
|
+
* Clear table cache
|
|
771
|
+
*
|
|
772
|
+
* @param {string} tableName
|
|
773
|
+
*/
|
|
774
|
+
async clearCache(tableName) {
|
|
775
|
+
await Promise.all((await readdir(join(this.databasePath, tableName, ".cache"))).map((file) => unlink(join(this.databasePath, tableName, ".cache", file))));
|
|
756
776
|
}
|
|
757
777
|
async get(tableName, where, options = {
|
|
758
778
|
page: 1,
|
|
@@ -924,7 +944,7 @@ export default class Inibase {
|
|
|
924
944
|
renameList = [];
|
|
925
945
|
totalItems += Array.isArray(RETURN) ? RETURN.length : 1;
|
|
926
946
|
if (this.tables[tableName].config.cache)
|
|
927
|
-
await this.clearCache(
|
|
947
|
+
await this.clearCache(tableName);
|
|
928
948
|
await writeFile(join(tablePath, ".pagination"), `${lastId},${totalItems}`);
|
|
929
949
|
if (returnPostedData)
|
|
930
950
|
return this.get(tableName, this.tables[tableName].config.prepend
|
|
@@ -954,6 +974,7 @@ export default class Inibase {
|
|
|
954
974
|
if (Utils.isArrayOfObjects(data)) {
|
|
955
975
|
if (!data.every((item) => Object.hasOwn(item, "id") && Utils.isValidID(item.id)))
|
|
956
976
|
throw this.throwError("INVALID_ID");
|
|
977
|
+
// TODO: Reduce I/O
|
|
957
978
|
return this.put(tableName, data, data
|
|
958
979
|
.filter(({ id }) => id !== undefined)
|
|
959
980
|
.map(({ id }) => id));
|
|
@@ -1022,7 +1043,7 @@ export default class Inibase {
|
|
|
1022
1043
|
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1023
1044
|
renameList = [];
|
|
1024
1045
|
if (this.tables[tableName].config.cache)
|
|
1025
|
-
await this.clearCache(
|
|
1046
|
+
await this.clearCache(tableName);
|
|
1026
1047
|
if (returnUpdatedData)
|
|
1027
1048
|
return this.get(tableName, where, options, !Array.isArray(where));
|
|
1028
1049
|
}
|
|
@@ -1052,7 +1073,7 @@ export default class Inibase {
|
|
|
1052
1073
|
?.filter((fileName) => fileName.endsWith(".inib"))
|
|
1053
1074
|
.map(async (file) => unlink(join(tablePath, file))));
|
|
1054
1075
|
if (this.tables[tableName].config.cache)
|
|
1055
|
-
await this.clearCache(
|
|
1076
|
+
await this.clearCache(tableName);
|
|
1056
1077
|
}
|
|
1057
1078
|
finally {
|
|
1058
1079
|
await File.unlock(join(tablePath, ".tmp"));
|
|
@@ -1074,7 +1095,7 @@ export default class Inibase {
|
|
|
1074
1095
|
await Promise.all(files.map(async (file) => renameList.push(await File.remove(join(tablePath, file), where))));
|
|
1075
1096
|
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1076
1097
|
if (this.tables[tableName].config.cache)
|
|
1077
|
-
await this.clearCache(
|
|
1098
|
+
await this.clearCache(tableName);
|
|
1078
1099
|
if (await File.isExists(join(tablePath, ".pagination"))) {
|
|
1079
1100
|
const [lastId, totalItems] = (await readFile(join(tablePath, ".pagination"), "utf8"))
|
|
1080
1101
|
.split(",")
|
|
@@ -1163,6 +1184,19 @@ export default class Inibase {
|
|
|
1163
1184
|
}
|
|
1164
1185
|
return RETURN;
|
|
1165
1186
|
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Sort column(s) of a table
|
|
1189
|
+
*
|
|
1190
|
+
* @param {string} tableName
|
|
1191
|
+
* @param {(string
|
|
1192
|
+
* | string[]
|
|
1193
|
+
* | Record<string, 1 | -1 | "asc" | "ASC" | "desc" | "DESC">)} columns
|
|
1194
|
+
* @param {(string | number | (string | number)[] | Criteria)} [where]
|
|
1195
|
+
* @param {Options} [options={
|
|
1196
|
+
* page: 1,
|
|
1197
|
+
* perPage: 15,
|
|
1198
|
+
* }]
|
|
1199
|
+
*/
|
|
1166
1200
|
async sort(tableName, columns, where, options = {
|
|
1167
1201
|
page: 1,
|
|
1168
1202
|
perPage: 15,
|
package/dist/utils.d.ts
CHANGED
|
@@ -169,9 +169,34 @@ export declare function FormatObjectCriteriaValue(value: string, isParentArray?:
|
|
|
169
169
|
ComparisonOperator,
|
|
170
170
|
string | number | boolean | null | (string | number | null)[]
|
|
171
171
|
];
|
|
172
|
+
/**
|
|
173
|
+
* Get field from schema
|
|
174
|
+
*
|
|
175
|
+
* @export
|
|
176
|
+
* @param {string} keyPath Support dot notation path
|
|
177
|
+
* @param {Schema} schema
|
|
178
|
+
*/
|
|
172
179
|
export declare function getField(keyPath: string, schema: Schema): Field | null;
|
|
180
|
+
/**
|
|
181
|
+
* Override a schema field, key, type or other properties
|
|
182
|
+
*
|
|
183
|
+
* @export
|
|
184
|
+
* @param {string} keyPath Support dot notation path
|
|
185
|
+
* @param {Schema} schema
|
|
186
|
+
* @param {(Omit<Field, "key" | "type"> & {
|
|
187
|
+
* key?: string;
|
|
188
|
+
* type?: FieldType | FieldType[];
|
|
189
|
+
* })} field
|
|
190
|
+
*/
|
|
173
191
|
export declare function setField(keyPath: string, schema: Schema, field: Omit<Field, "key" | "type"> & {
|
|
174
192
|
key?: string;
|
|
175
193
|
type?: FieldType | FieldType[];
|
|
176
194
|
}): Field | null | undefined;
|
|
195
|
+
/**
|
|
196
|
+
* Remove field from schema
|
|
197
|
+
*
|
|
198
|
+
* @export
|
|
199
|
+
* @param {string} keyPath Support dot notation path
|
|
200
|
+
* @param {Schema} schema
|
|
201
|
+
*/
|
|
177
202
|
export declare function unsetField(keyPath: string, schema: Schema): Field | null | undefined;
|
package/dist/utils.js
CHANGED
|
@@ -346,6 +346,13 @@ export function FormatObjectCriteriaValue(value, isParentArray = false) {
|
|
|
346
346
|
return ["=", value];
|
|
347
347
|
}
|
|
348
348
|
}
|
|
349
|
+
/**
|
|
350
|
+
* Get field from schema
|
|
351
|
+
*
|
|
352
|
+
* @export
|
|
353
|
+
* @param {string} keyPath Support dot notation path
|
|
354
|
+
* @param {Schema} schema
|
|
355
|
+
*/
|
|
349
356
|
export function getField(keyPath, schema) {
|
|
350
357
|
let RETURN = null;
|
|
351
358
|
const keyPathSplited = keyPath.split(".");
|
|
@@ -364,6 +371,17 @@ export function getField(keyPath, schema) {
|
|
|
364
371
|
return null;
|
|
365
372
|
return isArrayOfObjects(RETURN) ? RETURN[0] : RETURN;
|
|
366
373
|
}
|
|
374
|
+
/**
|
|
375
|
+
* Override a schema field, key, type or other properties
|
|
376
|
+
*
|
|
377
|
+
* @export
|
|
378
|
+
* @param {string} keyPath Support dot notation path
|
|
379
|
+
* @param {Schema} schema
|
|
380
|
+
* @param {(Omit<Field, "key" | "type"> & {
|
|
381
|
+
* key?: string;
|
|
382
|
+
* type?: FieldType | FieldType[];
|
|
383
|
+
* })} field
|
|
384
|
+
*/
|
|
367
385
|
export function setField(keyPath, schema, field) {
|
|
368
386
|
const keyPathSplited = keyPath.split(".");
|
|
369
387
|
for (const [index, key] of keyPathSplited.entries()) {
|
|
@@ -380,6 +398,13 @@ export function setField(keyPath, schema, field) {
|
|
|
380
398
|
schema = foundItem.children;
|
|
381
399
|
}
|
|
382
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* Remove field from schema
|
|
403
|
+
*
|
|
404
|
+
* @export
|
|
405
|
+
* @param {string} keyPath Support dot notation path
|
|
406
|
+
* @param {Schema} schema
|
|
407
|
+
*/
|
|
383
408
|
export function unsetField(keyPath, schema) {
|
|
384
409
|
const keyPathSplited = keyPath.split(".");
|
|
385
410
|
let parent = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "inibase",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.63",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Karim Amahtil",
|
|
6
6
|
"email": "karim.amahtil@gmail.com"
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./dist/index.js",
|
|
12
12
|
"./file": "./dist/file.js",
|
|
13
|
-
"./config": "./dist/config.js",
|
|
14
13
|
"./utils": "./dist/utils.js",
|
|
15
14
|
"./utils.server": "./dist/utils.server.js"
|
|
16
15
|
},
|
|
@@ -63,9 +62,6 @@
|
|
|
63
62
|
"utils": [
|
|
64
63
|
"./dist/utils.d.ts"
|
|
65
64
|
],
|
|
66
|
-
"config": [
|
|
67
|
-
"./dist/config.d.ts"
|
|
68
|
-
],
|
|
69
65
|
"utils.server": [
|
|
70
66
|
"./dist/utils.server.d.ts"
|
|
71
67
|
]
|
package/dist/config.d.ts
DELETED
package/dist/config.js
DELETED