inibase 1.1.21 → 1.1.23
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 +7 -2
- package/dist/file.d.ts +17 -14
- package/dist/file.js +57 -51
- package/dist/index.d.ts +8 -3
- package/dist/index.js +106 -100
- package/dist/utils.d.ts +3 -4
- package/dist/utils.js +35 -34
- package/dist/utils.server.d.ts +10 -14
- package/dist/utils.server.js +25 -38
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10,13 +10,12 @@ import * as Utils from "./utils.js";
|
|
|
10
10
|
import * as UtilsServer from "./utils.server.js";
|
|
11
11
|
// hide ExperimentalWarning glob()
|
|
12
12
|
process.removeAllListeners("warning");
|
|
13
|
+
export const globalConfig = {};
|
|
13
14
|
export default class Inibase {
|
|
14
15
|
pageInfo;
|
|
15
16
|
language;
|
|
16
|
-
salt;
|
|
17
|
-
databasePath;
|
|
18
17
|
fileExtension = ".txt";
|
|
19
|
-
|
|
18
|
+
databasePath;
|
|
20
19
|
uniqueMap;
|
|
21
20
|
totalItems;
|
|
22
21
|
constructor(database, mainFolder = ".", language = "en") {
|
|
@@ -27,11 +26,11 @@ export default class Inibase {
|
|
|
27
26
|
if (existsSync(".env") &&
|
|
28
27
|
readFileSync(".env").includes("INIBASE_SECRET="))
|
|
29
28
|
throw this.createError("NO_ENV");
|
|
30
|
-
|
|
31
|
-
appendFileSync(".env", `\nINIBASE_SECRET=${
|
|
29
|
+
globalConfig.salt = scryptSync(randomBytes(16), randomBytes(16), 32);
|
|
30
|
+
appendFileSync(".env", `\nINIBASE_SECRET=${globalConfig.salt.toString("hex")}\n`);
|
|
32
31
|
}
|
|
33
32
|
else
|
|
34
|
-
|
|
33
|
+
globalConfig.salt = Buffer.from(process.env.INIBASE_SECRET, "hex");
|
|
35
34
|
}
|
|
36
35
|
static errorMessages = {
|
|
37
36
|
en: {
|
|
@@ -112,7 +111,7 @@ export default class Inibase {
|
|
|
112
111
|
return error;
|
|
113
112
|
}
|
|
114
113
|
clear() {
|
|
115
|
-
this.
|
|
114
|
+
globalConfig[this.databasePath] = { tables: new Map() };
|
|
116
115
|
this.totalItems = new Map();
|
|
117
116
|
this.pageInfo = {};
|
|
118
117
|
this.uniqueMap = new Map();
|
|
@@ -120,9 +119,9 @@ export default class Inibase {
|
|
|
120
119
|
getFileExtension(tableName) {
|
|
121
120
|
let mainExtension = this.fileExtension;
|
|
122
121
|
// TODO: ADD ENCRYPTION
|
|
123
|
-
// if(this.
|
|
122
|
+
// if(globalConfig[this.databasePath].tables.get(tableName).config.encryption)
|
|
124
123
|
// mainExtension += ".enc"
|
|
125
|
-
if (this.
|
|
124
|
+
if (globalConfig[this.databasePath].tables.get(tableName).config.compression)
|
|
126
125
|
mainExtension += ".gz";
|
|
127
126
|
return mainExtension;
|
|
128
127
|
}
|
|
@@ -134,9 +133,7 @@ export default class Inibase {
|
|
|
134
133
|
Utils.isArrayOfObjects(field.children))
|
|
135
134
|
Utils.deepMerge(RETURN, this._schemaToIdsPath(tableName, field.children, `${(prefix ?? "") + field.key}.`));
|
|
136
135
|
else if (field.id)
|
|
137
|
-
RETURN[Utils.isValidID(field.id)
|
|
138
|
-
? UtilsServer.decodeID(field.id, this.salt)
|
|
139
|
-
: field.id] = `${(prefix ?? "") + field.key}${this.getFileExtension(tableName)}`;
|
|
136
|
+
RETURN[Utils.isValidID(field.id) ? UtilsServer.decodeID(field.id) : field.id] = `${(prefix ?? "") + field.key}${this.getFileExtension(tableName)}`;
|
|
140
137
|
return RETURN;
|
|
141
138
|
}
|
|
142
139
|
/**
|
|
@@ -170,7 +167,7 @@ export default class Inibase {
|
|
|
170
167
|
}
|
|
171
168
|
if (schema) {
|
|
172
169
|
const lastSchemaID = { value: 0 };
|
|
173
|
-
await writeFile(join(tablePath, "schema.json"), JSON.stringify(UtilsServer.addIdToSchema(schema, lastSchemaID
|
|
170
|
+
await writeFile(join(tablePath, "schema.json"), JSON.stringify(UtilsServer.addIdToSchema(schema, lastSchemaID), null, 2));
|
|
174
171
|
await writeFile(join(tablePath, `${lastSchemaID.value}.schema`), "");
|
|
175
172
|
}
|
|
176
173
|
else
|
|
@@ -206,7 +203,7 @@ export default class Inibase {
|
|
|
206
203
|
};
|
|
207
204
|
if (await File.isExists(join(tablePath, "schema.json"))) {
|
|
208
205
|
// update columns files names based on field id
|
|
209
|
-
schema = UtilsServer.addIdToSchema(schema, lastSchemaID
|
|
206
|
+
schema = UtilsServer.addIdToSchema(schema, lastSchemaID);
|
|
210
207
|
if (table.schema?.length) {
|
|
211
208
|
const replaceOldPathes = Utils.findChangedProperties(this._schemaToIdsPath(tableName, table.schema), this._schemaToIdsPath(tableName, schema));
|
|
212
209
|
if (replaceOldPathes)
|
|
@@ -217,7 +214,7 @@ export default class Inibase {
|
|
|
217
214
|
}
|
|
218
215
|
}
|
|
219
216
|
else
|
|
220
|
-
schema = UtilsServer.addIdToSchema(schema, lastSchemaID
|
|
217
|
+
schema = UtilsServer.addIdToSchema(schema, lastSchemaID);
|
|
221
218
|
await writeFile(join(tablePath, "schema.json"), JSON.stringify(schema, null, 2));
|
|
222
219
|
if (schemaIdFilePath)
|
|
223
220
|
await rename(schemaIdFilePath, join(tablePath, `${lastSchemaID.value}.schema`));
|
|
@@ -291,7 +288,7 @@ export default class Inibase {
|
|
|
291
288
|
await this.replaceStringInFile(schemaPath, `"table": "${tableName}"`, `"table": "${config.name}"`);
|
|
292
289
|
}
|
|
293
290
|
}
|
|
294
|
-
this.
|
|
291
|
+
globalConfig[this.databasePath].tables.delete(tableName);
|
|
295
292
|
}
|
|
296
293
|
/**
|
|
297
294
|
* Get table schema and config
|
|
@@ -303,8 +300,8 @@ export default class Inibase {
|
|
|
303
300
|
const tablePath = join(this.databasePath, tableName);
|
|
304
301
|
if (!(await File.isExists(tablePath)))
|
|
305
302
|
throw this.createError("TABLE_NOT_EXISTS", tableName);
|
|
306
|
-
if (!this.
|
|
307
|
-
this.
|
|
303
|
+
if (!globalConfig[this.databasePath].tables.has(tableName))
|
|
304
|
+
globalConfig[this.databasePath].tables.set(tableName, {
|
|
308
305
|
schema: await this.getTableSchema(tableName, encodeIDs),
|
|
309
306
|
config: {
|
|
310
307
|
compression: await File.isExists(join(tablePath, ".compression.config")),
|
|
@@ -313,7 +310,7 @@ export default class Inibase {
|
|
|
313
310
|
decodeID: await File.isExists(join(tablePath, ".decodeID.config")),
|
|
314
311
|
},
|
|
315
312
|
});
|
|
316
|
-
return this.
|
|
313
|
+
return globalConfig[this.databasePath].tables.get(tableName);
|
|
317
314
|
}
|
|
318
315
|
async getTableSchema(tableName, encodeIDs = true) {
|
|
319
316
|
const tablePath = join(this.databasePath, tableName);
|
|
@@ -345,7 +342,7 @@ export default class Inibase {
|
|
|
345
342
|
];
|
|
346
343
|
if (!encodeIDs)
|
|
347
344
|
return schema;
|
|
348
|
-
return UtilsServer.encodeSchemaID(schema
|
|
345
|
+
return UtilsServer.encodeSchemaID(schema);
|
|
349
346
|
}
|
|
350
347
|
async throwErrorIfTableEmpty(tableName) {
|
|
351
348
|
const table = await this.getTable(tableName, false);
|
|
@@ -370,11 +367,7 @@ export default class Inibase {
|
|
|
370
367
|
throw this.createError("FIELD_REQUIRED", field.key);
|
|
371
368
|
continue;
|
|
372
369
|
}
|
|
373
|
-
if (!Utils.validateFieldType(data[field.key], field
|
|
374
|
-
field.children &&
|
|
375
|
-
!Utils.isArrayOfObjects(field.children)
|
|
376
|
-
? field.children
|
|
377
|
-
: undefined))
|
|
370
|
+
if (!Utils.validateFieldType(data[field.key], field))
|
|
378
371
|
throw this.createError("INVALID_TYPE", [
|
|
379
372
|
field.key,
|
|
380
373
|
(Array.isArray(field.type) ? field.type.join(", ") : field.type) +
|
|
@@ -432,7 +425,7 @@ export default class Inibase {
|
|
|
432
425
|
async validateData(tableName, data, skipRequiredField = false) {
|
|
433
426
|
const clonedData = structuredClone(data);
|
|
434
427
|
// Skip ID and (created|updated)At
|
|
435
|
-
this._validateData(clonedData, this.
|
|
428
|
+
this._validateData(clonedData, globalConfig[this.databasePath].tables.get(tableName).schema.slice(1, -2), skipRequiredField);
|
|
436
429
|
await this.checkUnique(tableName);
|
|
437
430
|
}
|
|
438
431
|
cleanObject(obj) {
|
|
@@ -443,28 +436,30 @@ export default class Inibase {
|
|
|
443
436
|
}, {});
|
|
444
437
|
return Object.keys(cleanedObject).length > 0 ? cleanedObject : null;
|
|
445
438
|
}
|
|
446
|
-
formatField(value,
|
|
439
|
+
formatField(value, field, _formatOnlyAvailiableKeys) {
|
|
447
440
|
if (value === null || value === undefined)
|
|
448
441
|
return value;
|
|
449
|
-
if (Array.isArray(
|
|
450
|
-
|
|
451
|
-
if (Array.isArray(value) && !["array", "json"].includes(
|
|
442
|
+
if (Array.isArray(field.type))
|
|
443
|
+
field.type = Utils.detectFieldType(value, field.type) ?? field.type[0];
|
|
444
|
+
if (Array.isArray(value) && !["array", "json"].includes(field.type))
|
|
452
445
|
value = value[0];
|
|
453
|
-
switch (
|
|
446
|
+
switch (field.type) {
|
|
454
447
|
case "array":
|
|
455
|
-
if (!
|
|
448
|
+
if (!field.children)
|
|
456
449
|
return null;
|
|
457
450
|
if (!Array.isArray(value))
|
|
458
451
|
value = [value];
|
|
459
|
-
if (Utils.isArrayOfObjects(
|
|
460
|
-
return this.formatData(value,
|
|
461
|
-
}
|
|
452
|
+
if (Utils.isArrayOfObjects(field.children))
|
|
453
|
+
return this.formatData(value, field.children, _formatOnlyAvailiableKeys);
|
|
462
454
|
if (!value.length)
|
|
463
455
|
return null;
|
|
464
|
-
return value.map((_value) => this.formatField(_value,
|
|
456
|
+
return value.map((_value) => this.formatField(_value, {
|
|
457
|
+
...field,
|
|
458
|
+
type: field.children,
|
|
459
|
+
}));
|
|
465
460
|
case "object":
|
|
466
|
-
if (Utils.isArrayOfObjects(
|
|
467
|
-
return this.formatData(value,
|
|
461
|
+
if (Utils.isArrayOfObjects(field.children))
|
|
462
|
+
return this.formatData(value, field.children, _formatOnlyAvailiableKeys);
|
|
468
463
|
break;
|
|
469
464
|
case "table":
|
|
470
465
|
if (Utils.isObject(value)) {
|
|
@@ -473,12 +468,12 @@ export default class Inibase {
|
|
|
473
468
|
Utils.isNumber(value.id)))
|
|
474
469
|
return Utils.isNumber(value.id)
|
|
475
470
|
? Number(value.id)
|
|
476
|
-
: UtilsServer.decodeID(value.id
|
|
471
|
+
: UtilsServer.decodeID(value.id);
|
|
477
472
|
}
|
|
478
473
|
else if (Utils.isValidID(value) || Utils.isNumber(value))
|
|
479
474
|
return Utils.isNumber(value)
|
|
480
475
|
? Number(value)
|
|
481
|
-
: UtilsServer.decodeID(value
|
|
476
|
+
: UtilsServer.decodeID(value);
|
|
482
477
|
break;
|
|
483
478
|
case "password":
|
|
484
479
|
return Utils.isPassword(value)
|
|
@@ -493,7 +488,7 @@ export default class Inibase {
|
|
|
493
488
|
case "id":
|
|
494
489
|
return Utils.isNumber(value)
|
|
495
490
|
? value
|
|
496
|
-
: UtilsServer.decodeID(value
|
|
491
|
+
: UtilsServer.decodeID(value);
|
|
497
492
|
case "json": {
|
|
498
493
|
if (typeof value === "string" && Utils.isStringified(value))
|
|
499
494
|
return value;
|
|
@@ -513,7 +508,7 @@ export default class Inibase {
|
|
|
513
508
|
}
|
|
514
509
|
async checkUnique(tableName) {
|
|
515
510
|
const tablePath = join(this.databasePath, tableName);
|
|
516
|
-
const flattenSchema = Utils.flattenSchema(this.
|
|
511
|
+
const flattenSchema = Utils.flattenSchema(globalConfig[this.databasePath].tables.get(tableName).schema);
|
|
517
512
|
function hasDuplicates(setA, setB) {
|
|
518
513
|
for (const value of setA)
|
|
519
514
|
if (setB.has(value))
|
|
@@ -529,7 +524,7 @@ export default class Inibase {
|
|
|
529
524
|
index++;
|
|
530
525
|
const field = flattenSchema.find(({ id }) => id === columnID);
|
|
531
526
|
fieldsKeys.push(field.key);
|
|
532
|
-
const [_, totalLines, lineNumbers] = await File.search(join(tablePath, `${field.key}${this.getFileExtension(tableName)}`), "[]", Array.from(values), undefined, valueObject.exclude, field
|
|
527
|
+
const [_, totalLines, lineNumbers] = await File.search(join(tablePath, `${field.key}${this.getFileExtension(tableName)}`), "[]", Array.from(values), undefined, valueObject.exclude, { ...field, databasePath: this.databasePath }, 1, undefined, false);
|
|
533
528
|
if (totalLines > 0) {
|
|
534
529
|
if (valueObject.columnsValues.size === 1 ||
|
|
535
530
|
(valueObject.columnsValues.size === index &&
|
|
@@ -576,7 +571,7 @@ export default class Inibase {
|
|
|
576
571
|
RETURN[field.key] = this.getDefaultValue(field);
|
|
577
572
|
continue;
|
|
578
573
|
}
|
|
579
|
-
RETURN[field.key] = this.formatField(clonedData[field.key], field
|
|
574
|
+
RETURN[field.key] = this.formatField(clonedData[field.key], field, formatOnlyAvailiableKeys);
|
|
580
575
|
}
|
|
581
576
|
return RETURN;
|
|
582
577
|
}
|
|
@@ -727,9 +722,14 @@ export default class Inibase {
|
|
|
727
722
|
async processSimpleField(tableName, field, linesNumber, RETURN, _options, prefix) {
|
|
728
723
|
const fieldPath = join(this.databasePath, tableName, `${prefix ?? ""}${field.key}${this.getFileExtension(tableName)}`);
|
|
729
724
|
if (await File.isExists(fieldPath)) {
|
|
730
|
-
const items = await File.get(fieldPath, linesNumber,
|
|
731
|
-
|
|
732
|
-
: field.
|
|
725
|
+
const items = await File.get(fieldPath, linesNumber, {
|
|
726
|
+
...field,
|
|
727
|
+
type: field.key === "id" &&
|
|
728
|
+
globalConfig[this.databasePath].tables.get(tableName).config.decodeID
|
|
729
|
+
? "number"
|
|
730
|
+
: field.type,
|
|
731
|
+
databasePath: this.databasePath,
|
|
732
|
+
});
|
|
733
733
|
if (items) {
|
|
734
734
|
for (const [index, item] of Object.entries(items)) {
|
|
735
735
|
if (typeof item === "undefined")
|
|
@@ -875,7 +875,10 @@ export default class Inibase {
|
|
|
875
875
|
(await File.isExists(join(this.databasePath, field.table)))) {
|
|
876
876
|
const fieldPath = join(this.databasePath, tableName, `${prefix ?? ""}${field.key}${this.getFileExtension(tableName)}`);
|
|
877
877
|
if (await File.isExists(fieldPath)) {
|
|
878
|
-
const itemsIDs = await File.get(fieldPath, linesNumber,
|
|
878
|
+
const itemsIDs = (await File.get(fieldPath, linesNumber, {
|
|
879
|
+
...field,
|
|
880
|
+
databasePath: this.databasePath,
|
|
881
|
+
}));
|
|
879
882
|
const isArrayField = this.isArrayField(field.type);
|
|
880
883
|
if (itemsIDs) {
|
|
881
884
|
const searchableIDs = new Map();
|
|
@@ -888,26 +891,29 @@ export default class Inibase {
|
|
|
888
891
|
searchableIDs.set(lineNumber, lineContent);
|
|
889
892
|
}
|
|
890
893
|
if (searchableIDs.size) {
|
|
891
|
-
const items = await this.get(field.table, isArrayField
|
|
892
|
-
? Array.from(
|
|
893
|
-
:
|
|
894
|
+
const items = await this.get(field.table, Array.from(new Set(isArrayField
|
|
895
|
+
? Array.from(searchableIDs.values()).flat()
|
|
896
|
+
: searchableIDs.values())).flat(), {
|
|
894
897
|
...options,
|
|
895
898
|
perPage: Number.POSITIVE_INFINITY,
|
|
896
899
|
columns: options.columns
|
|
897
900
|
?.filter((column) => column.includes(`${field.key}.`))
|
|
898
901
|
.map((column) => column.replace(`${field.key}.`, "")),
|
|
899
902
|
});
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
?
|
|
904
|
-
?
|
|
905
|
-
:
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
903
|
+
for (const [lineNumber, lineContent] of searchableIDs.entries())
|
|
904
|
+
RETURN[lineNumber][field.key] = isArrayField
|
|
905
|
+
? Utils.isArrayOfArrays(lineContent)
|
|
906
|
+
? lineContent.map((item) => items
|
|
907
|
+
? items.filter(({ id }) => item.includes(id))
|
|
908
|
+
: {
|
|
909
|
+
id: item,
|
|
910
|
+
})
|
|
911
|
+
: lineContent.flatMap((item) => items
|
|
912
|
+
? items.find(({ id }) => item === id)
|
|
913
|
+
: { id: item })
|
|
914
|
+
: (items?.find(({ id }) => id === lineContent) ?? {
|
|
915
|
+
id: lineContent,
|
|
916
|
+
});
|
|
911
917
|
}
|
|
912
918
|
}
|
|
913
919
|
}
|
|
@@ -950,7 +956,7 @@ export default class Inibase {
|
|
|
950
956
|
criteria = Utils.toDotNotation(criteria, ["or", "and"]);
|
|
951
957
|
let index = -1;
|
|
952
958
|
for await (const [key, value] of Object.entries(criteria)) {
|
|
953
|
-
const field = Utils.getField(key, this.
|
|
959
|
+
const field = Utils.getField(key, globalConfig[this.databasePath].tables.get(tableName).schema);
|
|
954
960
|
index++;
|
|
955
961
|
let searchOperator = undefined;
|
|
956
962
|
let searchComparedAtValue = undefined;
|
|
@@ -1008,9 +1014,7 @@ export default class Inibase {
|
|
|
1008
1014
|
searchOperator = "=";
|
|
1009
1015
|
searchComparedAtValue = value;
|
|
1010
1016
|
}
|
|
1011
|
-
const [searchResult, totalLines, linesNumbers] = await File.search(join(tablePath, `${key}${this.getFileExtension(tableName)}`), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, allTrue ? searchIn : undefined, field
|
|
1012
|
-
? undefined
|
|
1013
|
-
: this.salt);
|
|
1017
|
+
const [searchResult, totalLines, linesNumbers] = await File.search(join(tablePath, `${key}${this.getFileExtension(tableName)}`), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, allTrue ? searchIn : undefined, { ...field, databasePath: this.databasePath }, options.perPage, (options.page - 1) * options.perPage + 1, true);
|
|
1014
1018
|
if (searchResult) {
|
|
1015
1019
|
const formatedSearchResult = Object.fromEntries(Object.entries(searchResult).map(([id, value]) => {
|
|
1016
1020
|
const nestedObj = {};
|
|
@@ -1128,13 +1132,13 @@ export default class Inibase {
|
|
|
1128
1132
|
.map((column) => [column, true]);
|
|
1129
1133
|
let cacheKey = "";
|
|
1130
1134
|
// Criteria
|
|
1131
|
-
if (this.
|
|
1135
|
+
if (globalConfig[this.databasePath].tables.get(tableName).config.cache)
|
|
1132
1136
|
cacheKey = UtilsServer.hashString(inspect(sortArray, { sorted: true }));
|
|
1133
1137
|
if (where) {
|
|
1134
1138
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
|
|
1135
1139
|
if (!lineNumbers?.length)
|
|
1136
1140
|
return null;
|
|
1137
|
-
const itemsIDs = Object.values((await File.get(join(tablePath, `id${this.getFileExtension(tableName)}`), lineNumbers, "
|
|
1141
|
+
const itemsIDs = Object.values((await File.get(join(tablePath, `id${this.getFileExtension(tableName)}`), lineNumbers, { key: "BLABLA", type: "number" })) ?? {}).map(Number);
|
|
1138
1142
|
awkCommand = `awk '${itemsIDs.map((id) => `$1 == ${id}`).join(" || ")}'`;
|
|
1139
1143
|
}
|
|
1140
1144
|
else
|
|
@@ -1157,9 +1161,7 @@ export default class Inibase {
|
|
|
1157
1161
|
.map(([key, ascending], i) => {
|
|
1158
1162
|
const field = Utils.getField(key, schema);
|
|
1159
1163
|
if (field)
|
|
1160
|
-
return `-k${i + index},${i + index}${Utils.isFieldType(["id", "number", "date"]
|
|
1161
|
-
? "n"
|
|
1162
|
-
: ""}${!ascending ? "r" : ""}`;
|
|
1164
|
+
return `-k${i + index},${i + index}${Utils.isFieldType(field, ["id", "number", "date"]) ? "n" : ""}${!ascending ? "r" : ""}`;
|
|
1163
1165
|
return "";
|
|
1164
1166
|
})
|
|
1165
1167
|
.join(" ");
|
|
@@ -1168,7 +1170,7 @@ export default class Inibase {
|
|
|
1168
1170
|
if (cacheKey)
|
|
1169
1171
|
await File.lock(join(tablePath, ".tmp"), cacheKey);
|
|
1170
1172
|
// Combine && Execute the commands synchronously
|
|
1171
|
-
let lines = (await UtilsServer.exec(this.
|
|
1173
|
+
let lines = (await UtilsServer.exec(globalConfig[this.databasePath].tables.get(tableName).config.cache
|
|
1172
1174
|
? (await File.isExists(join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)))
|
|
1173
1175
|
? `${awkCommand} '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}'`
|
|
1174
1176
|
: `${pasteCommand} | ${sortCommand} -o '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}' && ${awkCommand} '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}'`
|
|
@@ -1192,10 +1194,11 @@ export default class Inibase {
|
|
|
1192
1194
|
const field = Utils.getField(parse(fileName).name, schema);
|
|
1193
1195
|
if (field) {
|
|
1194
1196
|
if (field.key === "id" &&
|
|
1195
|
-
this.
|
|
1197
|
+
globalConfig[this.databasePath].tables.get(tableName).config
|
|
1198
|
+
.decodeID)
|
|
1196
1199
|
outputObject[field.key] = splitedFileColumns[index];
|
|
1197
1200
|
else
|
|
1198
|
-
outputObject[field.key] = File.decode(splitedFileColumns[index],
|
|
1201
|
+
outputObject[field.key] = File.decode(splitedFileColumns[index], { ...field, databasePath: this.databasePath });
|
|
1199
1202
|
}
|
|
1200
1203
|
});
|
|
1201
1204
|
return outputObject;
|
|
@@ -1223,7 +1226,8 @@ export default class Inibase {
|
|
|
1223
1226
|
}
|
|
1224
1227
|
else if (((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1225
1228
|
Utils.isNumber(where)) &&
|
|
1226
|
-
(_whereIsLinesNumbers ||
|
|
1229
|
+
(_whereIsLinesNumbers ||
|
|
1230
|
+
!globalConfig[this.databasePath].tables.get(tableName).config.decodeID)) {
|
|
1227
1231
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1228
1232
|
let lineNumbers = where;
|
|
1229
1233
|
if (!Array.isArray(lineNumbers))
|
|
@@ -1238,7 +1242,7 @@ export default class Inibase {
|
|
|
1238
1242
|
RETURN = RETURN[0];
|
|
1239
1243
|
}
|
|
1240
1244
|
else if ((!_whereIsLinesNumbers &&
|
|
1241
|
-
this.
|
|
1245
|
+
globalConfig[this.databasePath].tables.get(tableName).config.decodeID &&
|
|
1242
1246
|
((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1243
1247
|
Utils.isNumber(where))) ||
|
|
1244
1248
|
(Array.isArray(where) && where.every(Utils.isValidID)) ||
|
|
@@ -1246,7 +1250,7 @@ export default class Inibase {
|
|
|
1246
1250
|
let Ids = where;
|
|
1247
1251
|
if (!Array.isArray(Ids))
|
|
1248
1252
|
Ids = [Ids];
|
|
1249
|
-
const [lineNumbers, countItems] = await File.search(join(tablePath, `id${this.getFileExtension(tableName)}`), "[]", Ids.map((id) => Utils.isNumber(id) ? Number(id) : UtilsServer.decodeID(id
|
|
1253
|
+
const [lineNumbers, countItems] = await File.search(join(tablePath, `id${this.getFileExtension(tableName)}`), "[]", Ids.map((id) => Utils.isNumber(id) ? Number(id) : UtilsServer.decodeID(id)), undefined, undefined, { key: "BLABLA", type: "number" }, Ids.length, 0, !this.totalItems.has(`${tableName}-*`));
|
|
1250
1254
|
if (!lineNumbers)
|
|
1251
1255
|
return null;
|
|
1252
1256
|
if (!this.totalItems.has(`${tableName}-*`))
|
|
@@ -1267,7 +1271,7 @@ export default class Inibase {
|
|
|
1267
1271
|
else if (Utils.isObject(where)) {
|
|
1268
1272
|
let cachedFilePath = "";
|
|
1269
1273
|
// Criteria
|
|
1270
|
-
if (this.
|
|
1274
|
+
if (globalConfig[this.databasePath].tables.get(tableName).config.cache) {
|
|
1271
1275
|
cachedFilePath = join(tablePath, ".cache", `${UtilsServer.hashString(inspect(where, { sorted: true }))}${this.fileExtension}`);
|
|
1272
1276
|
if (await File.isExists(cachedFilePath)) {
|
|
1273
1277
|
const cachedItems = (await readFile(cachedFilePath, "utf8")).split(",");
|
|
@@ -1292,9 +1296,9 @@ export default class Inibase {
|
|
|
1292
1296
|
const alreadyExistsColumnsIDs = Utils.flattenSchema(schema)
|
|
1293
1297
|
.filter(({ key }) => alreadyExistsColumns.includes(key))
|
|
1294
1298
|
.map(({ id }) => id);
|
|
1295
|
-
RETURN = Object.values(Utils.deepMerge(LineNumberDataMap, await this.processSchemaData(tableName, Utils.filterSchema(schema, (
|
|
1296
|
-
Utils.isFieldType("table"
|
|
1297
|
-
if (this.
|
|
1299
|
+
RETURN = Object.values(Utils.deepMerge(LineNumberDataMap, await this.processSchemaData(tableName, Utils.filterSchema(schema, (field) => !alreadyExistsColumnsIDs.includes(field.id) ||
|
|
1300
|
+
Utils.isFieldType(field, "table")), Object.keys(LineNumberDataMap).map(Number), options)));
|
|
1301
|
+
if (globalConfig[this.databasePath].tables.get(tableName).config.cache)
|
|
1298
1302
|
await writeFile(cachedFilePath, Array.from(linesNumbers).join(","));
|
|
1299
1303
|
}
|
|
1300
1304
|
}
|
|
@@ -1323,7 +1327,7 @@ export default class Inibase {
|
|
|
1323
1327
|
};
|
|
1324
1328
|
const tablePath = join(this.databasePath, tableName);
|
|
1325
1329
|
await this.getTable(tableName);
|
|
1326
|
-
if (!this.
|
|
1330
|
+
if (!globalConfig[this.databasePath].tables.get(tableName).schema)
|
|
1327
1331
|
throw this.createError("NO_SCHEMA", tableName);
|
|
1328
1332
|
if (!returnPostedData)
|
|
1329
1333
|
returnPostedData = false;
|
|
@@ -1352,25 +1356,25 @@ export default class Inibase {
|
|
|
1352
1356
|
clonedData.createdAt = Date.now();
|
|
1353
1357
|
clonedData.updatedAt = undefined;
|
|
1354
1358
|
}
|
|
1355
|
-
clonedData = this.formatData(clonedData, this.
|
|
1356
|
-
const pathesContents = this.joinPathesContents(tableName, this.
|
|
1359
|
+
clonedData = this.formatData(clonedData, globalConfig[this.databasePath].tables.get(tableName).schema, false);
|
|
1360
|
+
const pathesContents = this.joinPathesContents(tableName, globalConfig[this.databasePath].tables.get(tableName).config.prepend
|
|
1357
1361
|
? Array.isArray(clonedData)
|
|
1358
1362
|
? clonedData.toReversed()
|
|
1359
1363
|
: clonedData
|
|
1360
1364
|
: clonedData);
|
|
1361
|
-
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(this.
|
|
1365
|
+
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(globalConfig[this.databasePath].tables.get(tableName).config.prepend
|
|
1362
1366
|
? await File.prepend(path, content)
|
|
1363
1367
|
: await File.append(path, content))));
|
|
1364
1368
|
await Promise.allSettled(renameList
|
|
1365
1369
|
.filter(([_, filePath]) => filePath)
|
|
1366
1370
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1367
|
-
if (this.
|
|
1371
|
+
if (globalConfig[this.databasePath].tables.get(tableName).config.cache)
|
|
1368
1372
|
await this.clearCache(tableName);
|
|
1369
1373
|
const currentValue = this.totalItems.get(`${tableName}-*`) || 0;
|
|
1370
1374
|
this.totalItems.set(`${tableName}-*`, currentValue + (Array.isArray(data) ? data.length : 1));
|
|
1371
1375
|
await rename(paginationFilePath, join(tablePath, `${lastId}-${this.totalItems.get(`${tableName}-*`)}.pagination`));
|
|
1372
1376
|
if (returnPostedData)
|
|
1373
|
-
return this.get(tableName, this.
|
|
1377
|
+
return this.get(tableName, globalConfig[this.databasePath].tables.get(tableName).config.prepend
|
|
1374
1378
|
? Array.isArray(clonedData)
|
|
1375
1379
|
? clonedData.map((_, index) => index + 1).toReversed()
|
|
1376
1380
|
: 1
|
|
@@ -1381,10 +1385,10 @@ export default class Inibase {
|
|
|
1381
1385
|
: this.totalItems.get(`${tableName}-*`), options, !Utils.isArrayOfObjects(clonedData), // return only one item if data is not array of objects
|
|
1382
1386
|
undefined, true);
|
|
1383
1387
|
return Array.isArray(clonedData)
|
|
1384
|
-
? (this.
|
|
1388
|
+
? (globalConfig[this.databasePath].tables.get(tableName).config.prepend
|
|
1385
1389
|
? clonedData.toReversed()
|
|
1386
|
-
: clonedData).map(({ id }) => UtilsServer.encodeID(id
|
|
1387
|
-
: UtilsServer.encodeID(clonedData.id
|
|
1390
|
+
: clonedData).map(({ id }) => UtilsServer.encodeID(id))
|
|
1391
|
+
: UtilsServer.encodeID(clonedData.id);
|
|
1388
1392
|
}
|
|
1389
1393
|
finally {
|
|
1390
1394
|
if (renameList.length)
|
|
@@ -1412,7 +1416,7 @@ export default class Inibase {
|
|
|
1412
1416
|
return this.put(tableName, clonedData, clonedData.id, options, returnUpdatedData);
|
|
1413
1417
|
}
|
|
1414
1418
|
await this.validateData(tableName, clonedData, true);
|
|
1415
|
-
clonedData = this.formatData(clonedData, this.
|
|
1419
|
+
clonedData = this.formatData(clonedData, globalConfig[this.databasePath].tables.get(tableName).schema, true);
|
|
1416
1420
|
const pathesContents = this.joinPathesContents(tableName, {
|
|
1417
1421
|
...(({ id, ...restOfData }) => restOfData)(clonedData),
|
|
1418
1422
|
updatedAt: Date.now(),
|
|
@@ -1427,7 +1431,7 @@ export default class Inibase {
|
|
|
1427
1431
|
await Promise.allSettled(renameList
|
|
1428
1432
|
.filter(([_, filePath]) => filePath)
|
|
1429
1433
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1430
|
-
if (this.
|
|
1434
|
+
if (globalConfig[this.databasePath].tables.get(tableName).config.cache)
|
|
1431
1435
|
await this.clearCache(join(tablePath, ".cache"));
|
|
1432
1436
|
if (returnUpdatedData)
|
|
1433
1437
|
return await this.get(tableName, undefined, options);
|
|
@@ -1440,10 +1444,11 @@ export default class Inibase {
|
|
|
1440
1444
|
}
|
|
1441
1445
|
else if (((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1442
1446
|
Utils.isNumber(where)) &&
|
|
1443
|
-
(_whereIsLinesNumbers ||
|
|
1447
|
+
(_whereIsLinesNumbers ||
|
|
1448
|
+
!globalConfig[this.databasePath].tables.get(tableName).config.decodeID)) {
|
|
1444
1449
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1445
1450
|
await this.validateData(tableName, clonedData, true);
|
|
1446
|
-
clonedData = this.formatData(clonedData, this.
|
|
1451
|
+
clonedData = this.formatData(clonedData, globalConfig[this.databasePath].tables.get(tableName).schema, true);
|
|
1447
1452
|
const pathesContents = Object.fromEntries(Object.entries(this.joinPathesContents(tableName, Array.isArray(clonedData)
|
|
1448
1453
|
? clonedData.map((item) => ({
|
|
1449
1454
|
...item,
|
|
@@ -1465,7 +1470,7 @@ export default class Inibase {
|
|
|
1465
1470
|
await Promise.allSettled(renameList
|
|
1466
1471
|
.filter(([_, filePath]) => filePath)
|
|
1467
1472
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1468
|
-
if (this.
|
|
1473
|
+
if (globalConfig[this.databasePath].tables.get(tableName).config.cache)
|
|
1469
1474
|
await this.clearCache(tableName);
|
|
1470
1475
|
if (returnUpdatedData)
|
|
1471
1476
|
return this.get(tableName, where, options, !Array.isArray(where), undefined, true);
|
|
@@ -1477,7 +1482,7 @@ export default class Inibase {
|
|
|
1477
1482
|
}
|
|
1478
1483
|
}
|
|
1479
1484
|
else if ((!_whereIsLinesNumbers &&
|
|
1480
|
-
this.
|
|
1485
|
+
globalConfig[this.databasePath].tables.get(tableName).config.decodeID &&
|
|
1481
1486
|
((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1482
1487
|
Utils.isNumber(where))) ||
|
|
1483
1488
|
(Array.isArray(where) && where.every(Utils.isValidID)) ||
|
|
@@ -1520,7 +1525,7 @@ export default class Inibase {
|
|
|
1520
1525
|
await Promise.all((await readdir(tablePath))
|
|
1521
1526
|
?.filter((fileName) => fileName.endsWith(this.getFileExtension(tableName)))
|
|
1522
1527
|
.map(async (file) => unlink(join(tablePath, file))));
|
|
1523
|
-
if (this.
|
|
1528
|
+
if (globalConfig[this.databasePath].tables.get(tableName).config.cache)
|
|
1524
1529
|
await this.clearCache(tableName);
|
|
1525
1530
|
await rename(paginationFilePath, join(tablePath, `${pagination[0]}-0.pagination`));
|
|
1526
1531
|
return true;
|
|
@@ -1531,7 +1536,8 @@ export default class Inibase {
|
|
|
1531
1536
|
}
|
|
1532
1537
|
if (((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1533
1538
|
Utils.isNumber(where)) &&
|
|
1534
|
-
(_whereIsLinesNumbers ||
|
|
1539
|
+
(_whereIsLinesNumbers ||
|
|
1540
|
+
!globalConfig[this.databasePath].tables.get(tableName).config.decodeID)) {
|
|
1535
1541
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1536
1542
|
const files = (await readdir(tablePath))?.filter((fileName) => fileName.endsWith(this.getFileExtension(tableName)));
|
|
1537
1543
|
if (files.length) {
|
|
@@ -1559,7 +1565,7 @@ export default class Inibase {
|
|
|
1559
1565
|
await Promise.all((await readdir(tablePath))
|
|
1560
1566
|
?.filter((fileName) => fileName.endsWith(this.getFileExtension(tableName)))
|
|
1561
1567
|
.map(async (file) => unlink(join(tablePath, file))));
|
|
1562
|
-
if (this.
|
|
1568
|
+
if (globalConfig[this.databasePath].tables.get(tableName).config.cache)
|
|
1563
1569
|
await this.clearCache(tableName);
|
|
1564
1570
|
await rename(paginationFilePath, join(tablePath, `${pagination[0]}-${pagination[1] - (Array.isArray(where) ? where.length : 1)}.pagination`));
|
|
1565
1571
|
return true;
|
|
@@ -1572,7 +1578,7 @@ export default class Inibase {
|
|
|
1572
1578
|
}
|
|
1573
1579
|
}
|
|
1574
1580
|
if ((!_whereIsLinesNumbers &&
|
|
1575
|
-
this.
|
|
1581
|
+
globalConfig[this.databasePath].tables.get(tableName).config.decodeID &&
|
|
1576
1582
|
((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1577
1583
|
Utils.isNumber(where))) ||
|
|
1578
1584
|
(Array.isArray(where) && where.every(Utils.isValidID)) ||
|
package/dist/utils.d.ts
CHANGED
|
@@ -156,18 +156,17 @@ export declare const findChangedProperties: (obj1: Record<string, string>, obj2:
|
|
|
156
156
|
* @returns The detected field type as a string, or undefined if no matching type is found.
|
|
157
157
|
*/
|
|
158
158
|
export declare const detectFieldType: (input: any, availableTypes: FieldType[]) => FieldType | undefined;
|
|
159
|
-
export declare const isFieldType: (compareAtType: string | string[]
|
|
159
|
+
export declare const isFieldType: (field: Field, compareAtType: string | string[]) => boolean;
|
|
160
160
|
export declare const flattenSchema: (schema: Schema, keepParents?: boolean) => Schema;
|
|
161
161
|
export declare const filterSchema: (schema: Schema, callback: (arg0: Field) => boolean) => Field[];
|
|
162
162
|
/**
|
|
163
163
|
* Validates if the given value matches the specified field type(s).
|
|
164
164
|
*
|
|
165
165
|
* @param value - The value to be validated.
|
|
166
|
-
* @param
|
|
167
|
-
* @param fieldChildrenType - Optional; the expected type(s) of children elements, used if the field type is an array.
|
|
166
|
+
* @param field - Field object config.
|
|
168
167
|
* @returns A boolean indicating whether the value matches the specified field type(s).
|
|
169
168
|
*/
|
|
170
|
-
export declare const validateFieldType: (value: any,
|
|
169
|
+
export declare const validateFieldType: (value: any, field: Field) => boolean;
|
|
171
170
|
export declare const FormatObjectCriteriaValue: (value: string) => [ComparisonOperator, string | number | boolean | null | (string | number | null)[]];
|
|
172
171
|
/**
|
|
173
172
|
* Get field from schema
|