inibase 1.0.0-rc.31 → 1.0.0-rc.33
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/file.d.ts +4 -0
- package/dist/file.js +27 -2
- package/dist/index.js +143 -158
- package/package.json +1 -1
package/dist/file.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
import { ComparisonOperator, FieldType } from "./index.js";
|
|
3
|
+
export declare const lock: (folderPath: string) => Promise<void>;
|
|
4
|
+
export declare const unlock: (folderPath: string) => Promise<void>;
|
|
3
5
|
export declare const write: (filePath: string, data: any, disableCompression?: boolean) => Promise<void>;
|
|
4
6
|
export declare const read: (filePath: string, disableCompression?: boolean) => Promise<string>;
|
|
5
7
|
/**
|
|
@@ -168,4 +170,6 @@ export default class File {
|
|
|
168
170
|
static count: (filePath: string) => Promise<number>;
|
|
169
171
|
static write: (filePath: string, data: any, disableCompression?: boolean) => Promise<void>;
|
|
170
172
|
static read: (filePath: string, disableCompression?: boolean) => Promise<string>;
|
|
173
|
+
static lock: (folderPath: string) => Promise<void>;
|
|
174
|
+
static unlock: (folderPath: string) => Promise<void>;
|
|
171
175
|
}
|
package/dist/file.js
CHANGED
|
@@ -1,16 +1,39 @@
|
|
|
1
|
-
import { open, access, writeFile, readFile, constants as fsConstants, } from "node:fs/promises";
|
|
1
|
+
import { open, access, writeFile, readFile, constants as fsConstants, unlink, } from "node:fs/promises";
|
|
2
2
|
import { createInterface } from "node:readline";
|
|
3
3
|
import { Transform } from "node:stream";
|
|
4
4
|
import { pipeline } from "node:stream/promises";
|
|
5
5
|
import { createGzip, createGunzip, gzip as gzipAsync, gunzip as gunzipAsync, } from "node:zlib";
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
|
+
import { join } from "node:path";
|
|
7
8
|
import { detectFieldType, isArrayOfArrays, isNumber, isObject, } from "./utils.js";
|
|
8
9
|
import { encodeID, comparePassword } from "./utils.server.js";
|
|
9
10
|
import Config from "./config.js";
|
|
10
11
|
const gzip = promisify(gzipAsync);
|
|
11
12
|
const gunzip = promisify(gunzipAsync);
|
|
13
|
+
export const lock = async (folderPath) => {
|
|
14
|
+
let lockFile, lockFilePath = join(folderPath, "locked.inib");
|
|
15
|
+
try {
|
|
16
|
+
lockFile = await open(lockFilePath, "wx");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
catch ({ message }) {
|
|
20
|
+
if (message.split(":")[0] === "EEXIST")
|
|
21
|
+
return await new Promise((resolve, reject) => setTimeout(() => resolve(lock(folderPath)), 13));
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
await lockFile?.close();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export const unlock = async (folderPath) => {
|
|
28
|
+
try {
|
|
29
|
+
await unlink(join(folderPath, "locked.inib"));
|
|
30
|
+
}
|
|
31
|
+
catch { }
|
|
32
|
+
};
|
|
12
33
|
export const write = async (filePath, data, disableCompression = false) => {
|
|
13
|
-
await writeFile(filePath, Config.isCompressionEnabled && !disableCompression
|
|
34
|
+
await writeFile(filePath, Config.isCompressionEnabled && !disableCompression
|
|
35
|
+
? await gzip(String(data))
|
|
36
|
+
: String(data));
|
|
14
37
|
};
|
|
15
38
|
export const read = async (filePath, disableCompression = false) => {
|
|
16
39
|
return Config.isCompressionEnabled && !disableCompression
|
|
@@ -765,4 +788,6 @@ export default class File {
|
|
|
765
788
|
static count = count;
|
|
766
789
|
static write = write;
|
|
767
790
|
static read = read;
|
|
791
|
+
static lock = lock;
|
|
792
|
+
static unlock = unlock;
|
|
768
793
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { unlink, rename, mkdir, readdir
|
|
1
|
+
import { unlink, rename, mkdir, readdir } from "node:fs/promises";
|
|
2
2
|
import { existsSync, appendFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { cpus } from "node:os";
|
|
@@ -66,12 +66,12 @@ export default class Inibase {
|
|
|
66
66
|
// remove id from schema
|
|
67
67
|
schema = schema.filter(({ key }) => !["id", "createdAt", "updatedAt"].includes(key));
|
|
68
68
|
schema = UtilsServer.addIdToSchema(schema, UtilsServer.findLastIdNumber(schema, this.salt), this.salt);
|
|
69
|
-
const
|
|
70
|
-
if (!(await File.isExists(
|
|
71
|
-
await mkdir(
|
|
72
|
-
if (!(await File.isExists(join(
|
|
73
|
-
await mkdir(join(
|
|
74
|
-
if (await File.isExists(
|
|
69
|
+
const tablePath = join(this.folder, this.database, tableName), tableSchemaPath = join(tablePath, "schema.json");
|
|
70
|
+
if (!(await File.isExists(tablePath)))
|
|
71
|
+
await mkdir(tablePath, { recursive: true });
|
|
72
|
+
if (!(await File.isExists(join(tablePath, ".tmp"))))
|
|
73
|
+
await mkdir(join(tablePath, ".tmp"));
|
|
74
|
+
if (await File.isExists(tableSchemaPath)) {
|
|
75
75
|
// update columns files names based on field id
|
|
76
76
|
const schemaToIdsPath = (schema, prefix = "") => {
|
|
77
77
|
let RETURN = {};
|
|
@@ -88,17 +88,17 @@ export default class Inibase {
|
|
|
88
88
|
}, replaceOldPathes = Utils.findChangedProperties(schemaToIdsPath((await this.getTableSchema(tableName)) ?? []), schemaToIdsPath(schema));
|
|
89
89
|
if (replaceOldPathes)
|
|
90
90
|
await Promise.all(Object.entries(replaceOldPathes).map(async ([oldPath, newPath]) => {
|
|
91
|
-
if (await File.isExists(join(
|
|
92
|
-
await rename(join(
|
|
91
|
+
if (await File.isExists(join(tablePath, oldPath)))
|
|
92
|
+
await rename(join(tablePath, oldPath), join(tablePath, newPath));
|
|
93
93
|
}));
|
|
94
94
|
}
|
|
95
|
-
await File.write(join(
|
|
95
|
+
await File.write(join(tablePath, "schema.json"), JSON.stringify(decodeIdFromSchema(schema), null, 2), true);
|
|
96
96
|
}
|
|
97
97
|
async getTableSchema(tableName) {
|
|
98
|
-
const
|
|
99
|
-
if (!(await File.isExists(
|
|
98
|
+
const tableSchemaPath = join(this.folder, this.database, tableName, "schema.json");
|
|
99
|
+
if (!(await File.isExists(tableSchemaPath)))
|
|
100
100
|
return undefined;
|
|
101
|
-
const schemaFile = await File.read(
|
|
101
|
+
const schemaFile = await File.read(tableSchemaPath, true);
|
|
102
102
|
if (!schemaFile)
|
|
103
103
|
return undefined;
|
|
104
104
|
const schema = JSON.parse(schemaFile), lastIdNumber = UtilsServer.findLastIdNumber(schema, this.salt);
|
|
@@ -301,7 +301,7 @@ export default class Inibase {
|
|
|
301
301
|
]));
|
|
302
302
|
}
|
|
303
303
|
async getItemsFromSchema(tableName, schema, linesNumber, options, prefix) {
|
|
304
|
-
const
|
|
304
|
+
const tablePath = join(this.folder, this.database, tableName);
|
|
305
305
|
let RETURN = {};
|
|
306
306
|
await Promise.all(schema.map(async (field) => {
|
|
307
307
|
if ((field.type === "array" ||
|
|
@@ -392,7 +392,7 @@ export default class Inibase {
|
|
|
392
392
|
options.columns = options.columns
|
|
393
393
|
.filter((column) => column.includes(`${field.key}.`))
|
|
394
394
|
.map((column) => column.replace(`${field.key}.`, ""));
|
|
395
|
-
const items = await File.get(join(
|
|
395
|
+
const items = await File.get(join(tablePath, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field.children, this.salt);
|
|
396
396
|
if (items)
|
|
397
397
|
await Promise.all(Object.entries(items).map(async ([index, item]) => {
|
|
398
398
|
if (!RETURN[index])
|
|
@@ -402,8 +402,8 @@ export default class Inibase {
|
|
|
402
402
|
: this.getDefaultValue(field);
|
|
403
403
|
}));
|
|
404
404
|
}
|
|
405
|
-
else if (await File.isExists(join(
|
|
406
|
-
const items = await File.get(join(
|
|
405
|
+
else if (await File.isExists(join(tablePath, (prefix ?? "") + field.key + ".inib"))) {
|
|
406
|
+
const items = await File.get(join(tablePath, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
|
|
407
407
|
if (items)
|
|
408
408
|
for (const [index, item] of Object.entries(items)) {
|
|
409
409
|
if (!RETURN[index])
|
|
@@ -428,13 +428,13 @@ export default class Inibase {
|
|
|
428
428
|
}
|
|
429
429
|
else if (field.type === "table") {
|
|
430
430
|
if ((await File.isExists(join(this.folder, this.database, field.key))) &&
|
|
431
|
-
(await File.isExists(join(
|
|
431
|
+
(await File.isExists(join(tablePath, (prefix ?? "") + field.key + ".inib")))) {
|
|
432
432
|
if (options.columns)
|
|
433
433
|
options.columns = options.columns
|
|
434
434
|
.filter((column) => column.includes(`${field.key}.`) &&
|
|
435
435
|
!column.includes(`${field.key}.`))
|
|
436
436
|
.map((column) => column.replace(`${field.key}.`, ""));
|
|
437
|
-
const items = await File.get(join(
|
|
437
|
+
const items = await File.get(join(tablePath, (prefix ?? "") + field.key + ".inib"), linesNumber, "number", undefined, this.salt);
|
|
438
438
|
if (items)
|
|
439
439
|
for await (const [index, item] of Object.entries(items)) {
|
|
440
440
|
if (!RETURN[index])
|
|
@@ -445,8 +445,8 @@ export default class Inibase {
|
|
|
445
445
|
}
|
|
446
446
|
}
|
|
447
447
|
}
|
|
448
|
-
else if (await File.isExists(join(
|
|
449
|
-
const items = await File.get(join(
|
|
448
|
+
else if (await File.isExists(join(tablePath, (prefix ?? "") + field.key + ".inib"))) {
|
|
449
|
+
const items = await File.get(join(tablePath, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
|
|
450
450
|
if (items)
|
|
451
451
|
for (const [index, item] of Object.entries(items)) {
|
|
452
452
|
if (!RETURN[index])
|
|
@@ -463,6 +463,7 @@ export default class Inibase {
|
|
|
463
463
|
return RETURN;
|
|
464
464
|
}
|
|
465
465
|
async applyCriteria(tableName, schema, options, criteria, allTrue) {
|
|
466
|
+
const tablePath = join(this.folder, this.database, tableName);
|
|
466
467
|
let RETURN = {}, RETURN_LineNumbers = null;
|
|
467
468
|
if (!criteria)
|
|
468
469
|
return [null, null];
|
|
@@ -545,7 +546,7 @@ export default class Inibase {
|
|
|
545
546
|
searchOperator = "=";
|
|
546
547
|
searchComparedAtValue = value;
|
|
547
548
|
}
|
|
548
|
-
const [searchResult, totalLines, linesNumbers] = await File.search(join(
|
|
549
|
+
const [searchResult, totalLines, linesNumbers] = await File.search(join(tablePath, key + ".inib"), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, field?.type, field?.children, options.perPage, options.page - 1 * options.perPage + 1, true, this.salt);
|
|
549
550
|
if (searchResult) {
|
|
550
551
|
RETURN = Utils.deepMerge(RETURN, Object.fromEntries(Object.entries(searchResult).map(([id, value]) => [
|
|
551
552
|
id,
|
|
@@ -592,6 +593,7 @@ export default class Inibase {
|
|
|
592
593
|
page: 1,
|
|
593
594
|
perPage: 15,
|
|
594
595
|
}, onlyOne, onlyLinesNumbers, tableSchema) {
|
|
596
|
+
const tablePath = join(this.folder, this.database, tableName);
|
|
595
597
|
// Ensure options.columns is an array
|
|
596
598
|
if (options.columns) {
|
|
597
599
|
options.columns = Array.isArray(options.columns)
|
|
@@ -607,8 +609,7 @@ export default class Inibase {
|
|
|
607
609
|
let schema = tableSchema ?? (await this.getTableSchema(tableName));
|
|
608
610
|
if (!schema)
|
|
609
611
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
610
|
-
|
|
611
|
-
if (!(await File.isExists(idFilePath)))
|
|
612
|
+
if (!(await File.isExists(join(tablePath, "id.inib"))))
|
|
612
613
|
return null;
|
|
613
614
|
if (options.columns && options.columns.length)
|
|
614
615
|
schema = this._filterSchemaByColumns(schema, options.columns);
|
|
@@ -618,12 +619,15 @@ export default class Inibase {
|
|
|
618
619
|
index +
|
|
619
620
|
1), options));
|
|
620
621
|
if (Config.isCacheEnabled &&
|
|
621
|
-
(await File.isExists(join(
|
|
622
|
-
this.totalItems[tableName + "-*"] = Number(await File.read(join(
|
|
622
|
+
(await File.isExists(join(tablePath, ".tmp", "pagination.inib"))))
|
|
623
|
+
this.totalItems[tableName + "-*"] = Number((await File.read(join(tablePath, ".tmp", "pagination.inib"), true)).split(",")[1]);
|
|
623
624
|
else {
|
|
624
|
-
|
|
625
|
+
let [lastId, totalItems] = await File.get(join(tablePath, "id.inib"), -1, "number", undefined, this.salt, true);
|
|
626
|
+
if (lastId)
|
|
627
|
+
lastId = Number(Object.keys(lastId)[0] ?? 0);
|
|
628
|
+
this.totalItems[tableName + "-*"] = totalItems;
|
|
625
629
|
if (Config.isCacheEnabled)
|
|
626
|
-
await File.write(join(
|
|
630
|
+
await File.write(join(tablePath, ".tmp", "pagination.inib"), `${lastId},${totalItems}`, true);
|
|
627
631
|
}
|
|
628
632
|
}
|
|
629
633
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
@@ -644,7 +648,7 @@ export default class Inibase {
|
|
|
644
648
|
let Ids = where;
|
|
645
649
|
if (!Array.isArray(Ids))
|
|
646
650
|
Ids = [Ids];
|
|
647
|
-
const [lineNumbers, countItems] = await File.search(
|
|
651
|
+
const [lineNumbers, countItems] = await File.search(join(tablePath, "id.inib"), "[]", Ids.map((id) => Utils.isNumber(id) ? Number(id) : UtilsServer.decodeID(id, this.salt)), undefined, "number", undefined, Ids.length, 0, !this.totalItems[tableName + "-*"], this.salt);
|
|
648
652
|
if (!lineNumbers)
|
|
649
653
|
throw this.throwError("INVALID_ID", where);
|
|
650
654
|
if (onlyLinesNumbers)
|
|
@@ -652,16 +656,8 @@ export default class Inibase {
|
|
|
652
656
|
? Object.keys(lineNumbers).map(Number)
|
|
653
657
|
: null;
|
|
654
658
|
RETURN = Object.values((await this.getItemsFromSchema(tableName, schema, Object.keys(lineNumbers).map(Number), options)) ?? {});
|
|
655
|
-
if (!this.totalItems[tableName + "-*"])
|
|
656
|
-
|
|
657
|
-
(await File.isExists(join(this.folder, this.database, tableName, ".tmp", "totalItems.inib"))))
|
|
658
|
-
this.totalItems[tableName + "-*"] = Number(await File.read(join(this.folder, this.database, tableName, ".tmp", "totalItems.inib"), true));
|
|
659
|
-
else {
|
|
660
|
-
this.totalItems[tableName + "-*"] = await File.count(idFilePath);
|
|
661
|
-
if (Config.isCacheEnabled)
|
|
662
|
-
await File.write(join(this.folder, this.database, tableName, ".tmp", "totalItems.inib"), String(this.totalItems[tableName + "-*"]), true);
|
|
663
|
-
}
|
|
664
|
-
}
|
|
659
|
+
if (!this.totalItems[tableName + "-*"])
|
|
660
|
+
this.totalItems[tableName + "-*"] = countItems;
|
|
665
661
|
if (RETURN && RETURN.length && !Array.isArray(where))
|
|
666
662
|
RETURN = RETURN[0];
|
|
667
663
|
}
|
|
@@ -669,7 +665,7 @@ export default class Inibase {
|
|
|
669
665
|
let cachedFilePath = "";
|
|
670
666
|
// Criteria
|
|
671
667
|
if (Config.isCacheEnabled)
|
|
672
|
-
cachedFilePath = join(
|
|
668
|
+
cachedFilePath = join(tablePath, ".tmp", `${UtilsServer.hashObject(where)}.inib`);
|
|
673
669
|
if (Config.isCacheEnabled && (await File.isExists(cachedFilePath))) {
|
|
674
670
|
const cachedItems = (await File.read(cachedFilePath, true)).split(",");
|
|
675
671
|
this.totalItems[tableName + "-*"] = cachedItems.length;
|
|
@@ -714,62 +710,50 @@ export default class Inibase {
|
|
|
714
710
|
page: 1,
|
|
715
711
|
perPage: 15,
|
|
716
712
|
};
|
|
717
|
-
const
|
|
718
|
-
let testFileHandle, renameList = [];
|
|
719
|
-
try {
|
|
720
|
-
testFileHandle = await open(join(cashFolderPath, "id.inib"), "wx");
|
|
721
|
-
renameList = [[join(cashFolderPath, "id.inib"), ""]];
|
|
722
|
-
}
|
|
723
|
-
catch ({ message }) {
|
|
724
|
-
if (message.split(":")[0] === "EEXIST")
|
|
725
|
-
return await new Promise((resolve, reject) => setTimeout(() => resolve(this.post(tableName, data, options, returnPostedData)), 13));
|
|
726
|
-
}
|
|
727
|
-
finally {
|
|
728
|
-
await testFileHandle?.close();
|
|
729
|
-
}
|
|
713
|
+
const tablePath = join(this.folder, this.database, tableName);
|
|
730
714
|
if (!returnPostedData)
|
|
731
715
|
returnPostedData = false;
|
|
732
716
|
const schema = await this.getTableSchema(tableName);
|
|
733
717
|
let RETURN;
|
|
734
718
|
if (!schema)
|
|
735
719
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
736
|
-
let lastId = 0, totalItems = 0,
|
|
737
|
-
if (await File.isExists(idFilePath)) {
|
|
738
|
-
if (await File.isExists(join(cashFolderPath, "lastId.inib"))) {
|
|
739
|
-
lastId = Number(await File.read(join(cashFolderPath, "lastId.inib"), true));
|
|
740
|
-
if (await File.isExists(join(cashFolderPath, "totalItems.inib")))
|
|
741
|
-
totalItems = Number(await File.read(join(cashFolderPath, "totalItems.inib"), true));
|
|
742
|
-
else
|
|
743
|
-
totalItems = await File.count(join(this.folder, this.database, tableName, "id.inib"));
|
|
744
|
-
}
|
|
745
|
-
else {
|
|
746
|
-
[lastIdObj, totalItems] = await File.get(idFilePath, -1, "number", undefined, this.salt, true);
|
|
747
|
-
if (lastIdObj)
|
|
748
|
-
lastId = Number(Object.entries(lastIdObj)[0][1]) ?? 0;
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
if (Utils.isArrayOfObjects(data))
|
|
752
|
-
RETURN = data.map(({ id, updatedAt, createdAt, ...rest }) => ({
|
|
753
|
-
id: ++lastId,
|
|
754
|
-
...rest,
|
|
755
|
-
createdAt: Date.now(),
|
|
756
|
-
}));
|
|
757
|
-
else
|
|
758
|
-
RETURN = (({ id, updatedAt, createdAt, ...rest }) => ({
|
|
759
|
-
id: ++lastId,
|
|
760
|
-
...rest,
|
|
761
|
-
createdAt: Date.now(),
|
|
762
|
-
}))(data);
|
|
763
|
-
if (!RETURN)
|
|
764
|
-
throw this.throwError("NO_DATA");
|
|
720
|
+
let lastId = 0, totalItems = 0, renameList = [];
|
|
765
721
|
try {
|
|
722
|
+
await File.lock(join(tablePath, ".tmp"));
|
|
723
|
+
if (await File.isExists(join(tablePath, "id.inib"))) {
|
|
724
|
+
if (Config.isCacheEnabled &&
|
|
725
|
+
(await File.isExists(join(tablePath, ".tmp", "pagination.inib"))))
|
|
726
|
+
[lastId, totalItems] = (await File.read(join(tablePath, ".tmp", "pagination.inib"), true))
|
|
727
|
+
.split(",")
|
|
728
|
+
.map(Number);
|
|
729
|
+
else {
|
|
730
|
+
let lastIdObj;
|
|
731
|
+
[lastIdObj, totalItems] = await File.get(join(tablePath, "id.inib"), -1, "number", undefined, this.salt, true);
|
|
732
|
+
if (lastIdObj)
|
|
733
|
+
lastId = Number(Object.keys(lastIdObj)[0] ?? 0);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
if (Utils.isArrayOfObjects(data))
|
|
737
|
+
RETURN = data.map(({ id, updatedAt, createdAt, ...rest }) => ({
|
|
738
|
+
id: ++lastId,
|
|
739
|
+
...rest,
|
|
740
|
+
createdAt: Date.now(),
|
|
741
|
+
}));
|
|
742
|
+
else
|
|
743
|
+
RETURN = (({ id, updatedAt, createdAt, ...rest }) => ({
|
|
744
|
+
id: ++lastId,
|
|
745
|
+
...rest,
|
|
746
|
+
createdAt: Date.now(),
|
|
747
|
+
}))(data);
|
|
748
|
+
if (!RETURN)
|
|
749
|
+
throw this.throwError("NO_DATA");
|
|
766
750
|
RETURN = this.formatData(RETURN, schema);
|
|
767
|
-
const pathesContents = this.joinPathesContents(join(
|
|
768
|
-
|
|
751
|
+
const pathesContents = this.joinPathesContents(join(tablePath), Array.isArray(RETURN) ? RETURN.toReversed() : RETURN);
|
|
752
|
+
await Promise.all(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(await File.append(path, content))));
|
|
769
753
|
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
770
754
|
renameList = [];
|
|
771
|
-
|
|
772
|
-
|
|
755
|
+
if (Config.isCacheEnabled)
|
|
756
|
+
await File.write(join(tablePath, ".tmp", "pagination.inib"), `${lastId},${totalItems + (Array.isArray(RETURN) ? RETURN.length : 1)}`, true);
|
|
773
757
|
if (returnPostedData)
|
|
774
758
|
return this.get(tableName, Utils.isArrayOfObjects(RETURN)
|
|
775
759
|
? RETURN.map((data) => Number(data.id))
|
|
@@ -778,18 +762,20 @@ export default class Inibase {
|
|
|
778
762
|
}
|
|
779
763
|
finally {
|
|
780
764
|
if (renameList.length)
|
|
781
|
-
await Promise.
|
|
765
|
+
await Promise.allSettled(renameList.map(async ([tempPath, _]) => unlink(tempPath)));
|
|
766
|
+
await File.unlock(join(tablePath, ".tmp"));
|
|
782
767
|
}
|
|
783
768
|
}
|
|
784
769
|
async put(tableName, data, where, options = {
|
|
785
770
|
page: 1,
|
|
786
771
|
perPage: 15,
|
|
787
772
|
}, returnPostedData) {
|
|
773
|
+
let renameList = [];
|
|
774
|
+
const tablePath = join(this.folder, this.database, tableName);
|
|
788
775
|
const schema = await this.getTableSchema(tableName);
|
|
789
776
|
if (!schema)
|
|
790
777
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
791
|
-
|
|
792
|
-
if (!(await File.isExists(idFilePath)))
|
|
778
|
+
if (!(await File.isExists(join(tablePath, "id.inib"))))
|
|
793
779
|
throw this.throwError("NO_ITEMS", tableName);
|
|
794
780
|
data = this.formatData(data, schema, true);
|
|
795
781
|
if (!where) {
|
|
@@ -806,7 +792,7 @@ export default class Inibase {
|
|
|
806
792
|
return this.put(tableName, data, UtilsServer.decodeID(data.id, this.salt));
|
|
807
793
|
}
|
|
808
794
|
else {
|
|
809
|
-
const pathesContents = this.joinPathesContents(join(
|
|
795
|
+
const pathesContents = this.joinPathesContents(join(tablePath), Utils.isArrayOfObjects(data)
|
|
810
796
|
? data.map((item) => ({
|
|
811
797
|
...(({ id, ...restOfData }) => restOfData)(item),
|
|
812
798
|
updatedAt: Date.now(),
|
|
@@ -815,26 +801,22 @@ export default class Inibase {
|
|
|
815
801
|
...(({ id, ...restOfData }) => restOfData)(data),
|
|
816
802
|
updatedAt: Date.now(),
|
|
817
803
|
});
|
|
818
|
-
let testFileHandle;
|
|
819
804
|
try {
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
if (
|
|
824
|
-
|
|
805
|
+
await File.lock(join(tablePath, ".tmp"));
|
|
806
|
+
await Promise.all(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(await File.replace(path, content))));
|
|
807
|
+
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
808
|
+
if (Config.isCacheEnabled)
|
|
809
|
+
await Promise.all((await readdir(join(tablePath, ".tmp")))
|
|
810
|
+
?.filter((fileName) => !["pagination.inib", "locked.inib"].includes(fileName))
|
|
811
|
+
.map(async (file) => unlink(join(tablePath, ".tmp", file))));
|
|
812
|
+
if (returnPostedData)
|
|
813
|
+
return this.get(tableName, where, options, undefined, undefined, schema);
|
|
825
814
|
}
|
|
826
815
|
finally {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
831
|
-
if (Config.isCacheEnabled) {
|
|
832
|
-
const cacheFiles = (await readdir(join(this.folder, this.database, tableName, ".tmp")))?.filter((fileName) => !["lastId.inib", "totalItems.inib"].includes(fileName));
|
|
833
|
-
if (cacheFiles.length)
|
|
834
|
-
await Promise.all(cacheFiles.map(async (file) => unlink(join(this.folder, this.database, tableName, ".tmp", file))));
|
|
816
|
+
if (renameList.length)
|
|
817
|
+
await Promise.allSettled(renameList.map(async ([tempPath, _]) => unlink(tempPath)));
|
|
818
|
+
await File.unlock(join(tablePath, ".tmp"));
|
|
835
819
|
}
|
|
836
|
-
if (returnPostedData)
|
|
837
|
-
return this.get(tableName, where, options, undefined, undefined, schema);
|
|
838
820
|
}
|
|
839
821
|
}
|
|
840
822
|
else if ((Array.isArray(where) &&
|
|
@@ -849,7 +831,7 @@ export default class Inibase {
|
|
|
849
831
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
850
832
|
Utils.isNumber(where)) {
|
|
851
833
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
852
|
-
const pathesContents = Object.fromEntries(Object.entries(this.joinPathesContents(join(
|
|
834
|
+
const pathesContents = Object.fromEntries(Object.entries(this.joinPathesContents(join(tablePath), Utils.isArrayOfObjects(data)
|
|
853
835
|
? data.map((item) => ({
|
|
854
836
|
...item,
|
|
855
837
|
updatedAt: Date.now(),
|
|
@@ -861,26 +843,23 @@ export default class Inibase {
|
|
|
861
843
|
[lineNum]: Array.isArray(content) ? content[index] : content,
|
|
862
844
|
}), {}),
|
|
863
845
|
]));
|
|
864
|
-
let testFileHandle;
|
|
865
846
|
try {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
847
|
+
await File.lock(join(tablePath, ".tmp"));
|
|
848
|
+
await Promise.all(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(await File.replace(path, content))));
|
|
849
|
+
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
850
|
+
renameList = [];
|
|
851
|
+
if (Config.isCacheEnabled)
|
|
852
|
+
await Promise.all((await readdir(join(tablePath, ".tmp")))
|
|
853
|
+
?.filter((fileName) => !["pagination.inib", "locked.inib"].includes(fileName))
|
|
854
|
+
.map(async (file) => unlink(join(tablePath, ".tmp", file))));
|
|
855
|
+
if (returnPostedData)
|
|
856
|
+
return this.get(tableName, where, options, !Array.isArray(where), undefined, schema);
|
|
871
857
|
}
|
|
872
858
|
finally {
|
|
873
|
-
|
|
859
|
+
if (renameList.length)
|
|
860
|
+
await Promise.allSettled(renameList.map(async ([tempPath, _]) => unlink(tempPath)));
|
|
861
|
+
await File.unlock(join(tablePath, ".tmp"));
|
|
874
862
|
}
|
|
875
|
-
const renameList = await Promise.all(Object.entries(pathesContents).map(async ([path, content]) => File.replace(path, content)));
|
|
876
|
-
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
877
|
-
if (Config.isCacheEnabled) {
|
|
878
|
-
const cacheFiles = (await readdir(join(this.folder, this.database, tableName, ".tmp")))?.filter((fileName) => !["lastId.inib", "totalItems.inib"].includes(fileName));
|
|
879
|
-
if (cacheFiles.length)
|
|
880
|
-
await Promise.all(cacheFiles.map(async (file) => unlink(join(this.folder, this.database, tableName, ".tmp", file))));
|
|
881
|
-
}
|
|
882
|
-
if (returnPostedData)
|
|
883
|
-
return this.get(tableName, where, options, !Array.isArray(where), undefined, schema);
|
|
884
863
|
}
|
|
885
864
|
}
|
|
886
865
|
else if (Utils.isObject(where)) {
|
|
@@ -893,20 +872,26 @@ export default class Inibase {
|
|
|
893
872
|
throw this.throwError("INVALID_PARAMETERS", tableName);
|
|
894
873
|
}
|
|
895
874
|
async delete(tableName, where, _id) {
|
|
875
|
+
let renameList = [];
|
|
876
|
+
const tablePath = join(this.folder, this.database, tableName);
|
|
896
877
|
const schema = await this.getTableSchema(tableName);
|
|
897
878
|
if (!schema)
|
|
898
879
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
899
|
-
|
|
900
|
-
if (!(await File.isExists(idFilePath)))
|
|
880
|
+
if (!(await File.isExists(join(tablePath, "id.inib"))))
|
|
901
881
|
throw this.throwError("NO_ITEMS", tableName);
|
|
902
882
|
if (!where) {
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
await Promise.all(
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
if (
|
|
909
|
-
await Promise.all(
|
|
883
|
+
try {
|
|
884
|
+
await File.lock(join(tablePath, ".tmp"));
|
|
885
|
+
await Promise.all((await readdir(join(tablePath)))
|
|
886
|
+
?.filter((fileName) => fileName.endsWith(".inib"))
|
|
887
|
+
.map(async (file) => unlink(join(tablePath, file))));
|
|
888
|
+
if (Config.isCacheEnabled)
|
|
889
|
+
await Promise.all((await readdir(join(tablePath, ".tmp")))
|
|
890
|
+
?.filter((fileName) => !["pagination.inib", "locked.inib"].includes(fileName))
|
|
891
|
+
.map(async (file) => unlink(join(tablePath, ".tmp", file))));
|
|
892
|
+
}
|
|
893
|
+
finally {
|
|
894
|
+
await File.unlock(join(tablePath, ".tmp"));
|
|
910
895
|
}
|
|
911
896
|
return "*";
|
|
912
897
|
}
|
|
@@ -924,34 +909,34 @@ export default class Inibase {
|
|
|
924
909
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
925
910
|
Utils.isNumber(where)) {
|
|
926
911
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
927
|
-
const files = (await readdir(join(
|
|
912
|
+
const files = (await readdir(join(tablePath)))?.filter((fileName) => fileName.endsWith(".inib"));
|
|
928
913
|
if (files.length) {
|
|
929
914
|
if (!_id)
|
|
930
|
-
_id = Object.entries((await File.get(join(
|
|
915
|
+
_id = Object.entries((await File.get(join(tablePath, "id.inib"), where, "number", undefined, this.salt)) ?? {}).map(([_key, id]) => UtilsServer.encodeID(Number(id), this.salt));
|
|
931
916
|
if (!_id.length)
|
|
932
917
|
throw this.throwError("NO_ITEMS", tableName);
|
|
933
|
-
let testFileHandle;
|
|
934
918
|
try {
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
if (
|
|
939
|
-
|
|
919
|
+
await File.lock(join(tablePath, ".tmp"));
|
|
920
|
+
await Promise.all(files.map(async (file) => renameList.push(await File.remove(join(tablePath, file), where))));
|
|
921
|
+
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
922
|
+
if (Config.isCacheEnabled) {
|
|
923
|
+
await Promise.all((await readdir(join(tablePath, ".tmp")))
|
|
924
|
+
?.filter((fileName) => !["pagination.inib", "locked.inib"].includes(fileName))
|
|
925
|
+
.map(async (file) => unlink(join(tablePath, ".tmp", file))));
|
|
926
|
+
if (await File.isExists(join(tablePath, ".tmp", "pagination.inib"))) {
|
|
927
|
+
let [lastId, totalItems] = (await File.read(join(tablePath, ".tmp", "pagination.inib"), true))
|
|
928
|
+
.split(",")
|
|
929
|
+
.map(Number);
|
|
930
|
+
await File.write(join(tablePath, ".tmp", "pagination.inib"), `${lastId},${totalItems - (Array.isArray(where) ? where.length : 1)}`, true);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
|
|
940
934
|
}
|
|
941
935
|
finally {
|
|
942
|
-
|
|
936
|
+
if (renameList.length)
|
|
937
|
+
await Promise.allSettled(renameList.map(async ([tempPath, _]) => unlink(tempPath)));
|
|
938
|
+
await File.unlock(join(tablePath, ".tmp"));
|
|
943
939
|
}
|
|
944
|
-
const renameList = await Promise.all(files.map(async (file) => File.remove(join(this.folder, this.database, tableName, file), where)));
|
|
945
|
-
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
946
|
-
if (Config.isCacheEnabled) {
|
|
947
|
-
const cacheFiles = (await readdir(join(this.folder, this.database, tableName, ".tmp")))?.filter((fileName) => !["lastId.inib", "totalItems.inib"].includes(fileName));
|
|
948
|
-
if (cacheFiles.length)
|
|
949
|
-
await Promise.all(cacheFiles.map(async (file) => unlink(join(this.folder, this.database, tableName, ".tmp", file))));
|
|
950
|
-
await File.write(join(this.folder, this.database, tableName, ".tmp", "totalItems.inib"), String(((await File.isExists(join(this.folder, this.database, tableName, ".tmp", "totalItems.inib")))
|
|
951
|
-
? Number(await File.read(join(this.folder, this.database, tableName, ".tmp", "totalItems.inib"), true))
|
|
952
|
-
: await File.count(join(this.folder, this.database, tableName, "id.inib"))) - (Array.isArray(where) ? where.length : 1)), true);
|
|
953
|
-
}
|
|
954
|
-
return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
|
|
955
940
|
}
|
|
956
941
|
}
|
|
957
942
|
}
|
|
@@ -967,10 +952,10 @@ export default class Inibase {
|
|
|
967
952
|
}
|
|
968
953
|
async sum(tableName, columns, where) {
|
|
969
954
|
let RETURN = {};
|
|
970
|
-
const schema = await this.getTableSchema(tableName);
|
|
955
|
+
const tablePath = join(this.folder, this.database, tableName), schema = await this.getTableSchema(tableName);
|
|
971
956
|
if (!schema)
|
|
972
957
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
973
|
-
if (!(await File.isExists(join(
|
|
958
|
+
if (!(await File.isExists(join(tablePath, "id.inib"))))
|
|
974
959
|
throw this.throwError("NO_ITEMS", tableName);
|
|
975
960
|
if (!Array.isArray(columns))
|
|
976
961
|
columns = [columns];
|
|
@@ -991,10 +976,10 @@ export default class Inibase {
|
|
|
991
976
|
}
|
|
992
977
|
async max(tableName, columns, where) {
|
|
993
978
|
let RETURN = {};
|
|
994
|
-
const schema = await this.getTableSchema(tableName);
|
|
979
|
+
const tablePath = join(this.folder, this.database, tableName), schema = await this.getTableSchema(tableName);
|
|
995
980
|
if (!schema)
|
|
996
981
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
997
|
-
if (!(await File.isExists(join(
|
|
982
|
+
if (!(await File.isExists(join(tablePath, "id.inib"))))
|
|
998
983
|
throw this.throwError("NO_ITEMS", tableName);
|
|
999
984
|
if (!Array.isArray(columns))
|
|
1000
985
|
columns = [columns];
|
|
@@ -1015,10 +1000,10 @@ export default class Inibase {
|
|
|
1015
1000
|
}
|
|
1016
1001
|
async min(tableName, columns, where) {
|
|
1017
1002
|
let RETURN = {};
|
|
1018
|
-
const schema = await this.getTableSchema(tableName);
|
|
1003
|
+
const tablePath = join(this.folder, this.database, tableName), schema = await this.getTableSchema(tableName);
|
|
1019
1004
|
if (!schema)
|
|
1020
1005
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
1021
|
-
if (!(await File.isExists(join(
|
|
1006
|
+
if (!(await File.isExists(join(tablePath, "id.inib"))))
|
|
1022
1007
|
throw this.throwError("NO_ITEMS", tableName);
|
|
1023
1008
|
if (!Array.isArray(columns))
|
|
1024
1009
|
columns = [columns];
|