inibase 1.0.0-rc.28 → 1.0.0-rc.29
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 +3 -1
- package/dist/file.js +16 -8
- package/dist/index.d.ts +1 -2
- package/dist/index.js +73 -93
- package/dist/utils.d.ts +6 -1
- package/dist/utils.js +55 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.org/package/inibase) [](./LICENSE) [](https://github.com/inicontent/inibase/pulse) [](https://github.com/inicontent/inibase)
|
|
6
6
|
|
|
7
|
-
> A file-based & memory-efficient, serverless relational database management system :fire:
|
|
7
|
+
> A file-based & memory-efficient, serverless, ACID compliant, relational database management system :fire:
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -74,6 +74,8 @@ To simplify the idea, each database has tables, each table has columns, each col
|
|
|
74
74
|
| PUT | 33 ms (10.29 mb) | 312 ms (11.06 mb) | 3539 ms (14.87 mb) |
|
|
75
75
|
| DELETE | 134 ms (13.50 mb) | 1224 ms (16.57 mb) | 7339 ms (11.46 mb) |
|
|
76
76
|
|
|
77
|
+
Ps: Testing by default with `user` table, with username, email, password fields _so results include password encryption process_
|
|
78
|
+
|
|
77
79
|
|
|
78
80
|
## Roadmap
|
|
79
81
|
|
package/dist/file.js
CHANGED
|
@@ -286,7 +286,7 @@ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, s
|
|
|
286
286
|
* Note: If the file doesn't exist and replacements is an object, it creates a new file with the specified replacements.
|
|
287
287
|
*/
|
|
288
288
|
export const replace = async (filePath, replacements) => {
|
|
289
|
-
const fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/$
|
|
289
|
+
const fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/$1`);
|
|
290
290
|
if (await isExists(filePath)) {
|
|
291
291
|
let fileHandle, fileTempHandle, rl;
|
|
292
292
|
try {
|
|
@@ -339,7 +339,7 @@ export const replace = async (filePath, replacements) => {
|
|
|
339
339
|
*
|
|
340
340
|
*/
|
|
341
341
|
export const append = async (filePath, data) => {
|
|
342
|
-
const fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/$
|
|
342
|
+
const fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/$1`);
|
|
343
343
|
if (await isExists(filePath)) {
|
|
344
344
|
let fileHandle, fileTempHandle, rl;
|
|
345
345
|
try {
|
|
@@ -366,7 +366,7 @@ export const append = async (filePath, data) => {
|
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
368
|
else
|
|
369
|
-
await write(fileTempPath, `${Array.isArray(data) ? data.join("\n") : data}\n
|
|
369
|
+
await write(fileTempPath, `${Array.isArray(data) ? data.join("\n") : data}\n`, undefined);
|
|
370
370
|
return [fileTempPath, filePath];
|
|
371
371
|
};
|
|
372
372
|
/**
|
|
@@ -379,16 +379,24 @@ export const append = async (filePath, data) => {
|
|
|
379
379
|
* Note: Creates a temporary file during the process and replaces the original file with it after removing lines.
|
|
380
380
|
*/
|
|
381
381
|
export const remove = async (filePath, linesToDelete) => {
|
|
382
|
-
let linesCount = 0;
|
|
383
|
-
const fileHandle = await open(filePath, "r"), fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/$
|
|
382
|
+
let linesCount = 0, deletedCount = 0;
|
|
383
|
+
const fileHandle = await open(filePath, "r"), fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/$1`), fileTempHandle = await open(fileTempPath, "w"), linesToDeleteArray = new Set(Array.isArray(linesToDelete)
|
|
384
384
|
? linesToDelete.map(Number)
|
|
385
385
|
: [Number(linesToDelete)]), rl = readLineInternface(fileHandle);
|
|
386
386
|
await _pipeline(rl, fileTempHandle.createWriteStream(), new Transform({
|
|
387
387
|
transform(line, encoding, callback) {
|
|
388
388
|
linesCount++;
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
389
|
+
if (linesToDeleteArray.has(linesCount)) {
|
|
390
|
+
deletedCount++;
|
|
391
|
+
return callback();
|
|
392
|
+
}
|
|
393
|
+
else
|
|
394
|
+
return callback(null, `${line}\n`);
|
|
395
|
+
},
|
|
396
|
+
final(callback) {
|
|
397
|
+
if (deletedCount === linesCount)
|
|
398
|
+
this.push("\n");
|
|
399
|
+
return callback();
|
|
392
400
|
},
|
|
393
401
|
}));
|
|
394
402
|
await fileTempHandle.close();
|
package/dist/index.d.ts
CHANGED
|
@@ -75,12 +75,11 @@ export default class Inibase {
|
|
|
75
75
|
private getDefaultValue;
|
|
76
76
|
private joinPathesContents;
|
|
77
77
|
private getItemsFromSchema;
|
|
78
|
-
private FormatObjectCriteriaValue;
|
|
79
78
|
private applyCriteria;
|
|
80
79
|
private _filterSchemaByColumns;
|
|
81
80
|
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: true, onlyLinesNumbers?: undefined, tableSchema?: Schema): Promise<Data | null>;
|
|
82
81
|
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: boolean | undefined, onlyLinesNumbers?: true, tableSchema?: Schema): Promise<number[] | null>;
|
|
83
|
-
post(tableName: string, data: Data | Data[], options?: Options, returnPostedData?:
|
|
82
|
+
post(tableName: string, data: Data | Data[], options?: Options, returnPostedData?: boolean): Promise<void | null>;
|
|
84
83
|
post(tableName: string, data: Data, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
|
|
85
84
|
post(tableName: string, data: Data[], options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
|
|
86
85
|
put(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria, options?: Options, returnPostedData?: false): Promise<void | null>;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { unlink, rename, mkdir, readdir } from "node:fs/promises";
|
|
1
|
+
import { unlink, rename, mkdir, readdir, open } 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";
|
|
@@ -87,9 +87,10 @@ export default class Inibase {
|
|
|
87
87
|
return RETURN;
|
|
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
91
|
if (await File.isExists(join(TablePath, oldPath)))
|
|
92
92
|
await rename(join(TablePath, oldPath), join(TablePath, newPath));
|
|
93
|
+
}));
|
|
93
94
|
}
|
|
94
95
|
await File.write(join(TablePath, "schema.json"), JSON.stringify(decodeIdFromSchema(schema), null, 2), true);
|
|
95
96
|
}
|
|
@@ -302,7 +303,7 @@ export default class Inibase {
|
|
|
302
303
|
async getItemsFromSchema(tableName, schema, linesNumber, options, prefix) {
|
|
303
304
|
const path = join(this.folder, this.database, tableName);
|
|
304
305
|
let RETURN = {};
|
|
305
|
-
|
|
306
|
+
await Promise.all(schema.map(async (field) => {
|
|
306
307
|
if ((field.type === "array" ||
|
|
307
308
|
(Array.isArray(field.type) && field.type.includes("array"))) &&
|
|
308
309
|
field.children) {
|
|
@@ -322,14 +323,17 @@ export default class Inibase {
|
|
|
322
323
|
if (Utils.isObject(item[child_field.key])) {
|
|
323
324
|
Object.entries(item[child_field.key]).forEach(([key, value]) => {
|
|
324
325
|
if (!Utils.isArrayOfArrays(value))
|
|
325
|
-
value = value.map((_value) => child_field.type === "array"
|
|
326
|
+
value = value.map((_value) => child_field.type === "array"
|
|
327
|
+
? [[_value]]
|
|
328
|
+
: [_value]);
|
|
326
329
|
for (let _i = 0; _i < value.length; _i++) {
|
|
327
330
|
if (Utils.isArrayOfNulls(value[_i]))
|
|
328
331
|
continue;
|
|
329
332
|
if (!RETURN[index][field.key][_i])
|
|
330
333
|
RETURN[index][field.key][_i] = {};
|
|
331
334
|
if (!RETURN[index][field.key][_i][child_field.key])
|
|
332
|
-
RETURN[index][field.key][_i][child_field.key] =
|
|
335
|
+
RETURN[index][field.key][_i][child_field.key] =
|
|
336
|
+
[];
|
|
333
337
|
value[_i].forEach((_element, _index) => {
|
|
334
338
|
if (!RETURN[index][field.key][_i][child_field.key][_index])
|
|
335
339
|
RETURN[index][field.key][_i][child_field.key][_index] = {};
|
|
@@ -390,13 +394,13 @@ export default class Inibase {
|
|
|
390
394
|
.map((column) => column.replace(`${field.key}.`, ""));
|
|
391
395
|
const items = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field.children, this.salt);
|
|
392
396
|
if (items)
|
|
393
|
-
|
|
397
|
+
await Promise.all(Object.entries(items).map(async ([index, item]) => {
|
|
394
398
|
if (!RETURN[index])
|
|
395
399
|
RETURN[index] = {};
|
|
396
400
|
RETURN[index][field.key] = item
|
|
397
401
|
? await this.get(field.key, item, options)
|
|
398
402
|
: this.getDefaultValue(field);
|
|
399
|
-
}
|
|
403
|
+
}));
|
|
400
404
|
}
|
|
401
405
|
else if (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib"))) {
|
|
402
406
|
const items = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
|
|
@@ -455,63 +459,9 @@ export default class Inibase {
|
|
|
455
459
|
{ ...data, [field.key]: this.getDefaultValue(field) },
|
|
456
460
|
]));
|
|
457
461
|
}
|
|
458
|
-
}
|
|
462
|
+
}));
|
|
459
463
|
return RETURN;
|
|
460
464
|
}
|
|
461
|
-
FormatObjectCriteriaValue(value, isParentArray = false) {
|
|
462
|
-
switch (value[0]) {
|
|
463
|
-
case ">":
|
|
464
|
-
case "<":
|
|
465
|
-
return value[1] === "="
|
|
466
|
-
? [
|
|
467
|
-
value.slice(0, 2),
|
|
468
|
-
value.slice(2),
|
|
469
|
-
]
|
|
470
|
-
: [
|
|
471
|
-
value.slice(0, 1),
|
|
472
|
-
value.slice(1),
|
|
473
|
-
];
|
|
474
|
-
case "[":
|
|
475
|
-
return value[1] === "]"
|
|
476
|
-
? [
|
|
477
|
-
value.slice(0, 2),
|
|
478
|
-
value.slice(2).toString().split(","),
|
|
479
|
-
]
|
|
480
|
-
: ["[]", value.slice(1)];
|
|
481
|
-
case "!":
|
|
482
|
-
return ["=", "*"].includes(value[1])
|
|
483
|
-
? [
|
|
484
|
-
value.slice(0, 2),
|
|
485
|
-
value.slice(2),
|
|
486
|
-
]
|
|
487
|
-
: value[1] === "["
|
|
488
|
-
? [
|
|
489
|
-
value.slice(0, 3),
|
|
490
|
-
value.slice(3),
|
|
491
|
-
]
|
|
492
|
-
: [
|
|
493
|
-
(value.slice(0, 1) + "="),
|
|
494
|
-
value.slice(1),
|
|
495
|
-
];
|
|
496
|
-
case "=":
|
|
497
|
-
return isParentArray
|
|
498
|
-
? [
|
|
499
|
-
value.slice(0, 1),
|
|
500
|
-
value.slice(1),
|
|
501
|
-
]
|
|
502
|
-
: [
|
|
503
|
-
value.slice(0, 1),
|
|
504
|
-
(value.slice(1) + ","),
|
|
505
|
-
];
|
|
506
|
-
case "*":
|
|
507
|
-
return [
|
|
508
|
-
value.slice(0, 1),
|
|
509
|
-
value.slice(1),
|
|
510
|
-
];
|
|
511
|
-
default:
|
|
512
|
-
return ["=", value];
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
465
|
async applyCriteria(tableName, schema, options, criteria, allTrue) {
|
|
516
466
|
let RETURN = {}, RETURN_LineNumbers = null;
|
|
517
467
|
if (!criteria)
|
|
@@ -547,7 +497,7 @@ export default class Inibase {
|
|
|
547
497
|
Array.isArray(value?.or)) {
|
|
548
498
|
const searchCriteria = (value?.or)
|
|
549
499
|
.map((single_or) => typeof single_or === "string"
|
|
550
|
-
?
|
|
500
|
+
? Utils.FormatObjectCriteriaValue(single_or)
|
|
551
501
|
: ["=", single_or])
|
|
552
502
|
.filter((a) => a);
|
|
553
503
|
if (searchCriteria.length > 0) {
|
|
@@ -561,7 +511,7 @@ export default class Inibase {
|
|
|
561
511
|
Array.isArray(value?.and)) {
|
|
562
512
|
const searchCriteria = (value?.and)
|
|
563
513
|
.map((single_and) => typeof single_and === "string"
|
|
564
|
-
?
|
|
514
|
+
? Utils.FormatObjectCriteriaValue(single_and)
|
|
565
515
|
: ["=", single_and])
|
|
566
516
|
.filter((a) => a);
|
|
567
517
|
if (searchCriteria.length > 0) {
|
|
@@ -575,7 +525,7 @@ export default class Inibase {
|
|
|
575
525
|
else if (Array.isArray(value)) {
|
|
576
526
|
const searchCriteria = value
|
|
577
527
|
.map((single) => typeof single === "string"
|
|
578
|
-
?
|
|
528
|
+
? Utils.FormatObjectCriteriaValue(single)
|
|
579
529
|
: ["=", single])
|
|
580
530
|
.filter((a) => a);
|
|
581
531
|
if (searchCriteria.length > 0) {
|
|
@@ -585,7 +535,7 @@ export default class Inibase {
|
|
|
585
535
|
}
|
|
586
536
|
}
|
|
587
537
|
else if (typeof value === "string") {
|
|
588
|
-
const ComparisonOperatorValue =
|
|
538
|
+
const ComparisonOperatorValue = Utils.FormatObjectCriteriaValue(value);
|
|
589
539
|
if (ComparisonOperatorValue) {
|
|
590
540
|
searchOperator = ComparisonOperatorValue[0];
|
|
591
541
|
searchComparedAtValue = ComparisonOperatorValue[1];
|
|
@@ -769,6 +719,17 @@ export default class Inibase {
|
|
|
769
719
|
if (!schema)
|
|
770
720
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
771
721
|
const idFilePath = join(this.folder, this.database, tableName, "id.inib"), cashFolderPath = join(this.folder, this.database, tableName, ".tmp");
|
|
722
|
+
let testFileHandle;
|
|
723
|
+
try {
|
|
724
|
+
testFileHandle = await open(join(cashFolderPath, "id.inib"), "wx");
|
|
725
|
+
}
|
|
726
|
+
catch ({ message }) {
|
|
727
|
+
if (message.split(":")[0] === "EEXIST")
|
|
728
|
+
return await new Promise((resolve, reject) => setTimeout(() => resolve(this.post(tableName, data, options, returnPostedData)), 13));
|
|
729
|
+
}
|
|
730
|
+
finally {
|
|
731
|
+
await testFileHandle?.close();
|
|
732
|
+
}
|
|
772
733
|
let lastId = 0, totalItems = 0, lastIdObj;
|
|
773
734
|
if (await File.isExists(idFilePath)) {
|
|
774
735
|
if (await File.isExists(join(cashFolderPath, "lastId.inib"))) {
|
|
@@ -800,11 +761,8 @@ export default class Inibase {
|
|
|
800
761
|
throw this.throwError("NO_DATA");
|
|
801
762
|
RETURN = this.formatData(RETURN, schema);
|
|
802
763
|
const pathesContents = this.joinPathesContents(join(this.folder, this.database, tableName), Array.isArray(RETURN) ? RETURN.toReversed() : RETURN);
|
|
803
|
-
const renameList = [];
|
|
804
|
-
|
|
805
|
-
renameList.push(await File.append(path, content));
|
|
806
|
-
for await (const [tempPath, filePath] of renameList)
|
|
807
|
-
await rename(tempPath, filePath);
|
|
764
|
+
const renameList = await Promise.all(Object.entries(pathesContents).map(async ([path, content]) => File.append(path, content)));
|
|
765
|
+
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
808
766
|
await File.write(join(cashFolderPath, "lastId.inib"), lastId.toString(), true);
|
|
809
767
|
await File.write(join(cashFolderPath, "totalItems.inib"), String(totalItems + (Array.isArray(RETURN) ? RETURN.length : 1)), true);
|
|
810
768
|
if (returnPostedData)
|
|
@@ -847,13 +805,23 @@ export default class Inibase {
|
|
|
847
805
|
...(({ id, ...restOfData }) => restOfData)(data),
|
|
848
806
|
updatedAt: Date.now(),
|
|
849
807
|
});
|
|
850
|
-
|
|
851
|
-
|
|
808
|
+
let testFileHandle;
|
|
809
|
+
try {
|
|
810
|
+
testFileHandle = await open(Object.keys(pathesContents)[0].replace(/([^/]+)\/?$/, `.tmp/$1`), "wx");
|
|
811
|
+
}
|
|
812
|
+
catch ({ message }) {
|
|
813
|
+
if (message.split(":")[0] === "EEXIST")
|
|
814
|
+
return await new Promise((resolve, reject) => setTimeout(() => resolve(this.put(tableName, data, where, options)), 13));
|
|
815
|
+
}
|
|
816
|
+
finally {
|
|
817
|
+
await testFileHandle?.close();
|
|
818
|
+
}
|
|
819
|
+
const renameList = await Promise.all(Object.entries(pathesContents).map(async ([path, content]) => File.replace(path, content)));
|
|
820
|
+
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
852
821
|
if (Config.isCacheEnabled) {
|
|
853
822
|
const cacheFiles = (await readdir(join(this.folder, this.database, tableName, ".tmp")))?.filter((fileName) => !["lastId.inib", "totalItems.inib"].includes(fileName));
|
|
854
823
|
if (cacheFiles.length)
|
|
855
|
-
|
|
856
|
-
await unlink(join(this.folder, this.database, tableName, ".tmp", file));
|
|
824
|
+
await Promise.all(cacheFiles.map(async (file) => unlink(join(this.folder, this.database, tableName, ".tmp", file))));
|
|
857
825
|
}
|
|
858
826
|
if (returnPostedData)
|
|
859
827
|
return this.get(tableName, where, options, undefined, undefined, schema);
|
|
@@ -883,16 +851,23 @@ export default class Inibase {
|
|
|
883
851
|
[lineNum]: Array.isArray(content) ? content[index] : content,
|
|
884
852
|
}), {}),
|
|
885
853
|
]));
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
854
|
+
let testFileHandle;
|
|
855
|
+
try {
|
|
856
|
+
testFileHandle = await open(Object.keys(pathesContents)[0].replace(/([^/]+)\/?$/, `.tmp/$1`), "wx");
|
|
857
|
+
}
|
|
858
|
+
catch ({ message }) {
|
|
859
|
+
if (message.split(":")[0] === "EEXIST")
|
|
860
|
+
return await new Promise((resolve, reject) => setTimeout(() => resolve(this.put(tableName, data, where, options)), 13));
|
|
861
|
+
}
|
|
862
|
+
finally {
|
|
863
|
+
await testFileHandle?.close();
|
|
864
|
+
}
|
|
865
|
+
const renameList = await Promise.all(Object.entries(pathesContents).map(async ([path, content]) => File.replace(path, content)));
|
|
866
|
+
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
891
867
|
if (Config.isCacheEnabled) {
|
|
892
868
|
const cacheFiles = (await readdir(join(this.folder, this.database, tableName, ".tmp")))?.filter((fileName) => !["lastId.inib", "totalItems.inib"].includes(fileName));
|
|
893
869
|
if (cacheFiles.length)
|
|
894
|
-
|
|
895
|
-
await unlink(join(this.folder, this.database, tableName, ".tmp", file));
|
|
870
|
+
await Promise.all(cacheFiles.map(async (file) => unlink(join(this.folder, this.database, tableName, ".tmp", file))));
|
|
896
871
|
}
|
|
897
872
|
if (returnPostedData)
|
|
898
873
|
return this.get(tableName, where, options, !Array.isArray(where), undefined, schema);
|
|
@@ -917,13 +892,11 @@ export default class Inibase {
|
|
|
917
892
|
if (!where) {
|
|
918
893
|
const files = (await readdir(join(this.folder, this.database, tableName)))?.filter((fileName) => fileName.endsWith(".inib"));
|
|
919
894
|
if (files.length)
|
|
920
|
-
|
|
921
|
-
await unlink(join(this.folder, this.database, tableName, file));
|
|
895
|
+
await Promise.all(files.map(async (file) => unlink(join(this.folder, this.database, tableName, file))));
|
|
922
896
|
if (Config.isCacheEnabled) {
|
|
923
897
|
const cacheFiles = (await readdir(join(this.folder, this.database, tableName, ".tmp")))?.filter((fileName) => !["lastId.inib", "totalItems.inib"].includes(fileName));
|
|
924
898
|
if (cacheFiles.length)
|
|
925
|
-
|
|
926
|
-
await unlink(join(this.folder, this.database, tableName, ".tmp", file));
|
|
899
|
+
await Promise.all(cacheFiles.map(async (file) => unlink(join(this.folder, this.database, tableName, ".tmp", file))));
|
|
927
900
|
}
|
|
928
901
|
return "*";
|
|
929
902
|
}
|
|
@@ -947,16 +920,23 @@ export default class Inibase {
|
|
|
947
920
|
_id = Object.entries((await File.get(join(this.folder, this.database, tableName, "id.inib"), where, "number", undefined, this.salt)) ?? {}).map(([_key, id]) => UtilsServer.encodeID(Number(id), this.salt));
|
|
948
921
|
if (!_id.length)
|
|
949
922
|
throw this.throwError("NO_ITEMS", tableName);
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
923
|
+
let testFileHandle;
|
|
924
|
+
try {
|
|
925
|
+
testFileHandle = await open(join(this.folder, this.database, tableName, ".tmp", "id.inib"), "wx");
|
|
926
|
+
}
|
|
927
|
+
catch ({ message }) {
|
|
928
|
+
if (message.split(":")[0] === "EEXIST")
|
|
929
|
+
return await new Promise((resolve, reject) => setTimeout(() => resolve(this.delete(tableName, where, _id)), 13));
|
|
930
|
+
}
|
|
931
|
+
finally {
|
|
932
|
+
await testFileHandle?.close();
|
|
933
|
+
}
|
|
934
|
+
const renameList = await Promise.all(files.map(async (file) => File.remove(join(this.folder, this.database, tableName, file), where)));
|
|
935
|
+
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
955
936
|
if (Config.isCacheEnabled) {
|
|
956
937
|
const cacheFiles = (await readdir(join(this.folder, this.database, tableName, ".tmp")))?.filter((fileName) => !["lastId.inib", "totalItems.inib"].includes(fileName));
|
|
957
938
|
if (cacheFiles.length)
|
|
958
|
-
|
|
959
|
-
await unlink(join(this.folder, this.database, tableName, ".tmp", file));
|
|
939
|
+
await Promise.all(cacheFiles.map(async (file) => unlink(join(this.folder, this.database, tableName, ".tmp", file))));
|
|
960
940
|
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")))
|
|
961
941
|
? Number(await File.read(join(this.folder, this.database, tableName, ".tmp", "totalItems.inib"), true))
|
|
962
942
|
: await File.count(join(this.folder, this.database, tableName, "id.inib"))) - (Array.isArray(where) ? where.length : 1)), true);
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type FieldType } from "./index.js";
|
|
1
|
+
import { type FieldType, ComparisonOperator } from "./index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Type guard function to check if the input is an array of objects.
|
|
4
4
|
*
|
|
@@ -174,6 +174,10 @@ export declare const validateFieldType: (value: any, fieldType: FieldType | Fiel
|
|
|
174
174
|
* @returns A flattened object using dot notation for keys.
|
|
175
175
|
*/
|
|
176
176
|
export declare const objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
|
|
177
|
+
export declare function FormatObjectCriteriaValue(value: string, isParentArray?: boolean): [
|
|
178
|
+
ComparisonOperator,
|
|
179
|
+
string | number | boolean | null | (string | number | null)[]
|
|
180
|
+
];
|
|
177
181
|
export default class Utils {
|
|
178
182
|
static isNumber: (input: any) => input is number;
|
|
179
183
|
static isObject: (obj: any) => obj is Record<any, any>;
|
|
@@ -195,4 +199,5 @@ export default class Utils {
|
|
|
195
199
|
static validateFieldType: (value: any, fieldType: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[] | undefined) => boolean;
|
|
196
200
|
static objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
|
|
197
201
|
static isArrayOfNulls: (input: any) => input is null[] | null[][];
|
|
202
|
+
static FormatObjectCriteriaValue: typeof FormatObjectCriteriaValue;
|
|
198
203
|
}
|
package/dist/utils.js
CHANGED
|
@@ -363,6 +363,60 @@ export const objectToDotNotation = (input) => {
|
|
|
363
363
|
}
|
|
364
364
|
return result;
|
|
365
365
|
};
|
|
366
|
+
export function FormatObjectCriteriaValue(value, isParentArray = false) {
|
|
367
|
+
switch (value[0]) {
|
|
368
|
+
case ">":
|
|
369
|
+
case "<":
|
|
370
|
+
return value[1] === "="
|
|
371
|
+
? [
|
|
372
|
+
value.slice(0, 2),
|
|
373
|
+
value.slice(2),
|
|
374
|
+
]
|
|
375
|
+
: [
|
|
376
|
+
value.slice(0, 1),
|
|
377
|
+
value.slice(1),
|
|
378
|
+
];
|
|
379
|
+
case "[":
|
|
380
|
+
return value[1] === "]"
|
|
381
|
+
? [
|
|
382
|
+
value.slice(0, 2),
|
|
383
|
+
value.slice(2).toString().split(","),
|
|
384
|
+
]
|
|
385
|
+
: ["[]", value.slice(1)];
|
|
386
|
+
case "!":
|
|
387
|
+
return ["=", "*"].includes(value[1])
|
|
388
|
+
? [
|
|
389
|
+
value.slice(0, 2),
|
|
390
|
+
value.slice(2),
|
|
391
|
+
]
|
|
392
|
+
: value[1] === "["
|
|
393
|
+
? [
|
|
394
|
+
value.slice(0, 3),
|
|
395
|
+
value.slice(3),
|
|
396
|
+
]
|
|
397
|
+
: [
|
|
398
|
+
(value.slice(0, 1) + "="),
|
|
399
|
+
value.slice(1),
|
|
400
|
+
];
|
|
401
|
+
case "=":
|
|
402
|
+
return isParentArray
|
|
403
|
+
? [
|
|
404
|
+
value.slice(0, 1),
|
|
405
|
+
value.slice(1),
|
|
406
|
+
]
|
|
407
|
+
: [
|
|
408
|
+
value.slice(0, 1),
|
|
409
|
+
(value.slice(1) + ","),
|
|
410
|
+
];
|
|
411
|
+
case "*":
|
|
412
|
+
return [
|
|
413
|
+
value.slice(0, 1),
|
|
414
|
+
value.slice(1),
|
|
415
|
+
];
|
|
416
|
+
default:
|
|
417
|
+
return ["=", value];
|
|
418
|
+
}
|
|
419
|
+
}
|
|
366
420
|
export default class Utils {
|
|
367
421
|
static isNumber = isNumber;
|
|
368
422
|
static isObject = isObject;
|
|
@@ -384,4 +438,5 @@ export default class Utils {
|
|
|
384
438
|
static validateFieldType = validateFieldType;
|
|
385
439
|
static objectToDotNotation = objectToDotNotation;
|
|
386
440
|
static isArrayOfNulls = isArrayOfNulls;
|
|
441
|
+
static FormatObjectCriteriaValue = FormatObjectCriteriaValue;
|
|
387
442
|
}
|
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.29",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Karim Amahtil",
|
|
6
6
|
"email": "karim.amahtil@gmail.com"
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./dist/index.js",
|
|
12
12
|
"./file": "./dist/file.js",
|
|
13
|
+
"./config": "./dist/config.js",
|
|
13
14
|
"./utils": "./dist/utils.js",
|
|
14
15
|
"./utils.server": "./dist/utils.server.js"
|
|
15
16
|
},
|
|
@@ -53,13 +54,16 @@
|
|
|
53
54
|
"utils": [
|
|
54
55
|
"./dist/utils.d.ts"
|
|
55
56
|
],
|
|
57
|
+
"config": [
|
|
58
|
+
"./dist/config.d.ts"
|
|
59
|
+
],
|
|
56
60
|
"utils.server": [
|
|
57
61
|
"./dist/utils.server.d.ts"
|
|
58
62
|
]
|
|
59
63
|
}
|
|
60
64
|
},
|
|
61
65
|
"devDependencies": {
|
|
62
|
-
"@types/node": "^20.10.
|
|
66
|
+
"@types/node": "^20.10.6",
|
|
63
67
|
"typescript": "^5.3.3"
|
|
64
68
|
},
|
|
65
69
|
"scripts": {
|