inibase 1.0.0-rc.57 → 1.0.0-rc.59
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/README.md +320 -127
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +88 -0
- package/dist/file.js +58 -38
- package/dist/index.d.ts +5 -1
- package/dist/index.js +141 -122
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +16 -0
- package/package.json +8 -5
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
1
2
|
import { unlink, rename, mkdir, readdir } from "node:fs/promises";
|
|
2
3
|
import { existsSync, appendFileSync, readFileSync } from "node:fs";
|
|
3
4
|
import { join, parse } from "node:path";
|
|
@@ -13,8 +14,8 @@ export default class Inibase {
|
|
|
13
14
|
database;
|
|
14
15
|
table;
|
|
15
16
|
pageInfo;
|
|
17
|
+
fileExtension = ".txt";
|
|
16
18
|
checkIFunique;
|
|
17
|
-
isThreadEnabled = false;
|
|
18
19
|
totalItems;
|
|
19
20
|
salt;
|
|
20
21
|
constructor(database, mainFolder = ".", _table = null, _totalItems = {}, _pageInfo = {}, _isThreadEnabled = false) {
|
|
@@ -23,7 +24,6 @@ export default class Inibase {
|
|
|
23
24
|
this.table = _table;
|
|
24
25
|
this.totalItems = _totalItems;
|
|
25
26
|
this.pageInfo = _pageInfo;
|
|
26
|
-
this.isThreadEnabled = _isThreadEnabled;
|
|
27
27
|
this.checkIFunique = {};
|
|
28
28
|
if (!process.env.INIBASE_SECRET) {
|
|
29
29
|
if (existsSync(".env") &&
|
|
@@ -34,6 +34,19 @@ export default class Inibase {
|
|
|
34
34
|
}
|
|
35
35
|
else
|
|
36
36
|
this.salt = Buffer.from(process.env.INIBASE_SECRET, "hex");
|
|
37
|
+
// try {
|
|
38
|
+
// if (Config.isCompressionEnabled)
|
|
39
|
+
// execSync(
|
|
40
|
+
// `gzip -r ${join(this.folder, this.database)}/*/*.txt 2>/dev/null`,
|
|
41
|
+
// );
|
|
42
|
+
// else
|
|
43
|
+
// execSync(
|
|
44
|
+
// `gunzip -r ${join(
|
|
45
|
+
// this.folder,
|
|
46
|
+
// this.database,
|
|
47
|
+
// )}/*/*.txt.gz 2>/dev/null`,
|
|
48
|
+
// );
|
|
49
|
+
// } catch {}
|
|
37
50
|
}
|
|
38
51
|
throwError(code, variable, language = "en") {
|
|
39
52
|
const errorMessages = {
|
|
@@ -61,6 +74,15 @@ export default class Inibase {
|
|
|
61
74
|
: errorMessage.replaceAll("{variable}", `'${variable.toString()}'`)
|
|
62
75
|
: errorMessage.replaceAll("{variable}", ""));
|
|
63
76
|
}
|
|
77
|
+
getFileExtension = () => {
|
|
78
|
+
let mainExtension = this.fileExtension;
|
|
79
|
+
// TODO: ADD ENCRYPTION
|
|
80
|
+
// if(Config.isEncryptionEnabled)
|
|
81
|
+
// mainExtension += ".enc"
|
|
82
|
+
if (Config.isCompressionEnabled)
|
|
83
|
+
mainExtension += ".gz";
|
|
84
|
+
return mainExtension;
|
|
85
|
+
};
|
|
64
86
|
_schemaToIdsPath = (schema, prefix = "") => {
|
|
65
87
|
const RETURN = {};
|
|
66
88
|
for (const field of schema)
|
|
@@ -70,7 +92,7 @@ export default class Inibase {
|
|
|
70
92
|
Utils.deepMerge(RETURN, this._schemaToIdsPath(field.children, `${(prefix ?? "") + field.key}.`));
|
|
71
93
|
}
|
|
72
94
|
else if (field.id)
|
|
73
|
-
RETURN[field.id] = `${(prefix ?? "") + field.key}.
|
|
95
|
+
RETURN[field.id] = `${(prefix ?? "") + field.key}${this.getFileExtension()}`;
|
|
74
96
|
return RETURN;
|
|
75
97
|
};
|
|
76
98
|
async setTableSchema(tableName, schema) {
|
|
@@ -140,7 +162,7 @@ export default class Inibase {
|
|
|
140
162
|
schema = await this.getTableSchema(tableName);
|
|
141
163
|
if (!schema)
|
|
142
164
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
143
|
-
if (!(await File.isExists(join(tablePath,
|
|
165
|
+
if (!(await File.isExists(join(tablePath, `id${this.getFileExtension()}`))))
|
|
144
166
|
throw this.throwError("NO_ITEMS", tableName);
|
|
145
167
|
return schema;
|
|
146
168
|
}
|
|
@@ -268,7 +290,7 @@ export default class Inibase {
|
|
|
268
290
|
const field = Utils.getField(key, schema);
|
|
269
291
|
if (!field)
|
|
270
292
|
continue;
|
|
271
|
-
const [searchResult, totalLines] = await File.search(join(tablePath, `${key}.
|
|
293
|
+
const [searchResult, totalLines] = await File.search(join(tablePath, `${key}${this.getFileExtension()}`), Array.isArray(values) ? "=" : "[]", values, undefined, field.type, field.children, 1, undefined, false, this.salt);
|
|
272
294
|
if (searchResult && totalLines > 0)
|
|
273
295
|
throw this.throwError("FIELD_UNIQUE", [
|
|
274
296
|
field.key,
|
|
@@ -357,7 +379,7 @@ export default class Inibase {
|
|
|
357
379
|
_addPathToKeys = (obj, path) => {
|
|
358
380
|
const newObject = {};
|
|
359
381
|
for (const key in obj)
|
|
360
|
-
newObject[join(path, `${key}.
|
|
382
|
+
newObject[join(path, `${key}${this.getFileExtension()}`)] = obj[key];
|
|
361
383
|
return newObject;
|
|
362
384
|
};
|
|
363
385
|
joinPathesContents(mainPath, data) {
|
|
@@ -407,7 +429,7 @@ export default class Inibase {
|
|
|
407
429
|
async getItemsFromSchema(tableName, schema, linesNumber, options, prefix) {
|
|
408
430
|
const tablePath = join(this.folder, this.database, tableName);
|
|
409
431
|
let RETURN = {};
|
|
410
|
-
await
|
|
432
|
+
for await (const field of schema) {
|
|
411
433
|
if ((field.type === "array" ||
|
|
412
434
|
(Array.isArray(field.type) && field.type.includes("array"))) &&
|
|
413
435
|
field.children) {
|
|
@@ -415,82 +437,86 @@ export default class Inibase {
|
|
|
415
437
|
if (field.children.filter((children) => children.type === "array" &&
|
|
416
438
|
Utils.isArrayOfObjects(children.children)).length) {
|
|
417
439
|
// one of children has array field type and has children array of object = Schema
|
|
418
|
-
|
|
419
|
-
Utils.isArrayOfObjects(children.children)), linesNumber, options, `${(prefix ?? "") + field.key}.`)
|
|
420
|
-
|
|
440
|
+
const childItems = await this.getItemsFromSchema(tableName, field.children.filter((children) => children.type === "array" &&
|
|
441
|
+
Utils.isArrayOfObjects(children.children)), linesNumber, options, `${(prefix ?? "") + field.key}.`);
|
|
442
|
+
if (childItems)
|
|
443
|
+
for (const [index, item] of Object.entries(childItems))
|
|
444
|
+
this._getItemsFromSchemaHelper(RETURN, item, index, field);
|
|
421
445
|
field.children = field.children.filter((children) => children.type !== "array" ||
|
|
422
446
|
!Utils.isArrayOfObjects(children.children));
|
|
423
447
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
for (let _i = 0; _i < value.length; _i++) {
|
|
453
|
-
if (value[_i] === null ||
|
|
454
|
-
(Array.isArray(value[_i]) &&
|
|
455
|
-
Utils.isArrayOfNulls(value[_i])))
|
|
456
|
-
continue;
|
|
457
|
-
if (!RETURN[index][field.key][_i])
|
|
458
|
-
RETURN[index][field.key][_i] = {};
|
|
459
|
-
RETURN[index][field.key][_i][key] = value[_i];
|
|
448
|
+
const fieldItems = await this.getItemsFromSchema(tableName, field.children, linesNumber, options, `${(prefix ?? "") + field.key}.`);
|
|
449
|
+
if (fieldItems)
|
|
450
|
+
for (const [index, item] of Object.entries(fieldItems)) {
|
|
451
|
+
if (!RETURN[index])
|
|
452
|
+
RETURN[index] = {};
|
|
453
|
+
if (Utils.isObject(item)) {
|
|
454
|
+
if (!Utils.isArrayOfNulls(Object.values(item))) {
|
|
455
|
+
if (RETURN[index][field.key])
|
|
456
|
+
Object.entries(item).forEach(([key, value], _index) => {
|
|
457
|
+
for (let _index = 0; _index < value.length; _index++)
|
|
458
|
+
if (RETURN[index][field.key][_index])
|
|
459
|
+
Object.assign(RETURN[index][field.key][_index], {
|
|
460
|
+
[key]: value[_index],
|
|
461
|
+
});
|
|
462
|
+
else
|
|
463
|
+
RETURN[index][field.key][_index] = {
|
|
464
|
+
[key]: value[_index],
|
|
465
|
+
};
|
|
466
|
+
});
|
|
467
|
+
else if (Object.values(item).every((_i) => Utils.isArrayOfArrays(_i) || Array.isArray(_i)) &&
|
|
468
|
+
prefix)
|
|
469
|
+
RETURN[index][field.key] = item;
|
|
470
|
+
else {
|
|
471
|
+
RETURN[index][field.key] = [];
|
|
472
|
+
Object.entries(item).forEach(([key, value], _ind) => {
|
|
473
|
+
if (!Array.isArray(value)) {
|
|
474
|
+
RETURN[index][field.key][_ind] = {};
|
|
475
|
+
RETURN[index][field.key][_ind][key] = value;
|
|
460
476
|
}
|
|
461
|
-
|
|
477
|
+
else
|
|
478
|
+
for (let _i = 0; _i < value.length; _i++) {
|
|
479
|
+
if (value[_i] === null ||
|
|
480
|
+
(Array.isArray(value[_i]) &&
|
|
481
|
+
Utils.isArrayOfNulls(value[_i])))
|
|
482
|
+
continue;
|
|
483
|
+
if (!RETURN[index][field.key][_i])
|
|
484
|
+
RETURN[index][field.key][_i] = {};
|
|
485
|
+
RETURN[index][field.key][_i][key] = value[_i];
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
}
|
|
462
489
|
}
|
|
490
|
+
else
|
|
491
|
+
RETURN[index][field.key] = null;
|
|
463
492
|
}
|
|
464
493
|
else
|
|
465
|
-
RETURN[index][field.key] =
|
|
494
|
+
RETURN[index][field.key] = item;
|
|
466
495
|
}
|
|
467
|
-
else
|
|
468
|
-
RETURN[index][field.key] = item;
|
|
469
|
-
}
|
|
470
496
|
}
|
|
471
497
|
else if (field.children === "table" ||
|
|
472
498
|
(Array.isArray(field.type) && field.type.includes("table")) ||
|
|
473
499
|
(Array.isArray(field.children) && field.children.includes("table"))) {
|
|
474
500
|
if (field.table &&
|
|
475
501
|
(await File.isExists(join(this.folder, this.database, field.table))) &&
|
|
476
|
-
(await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}.
|
|
502
|
+
(await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`)))) {
|
|
477
503
|
if (options.columns)
|
|
478
504
|
options.columns = options.columns
|
|
479
505
|
.filter((column) => column.includes(`${field.key}.`))
|
|
480
506
|
.map((column) => column.replace(`${field.key}.`, ""));
|
|
481
|
-
const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}.
|
|
507
|
+
const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`), linesNumber, field.type, field.children, this.salt);
|
|
482
508
|
if (items)
|
|
483
|
-
await
|
|
509
|
+
for await (const [index, item] of Object.entries(items)) {
|
|
484
510
|
if (!RETURN[index])
|
|
485
511
|
RETURN[index] = {};
|
|
486
512
|
RETURN[index][field.key] = item
|
|
487
513
|
? await this.get(field.table, item, options)
|
|
488
514
|
: this.getDefaultValue(field);
|
|
489
|
-
}
|
|
515
|
+
}
|
|
490
516
|
}
|
|
491
517
|
}
|
|
492
|
-
else if (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}.
|
|
493
|
-
const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}.
|
|
518
|
+
else if (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`))) {
|
|
519
|
+
const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`), linesNumber, field.type, field.children, this.salt);
|
|
494
520
|
if (items)
|
|
495
521
|
for (const [index, item] of Object.entries(items)) {
|
|
496
522
|
if (!RETURN[index])
|
|
@@ -500,40 +526,42 @@ export default class Inibase {
|
|
|
500
526
|
}
|
|
501
527
|
}
|
|
502
528
|
else if (field.type === "object") {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
529
|
+
const fieldItems = await this.getItemsFromSchema(tableName, field.children, linesNumber, options, `${(prefix ?? "") + field.key}.`);
|
|
530
|
+
if (fieldItems)
|
|
531
|
+
for (const [index, item] of Object.entries(fieldItems)) {
|
|
532
|
+
if (!RETURN[index])
|
|
533
|
+
RETURN[index] = {};
|
|
534
|
+
if (Utils.isObject(item)) {
|
|
535
|
+
if (!Object.values(item).every((i) => i === null))
|
|
536
|
+
RETURN[index][field.key] = item;
|
|
537
|
+
else
|
|
538
|
+
RETURN[index][field.key] = null;
|
|
539
|
+
}
|
|
509
540
|
else
|
|
510
541
|
RETURN[index][field.key] = null;
|
|
511
542
|
}
|
|
512
|
-
else
|
|
513
|
-
RETURN[index][field.key] = null;
|
|
514
|
-
}
|
|
515
543
|
}
|
|
516
544
|
else if (field.type === "table") {
|
|
517
545
|
if (field.table &&
|
|
518
546
|
(await File.isExists(join(this.folder, this.database, field.table))) &&
|
|
519
|
-
(await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}.
|
|
547
|
+
(await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`)))) {
|
|
520
548
|
if (options.columns)
|
|
521
549
|
options.columns = options.columns
|
|
522
550
|
.filter((column) => column.includes(`${field.key}.`))
|
|
523
551
|
.map((column) => column.replace(`${field.key}.`, ""));
|
|
524
|
-
const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}.
|
|
552
|
+
const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`), linesNumber, "number", undefined, this.salt);
|
|
525
553
|
if (items)
|
|
526
|
-
await
|
|
554
|
+
for await (const [index, item] of Object.entries(items)) {
|
|
527
555
|
if (!RETURN[index])
|
|
528
556
|
RETURN[index] = {};
|
|
529
557
|
RETURN[index][field.key] = item
|
|
530
558
|
? await this.get(field.table, item, options)
|
|
531
559
|
: this.getDefaultValue(field);
|
|
532
|
-
}
|
|
560
|
+
}
|
|
533
561
|
}
|
|
534
562
|
}
|
|
535
|
-
else if (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}.
|
|
536
|
-
const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}.
|
|
563
|
+
else if (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`))) {
|
|
564
|
+
const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`), linesNumber, field.type, field.children, this.salt);
|
|
537
565
|
if (items)
|
|
538
566
|
for (const [index, item] of Object.entries(items)) {
|
|
539
567
|
if (!RETURN[index])
|
|
@@ -546,7 +574,7 @@ export default class Inibase {
|
|
|
546
574
|
{ ...data, [field.key]: this.getDefaultValue(field) },
|
|
547
575
|
]));
|
|
548
576
|
}
|
|
549
|
-
}
|
|
577
|
+
}
|
|
550
578
|
return RETURN;
|
|
551
579
|
}
|
|
552
580
|
async applyCriteria(tableName, schema, options, criteria, allTrue) {
|
|
@@ -634,7 +662,7 @@ export default class Inibase {
|
|
|
634
662
|
searchOperator = "=";
|
|
635
663
|
searchComparedAtValue = value;
|
|
636
664
|
}
|
|
637
|
-
const [searchResult, totalLines, linesNumbers] = await File.search(join(tablePath, `${key}.
|
|
665
|
+
const [searchResult, totalLines, linesNumbers] = await File.search(join(tablePath, `${key}${this.getFileExtension()}`), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, field?.type, field?.children, options.perPage, options.page - 1 * options.perPage + 1, true, this.salt);
|
|
638
666
|
if (searchResult) {
|
|
639
667
|
RETURN = Utils.deepMerge(RETURN, Object.fromEntries(Object.entries(searchResult).map(([id, value]) => [
|
|
640
668
|
id,
|
|
@@ -679,7 +707,7 @@ export default class Inibase {
|
|
|
679
707
|
}
|
|
680
708
|
async clearCache(tablePath) {
|
|
681
709
|
await Promise.all((await readdir(join(tablePath, ".cache")))
|
|
682
|
-
?.filter((fileName) => fileName !==
|
|
710
|
+
?.filter((fileName) => fileName !== `pagination${this.fileExtension}`)
|
|
683
711
|
.map(async (file) => unlink(join(tablePath, ".cache", file))));
|
|
684
712
|
}
|
|
685
713
|
async get(tableName, where, options = {
|
|
@@ -713,16 +741,14 @@ export default class Inibase {
|
|
|
713
741
|
RETURN = Object.values(await this.getItemsFromSchema(tableName, schema, Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
|
|
714
742
|
index +
|
|
715
743
|
1), options));
|
|
716
|
-
if (
|
|
717
|
-
(await File.
|
|
718
|
-
this.totalItems[`${tableName}-*`] = Number((await File.read(join(tablePath, ".cache", "pagination.inib"), true)).split(",")[1]);
|
|
744
|
+
if (await File.isExists(join(tablePath, ".cache", `pagination${this.fileExtension}`)))
|
|
745
|
+
this.totalItems[`${tableName}-*`] = Number((await File.read(join(tablePath, ".cache", `pagination${this.fileExtension}`), true)).split(",")[1]);
|
|
719
746
|
else {
|
|
720
|
-
let [lastId, totalItems] = await File.get(join(tablePath,
|
|
747
|
+
let [lastId, totalItems] = await File.get(join(tablePath, `id${this.getFileExtension()}`), -1, "number", undefined, this.salt, true);
|
|
721
748
|
if (lastId)
|
|
722
749
|
lastId = Number(Object.keys(lastId)?.[0] ?? 0);
|
|
723
750
|
this.totalItems[`${tableName}-*`] = totalItems;
|
|
724
|
-
|
|
725
|
-
await File.write(join(tablePath, ".cache", "pagination.inib"), `${lastId},${totalItems}`, true);
|
|
751
|
+
await File.write(join(tablePath, ".cache", `pagination${this.fileExtension}`), `${lastId},${totalItems}`, true);
|
|
726
752
|
}
|
|
727
753
|
}
|
|
728
754
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
@@ -745,7 +771,7 @@ export default class Inibase {
|
|
|
745
771
|
let Ids = where;
|
|
746
772
|
if (!Array.isArray(Ids))
|
|
747
773
|
Ids = [Ids];
|
|
748
|
-
const [lineNumbers, countItems] = await File.search(join(tablePath,
|
|
774
|
+
const [lineNumbers, countItems] = await File.search(join(tablePath, `id${this.getFileExtension()}`), "[]", Ids.map((id) => Utils.isNumber(id) ? Number(id) : UtilsServer.decodeID(id, this.salt)), undefined, "number", undefined, Ids.length, 0, !this.totalItems[`${tableName}-*`], this.salt);
|
|
749
775
|
if (!lineNumbers)
|
|
750
776
|
throw this.throwError("NO_RESULTS", tableName);
|
|
751
777
|
if (onlyLinesNumbers)
|
|
@@ -762,7 +788,7 @@ export default class Inibase {
|
|
|
762
788
|
let cachedFilePath = "";
|
|
763
789
|
// Criteria
|
|
764
790
|
if (Config.isCacheEnabled)
|
|
765
|
-
cachedFilePath = join(tablePath, ".cache", `${UtilsServer.hashString(inspect(where, { sorted: true }))}.
|
|
791
|
+
cachedFilePath = join(tablePath, ".cache", `${UtilsServer.hashString(inspect(where, { sorted: true }))}${this.fileExtension}`);
|
|
766
792
|
if (Config.isCacheEnabled && (await File.isExists(cachedFilePath))) {
|
|
767
793
|
const cachedItems = (await File.read(cachedFilePath, true)).split(",");
|
|
768
794
|
this.totalItems[`${tableName}-*`] = cachedItems.length;
|
|
@@ -815,15 +841,14 @@ export default class Inibase {
|
|
|
815
841
|
let lastId = 0, totalItems = 0, renameList = [];
|
|
816
842
|
try {
|
|
817
843
|
await File.lock(join(tablePath, ".tmp"), keys);
|
|
818
|
-
if (await File.isExists(join(tablePath,
|
|
819
|
-
if (
|
|
820
|
-
(await File.
|
|
821
|
-
[lastId, totalItems] = (await File.read(join(tablePath, ".cache", "pagination.inib"), true))
|
|
844
|
+
if (await File.isExists(join(tablePath, `id${this.getFileExtension()}`))) {
|
|
845
|
+
if (await File.isExists(join(tablePath, ".cache", `pagination${this.fileExtension}`)))
|
|
846
|
+
[lastId, totalItems] = (await File.read(join(tablePath, ".cache", `pagination${this.fileExtension}`), true))
|
|
822
847
|
.split(",")
|
|
823
848
|
.map(Number);
|
|
824
849
|
else {
|
|
825
850
|
let lastIdObj = null;
|
|
826
|
-
[lastIdObj, totalItems] = await File.get(join(tablePath,
|
|
851
|
+
[lastIdObj, totalItems] = await File.get(join(tablePath, `id${this.getFileExtension()}`), -1, "number", undefined, this.salt, true);
|
|
827
852
|
if (lastIdObj)
|
|
828
853
|
lastId = Number(Object.keys(lastIdObj)?.[0] ?? 0);
|
|
829
854
|
}
|
|
@@ -852,10 +877,9 @@ export default class Inibase {
|
|
|
852
877
|
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
853
878
|
renameList = [];
|
|
854
879
|
totalItems += Array.isArray(RETURN) ? RETURN.length : 1;
|
|
855
|
-
if (Config.isCacheEnabled)
|
|
880
|
+
if (Config.isCacheEnabled)
|
|
856
881
|
await this.clearCache(tablePath);
|
|
857
|
-
|
|
858
|
-
}
|
|
882
|
+
await File.write(join(tablePath, ".cache", `pagination${this.fileExtension}`), `${lastId},${totalItems}`, true);
|
|
859
883
|
if (returnPostedData)
|
|
860
884
|
return this.get(tableName, Config.isReverseEnabled
|
|
861
885
|
? Array.isArray(RETURN)
|
|
@@ -895,13 +919,12 @@ export default class Inibase {
|
|
|
895
919
|
return this.put(tableName, data, data.id);
|
|
896
920
|
}
|
|
897
921
|
let totalItems;
|
|
898
|
-
if (
|
|
899
|
-
(await File.
|
|
900
|
-
totalItems = (await File.read(join(tablePath, ".cache", "pagination.inib"), true))
|
|
922
|
+
if (await File.isExists(join(tablePath, ".cache", `pagination${this.fileExtension}`)))
|
|
923
|
+
totalItems = (await File.read(join(tablePath, ".cache", `pagination${this.fileExtension}`), true))
|
|
901
924
|
.split(",")
|
|
902
925
|
.map(Number)[1];
|
|
903
926
|
else
|
|
904
|
-
totalItems = await File.count(join(tablePath,
|
|
927
|
+
totalItems = await File.count(join(tablePath, `id${this.getFileExtension()}`));
|
|
905
928
|
const pathesContents = this.joinPathesContents(tablePath, {
|
|
906
929
|
...(({ id, ...restOfData }) => restOfData)(data),
|
|
907
930
|
updatedAt: Date.now(),
|
|
@@ -998,26 +1021,23 @@ export default class Inibase {
|
|
|
998
1021
|
if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
999
1022
|
Utils.isNumber(where)) {
|
|
1000
1023
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1001
|
-
const files = (await readdir(tablePath))?.filter((fileName) => fileName.endsWith(
|
|
1024
|
+
const files = (await readdir(tablePath))?.filter((fileName) => fileName.endsWith(this.getFileExtension()));
|
|
1002
1025
|
if (files.length) {
|
|
1003
|
-
if (!_id)
|
|
1004
|
-
_id = Object.entries((await File.get(join(tablePath, "id.inib"), where, "number", undefined, this.salt)) ?? {}).map(([_, id]) => UtilsServer.encodeID(id, this.salt));
|
|
1005
|
-
if (!_id.length)
|
|
1006
|
-
throw this.throwError("NO_RESULTS", tableName);
|
|
1007
1026
|
try {
|
|
1008
1027
|
await File.lock(join(tablePath, ".tmp"));
|
|
1009
1028
|
await Promise.all(files.map(async (file) => renameList.push(await File.remove(join(tablePath, file), where))));
|
|
1010
1029
|
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1011
|
-
if (Config.isCacheEnabled)
|
|
1030
|
+
if (Config.isCacheEnabled)
|
|
1012
1031
|
await this.clearCache(tablePath);
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
}
|
|
1032
|
+
if (await File.isExists(join(tablePath, ".cache", `pagination${this.fileExtension}`))) {
|
|
1033
|
+
const [lastId, totalItems] = (await File.read(join(tablePath, ".cache", `pagination${this.fileExtension}`), true))
|
|
1034
|
+
.split(",")
|
|
1035
|
+
.map(Number);
|
|
1036
|
+
await File.write(join(tablePath, ".cache", `pagination${this.fileExtension}`), `${lastId},${totalItems - (Array.isArray(where) ? where.length : 1)}`, true);
|
|
1019
1037
|
}
|
|
1020
|
-
|
|
1038
|
+
if (_id)
|
|
1039
|
+
return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
|
|
1040
|
+
return where;
|
|
1021
1041
|
}
|
|
1022
1042
|
finally {
|
|
1023
1043
|
if (renameList.length)
|
|
@@ -1040,7 +1060,7 @@ export default class Inibase {
|
|
|
1040
1060
|
if (!Array.isArray(columns))
|
|
1041
1061
|
columns = [columns];
|
|
1042
1062
|
for await (const column of columns) {
|
|
1043
|
-
const columnPath = join(tablePath, `${column}.
|
|
1063
|
+
const columnPath = join(tablePath, `${column}${this.getFileExtension()}`);
|
|
1044
1064
|
if (await File.isExists(columnPath)) {
|
|
1045
1065
|
if (where) {
|
|
1046
1066
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true, schema);
|
|
@@ -1060,7 +1080,7 @@ export default class Inibase {
|
|
|
1060
1080
|
if (!Array.isArray(columns))
|
|
1061
1081
|
columns = [columns];
|
|
1062
1082
|
for await (const column of columns) {
|
|
1063
|
-
const columnPath = join(tablePath, `${column}.
|
|
1083
|
+
const columnPath = join(tablePath, `${column}${this.getFileExtension()}`);
|
|
1064
1084
|
if (await File.isExists(columnPath)) {
|
|
1065
1085
|
if (where) {
|
|
1066
1086
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true, schema);
|
|
@@ -1080,7 +1100,7 @@ export default class Inibase {
|
|
|
1080
1100
|
if (!Array.isArray(columns))
|
|
1081
1101
|
columns = [columns];
|
|
1082
1102
|
for await (const column of columns) {
|
|
1083
|
-
const columnPath = join(tablePath, `${column}.
|
|
1103
|
+
const columnPath = join(tablePath, `${column}${this.getFileExtension()}`);
|
|
1084
1104
|
if (await File.isExists(columnPath)) {
|
|
1085
1105
|
if (where) {
|
|
1086
1106
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true, schema);
|
|
@@ -1098,7 +1118,6 @@ export default class Inibase {
|
|
|
1098
1118
|
page: 1,
|
|
1099
1119
|
perPage: 15,
|
|
1100
1120
|
}) {
|
|
1101
|
-
// TO-DO: Cache Results based on "Columns and Sort Direction"
|
|
1102
1121
|
const tablePath = join(this.folder, this.database, tableName), schema = await this.getSchemaWhenTableNotEmpty(tableName);
|
|
1103
1122
|
// Default values for page and perPage
|
|
1104
1123
|
options.page = options.page || 1;
|
|
@@ -1122,7 +1141,7 @@ export default class Inibase {
|
|
|
1122
1141
|
cacheKey = UtilsServer.hashString(inspect(sortArray, { sorted: true }));
|
|
1123
1142
|
if (where) {
|
|
1124
1143
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true, schema);
|
|
1125
|
-
keepItems = Object.values((await File.get(join(tablePath,
|
|
1144
|
+
keepItems = Object.values((await File.get(join(tablePath, `id${this.getFileExtension()}`), lineNumbers, "number", undefined, this.salt)) ?? {}).map(Number);
|
|
1126
1145
|
isLineNumbers = false;
|
|
1127
1146
|
if (!keepItems.length)
|
|
1128
1147
|
throw this.throwError("NO_RESULTS", tableName);
|
|
@@ -1132,7 +1151,7 @@ export default class Inibase {
|
|
|
1132
1151
|
keepItems = Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
|
|
1133
1152
|
index +
|
|
1134
1153
|
1);
|
|
1135
|
-
const filesPathes = [["id", true], ...sortArray].map((column) => join(tablePath, `${column[0]}.
|
|
1154
|
+
const filesPathes = [["id", true], ...sortArray].map((column) => join(tablePath, `${column[0]}${this.getFileExtension()}`));
|
|
1136
1155
|
// Construct the paste command to merge files and filter lines by IDs
|
|
1137
1156
|
const pasteCommand = `paste ${filesPathes.join(" ")}`;
|
|
1138
1157
|
// Construct the sort command dynamically based on the number of files for sorting
|
|
@@ -1157,10 +1176,10 @@ export default class Inibase {
|
|
|
1157
1176
|
await File.lock(join(tablePath, ".tmp"), cacheKey);
|
|
1158
1177
|
// Combine the commands
|
|
1159
1178
|
// Execute the command synchronously
|
|
1160
|
-
const { stdout
|
|
1161
|
-
? (await File.isExists(join(tablePath, ".cache", `${cacheKey}.
|
|
1162
|
-
? `${awkCommand} ${join(tablePath, ".cache", `${cacheKey}.
|
|
1163
|
-
: `${pasteCommand} | ${sortCommand} -o ${join(tablePath, ".cache", `${cacheKey}.
|
|
1179
|
+
const { stdout } = await UtilsServer.exec(Config.isCacheEnabled
|
|
1180
|
+
? (await File.isExists(join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)))
|
|
1181
|
+
? `${awkCommand} ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}`
|
|
1182
|
+
: `${pasteCommand} | ${sortCommand} -o ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)} && ${awkCommand} ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}`
|
|
1164
1183
|
: `${pasteCommand} | ${sortCommand} | ${awkCommand}`, {
|
|
1165
1184
|
encoding: "utf-8",
|
|
1166
1185
|
});
|
|
@@ -1169,11 +1188,11 @@ export default class Inibase {
|
|
|
1169
1188
|
const outputArray = lines.map((line) => {
|
|
1170
1189
|
const splitedFileColumns = line.split("\t"); // Assuming tab-separated columns
|
|
1171
1190
|
const outputObject = {};
|
|
1172
|
-
// Extract values for each file, including
|
|
1191
|
+
// Extract values for each file, including `id${this.getFileExtension()}`
|
|
1173
1192
|
filesPathes.forEach((fileName, index) => {
|
|
1174
|
-
const
|
|
1175
|
-
if (
|
|
1176
|
-
outputObject[
|
|
1193
|
+
const field = Utils.getField(parse(fileName).name, schema);
|
|
1194
|
+
if (field)
|
|
1195
|
+
outputObject[field.key] = File.decode(splitedFileColumns[index], field?.type, field?.children, this.salt);
|
|
1177
1196
|
});
|
|
1178
1197
|
return outputObject;
|
|
1179
1198
|
});
|
package/dist/utils.d.ts
CHANGED
|
@@ -172,4 +172,8 @@ export declare function FormatObjectCriteriaValue(value: string, isParentArray?:
|
|
|
172
172
|
type ValidKey = number | string;
|
|
173
173
|
export declare const swapKeyValue: <K extends ValidKey, V extends ValidKey>(object: Record<K, V>) => Record<V, K>;
|
|
174
174
|
export declare function getField(keyPath: string, schema: Schema): Field | null;
|
|
175
|
+
export declare function setField(keyPath: string, schema: Schema, field: Omit<Field, "key" | "type"> & {
|
|
176
|
+
key?: string;
|
|
177
|
+
type?: FieldType | FieldType[];
|
|
178
|
+
}): Field | null | undefined;
|
|
175
179
|
export {};
|
package/dist/utils.js
CHANGED
|
@@ -365,3 +365,19 @@ export function getField(keyPath, schema) {
|
|
|
365
365
|
return null;
|
|
366
366
|
return isArrayOfObjects(RETURN) ? RETURN[0] : RETURN;
|
|
367
367
|
}
|
|
368
|
+
export function setField(keyPath, schema, field) {
|
|
369
|
+
const keyPathSplited = keyPath.split(".");
|
|
370
|
+
for (const [index, key] of keyPathSplited.entries()) {
|
|
371
|
+
const foundItem = schema.find((item) => item.key === key);
|
|
372
|
+
if (!foundItem)
|
|
373
|
+
return null;
|
|
374
|
+
if (index === keyPathSplited.length - 1) {
|
|
375
|
+
Object.assign(foundItem, field);
|
|
376
|
+
return foundItem;
|
|
377
|
+
}
|
|
378
|
+
if ((foundItem.type === "array" || foundItem.type === "object") &&
|
|
379
|
+
foundItem.children &&
|
|
380
|
+
isArrayOfObjects(foundItem.children))
|
|
381
|
+
schema = foundItem.children;
|
|
382
|
+
}
|
|
383
|
+
}
|
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.59",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Karim Amahtil",
|
|
6
6
|
"email": "karim.amahtil@gmail.com"
|
|
@@ -47,6 +47,9 @@
|
|
|
47
47
|
"pocketbase"
|
|
48
48
|
],
|
|
49
49
|
"license": "MIT",
|
|
50
|
+
"bin": {
|
|
51
|
+
"inibase": "./dist/cli.js"
|
|
52
|
+
},
|
|
50
53
|
"type": "module",
|
|
51
54
|
"types": "./dist",
|
|
52
55
|
"typesVersions": {
|
|
@@ -70,6 +73,7 @@
|
|
|
70
73
|
},
|
|
71
74
|
"devDependencies": {
|
|
72
75
|
"@types/node": "^20.12.11",
|
|
76
|
+
"dotenv": "^16.4.5",
|
|
73
77
|
"tinybench": "^2.6.0"
|
|
74
78
|
},
|
|
75
79
|
"dependencies": {
|
|
@@ -77,9 +81,8 @@
|
|
|
77
81
|
},
|
|
78
82
|
"scripts": {
|
|
79
83
|
"build": "tsc",
|
|
80
|
-
"
|
|
81
|
-
"benchmark": "
|
|
82
|
-
"benchmark:
|
|
83
|
-
"benchmark:bulk": "npx tsx --expose-gc --env-file=.env ./benchmark/bulk"
|
|
84
|
+
"benchmark": "tsx ./benchmark/index",
|
|
85
|
+
"benchmark:single": "tsx --expose-gc ./benchmark/single",
|
|
86
|
+
"benchmark:bulk": "tsx --expose-gc ./benchmark/bulk"
|
|
84
87
|
}
|
|
85
88
|
}
|