inibase 1.5.7 → 1.5.8
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.js +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +105 -84
- package/package.json +1 -1
package/dist/file.js
CHANGED
|
@@ -227,7 +227,7 @@ export async function get(filePath, lineNumbers, field, readWholeFile = false) {
|
|
|
227
227
|
else if (lineNumbers === -1) {
|
|
228
228
|
const escapedFilePath = escapeShellPath(filePath);
|
|
229
229
|
const command = filePath.endsWith(".gz")
|
|
230
|
-
? `
|
|
230
|
+
? `gunzip -c ${escapedFilePath} | sed -n '$p'`
|
|
231
231
|
: `sed -n '$p' ${escapedFilePath}`;
|
|
232
232
|
const foundedLine = (await exec(command)).stdout.trimEnd();
|
|
233
233
|
if (foundedLine)
|
|
@@ -250,7 +250,7 @@ export async function get(filePath, lineNumbers, field, readWholeFile = false) {
|
|
|
250
250
|
}
|
|
251
251
|
const escapedFilePath = escapeShellPath(filePath);
|
|
252
252
|
const command = filePath.endsWith(".gz")
|
|
253
|
-
? `
|
|
253
|
+
? `gunzip -c ${escapedFilePath} | sed -n '${_groupIntoRanges(lineNumbers)}'`
|
|
254
254
|
: `sed -n '${_groupIntoRanges(lineNumbers)}' ${escapedFilePath}`;
|
|
255
255
|
const foundedLines = (await exec(command)).stdout.trimEnd().split("\n");
|
|
256
256
|
let index = 0;
|
|
@@ -336,7 +336,7 @@ export const replace = async (filePath, replacements, totalItems) => {
|
|
|
336
336
|
const escapedFileTempPath = escapeShellPath(fileTempPath);
|
|
337
337
|
const sedCommand = `sed -e s/.*/${replacements}/ -e /^$/s/^/${replacements}/ ${escapedFilePath}`;
|
|
338
338
|
const command = filePath.endsWith(".gz")
|
|
339
|
-
? `
|
|
339
|
+
? `gunzip -c ${escapedFilePath} | ${sedCommand} | gzip > ${escapedFileTempPath}`
|
|
340
340
|
: `${sedCommand} > ${escapedFileTempPath}`;
|
|
341
341
|
try {
|
|
342
342
|
await exec(command);
|
|
@@ -491,7 +491,7 @@ export const remove = async (filePath, linesToDelete) => {
|
|
|
491
491
|
const escapedFilePath = escapeShellPath(filePath);
|
|
492
492
|
const escapedFileTempPath = escapeShellPath(fileTempPath);
|
|
493
493
|
const command = filePath.endsWith(".gz")
|
|
494
|
-
? `
|
|
494
|
+
? `gunzip -c ${escapedFilePath} | sed '${_groupIntoRanges(linesToDelete, "d")}' | gzip > ${escapedFileTempPath}`
|
|
495
495
|
: `sed '${_groupIntoRanges(linesToDelete, "d")}' ${escapedFilePath} > ${escapedFileTempPath}`;
|
|
496
496
|
await exec(command);
|
|
497
497
|
return [fileTempPath, filePath];
|
package/dist/index.d.ts
CHANGED
|
@@ -104,9 +104,9 @@ export default class Inibase {
|
|
|
104
104
|
* Get table schema and config
|
|
105
105
|
*
|
|
106
106
|
* @param {string} tableName
|
|
107
|
-
* @return {*} {Promise<TableObject>}
|
|
107
|
+
* @return {*} {Promise<TableObject | undefined>}
|
|
108
108
|
*/
|
|
109
|
-
getTable(tableName: string): Promise<TableObject>;
|
|
109
|
+
getTable(tableName: string): Promise<TableObject | undefined>;
|
|
110
110
|
getTableSchema(tableName: string): Promise<Schema>;
|
|
111
111
|
private throwErrorIfTableEmpty;
|
|
112
112
|
validateData(data: Data | Data[], schema: Schema, skipRequiredField?: boolean): void;
|
package/dist/index.js
CHANGED
|
@@ -137,9 +137,9 @@ export default class Inibase {
|
|
|
137
137
|
getFileExtension(tableName) {
|
|
138
138
|
let mainExtension = this.fileExtension;
|
|
139
139
|
// TODO: ADD ENCRYPTION
|
|
140
|
-
// if(globalConfig[this.databasePath].tables
|
|
140
|
+
// if(globalConfig[this.databasePath].tables?.get(tableName)?.config.encryption)
|
|
141
141
|
// mainExtension += ".enc"
|
|
142
|
-
if (globalConfig[this.databasePath].tables
|
|
142
|
+
if (globalConfig[this.databasePath].tables?.get(tableName)?.config.compression)
|
|
143
143
|
mainExtension += ".gz";
|
|
144
144
|
return mainExtension;
|
|
145
145
|
}
|
|
@@ -212,11 +212,13 @@ export default class Inibase {
|
|
|
212
212
|
*/
|
|
213
213
|
async updateTable(tableName, schema, config) {
|
|
214
214
|
const table = await this.getTable(tableName);
|
|
215
|
+
if (!table)
|
|
216
|
+
return;
|
|
215
217
|
const tablePath = join(this.databasePath, tableName);
|
|
216
218
|
if (schema) {
|
|
217
219
|
// remove id from schema
|
|
218
220
|
schema = schema.filter(({ key }) => !["id", "createdAt", "updatedAt"].includes(key));
|
|
219
|
-
let schemaIdFilePath;
|
|
221
|
+
let schemaIdFilePath = "";
|
|
220
222
|
for await (const fileName of glob("*.schema", { cwd: tablePath }))
|
|
221
223
|
schemaIdFilePath = join(tablePath, fileName);
|
|
222
224
|
const lastSchemaID = {
|
|
@@ -293,8 +295,8 @@ export default class Inibase {
|
|
|
293
295
|
"sh",
|
|
294
296
|
"-c",
|
|
295
297
|
`for file; do ${config.compression
|
|
296
|
-
?
|
|
297
|
-
:
|
|
298
|
+
? `zcat "$file" | ${process.platform === "darwin" ? "tail -r" : "tac"} | gzip > "$file.reversed" && mv "$file.reversed" "$file"`
|
|
299
|
+
: `${process.platform === "darwin" ? "tail -r" : "tac"} "$file" > "$file.reversed" && mv "$file.reversed" "$file"`}; done`,
|
|
298
300
|
"_",
|
|
299
301
|
"{}",
|
|
300
302
|
"+",
|
|
@@ -319,22 +321,22 @@ export default class Inibase {
|
|
|
319
321
|
: `table:${config.name}`);
|
|
320
322
|
}
|
|
321
323
|
}
|
|
322
|
-
globalConfig[this.databasePath].tables
|
|
324
|
+
globalConfig[this.databasePath].tables?.delete(tableName);
|
|
323
325
|
}
|
|
324
326
|
/**
|
|
325
327
|
* Get table schema and config
|
|
326
328
|
*
|
|
327
329
|
* @param {string} tableName
|
|
328
|
-
* @return {*} {Promise<TableObject>}
|
|
330
|
+
* @return {*} {Promise<TableObject | undefined>}
|
|
329
331
|
*/
|
|
330
332
|
async getTable(tableName) {
|
|
331
333
|
const tablePath = join(this.databasePath, tableName);
|
|
332
334
|
if (!(await File.isExists(tablePath)))
|
|
333
335
|
throw this.createError("TABLE_NOT_EXISTS", tableName);
|
|
334
|
-
if (!globalConfig[this.databasePath].tables
|
|
335
|
-
globalConfig[this.databasePath].tables
|
|
336
|
+
if (!globalConfig[this.databasePath].tables?.has(tableName) ||
|
|
337
|
+
globalConfig[this.databasePath].tables?.get(tableName)?.timestamp !==
|
|
336
338
|
(await File.getFileDate(join(tablePath, `schema.${this.schemaFileExtension}`))))
|
|
337
|
-
globalConfig[this.databasePath].tables
|
|
339
|
+
globalConfig[this.databasePath].tables?.set(tableName, {
|
|
338
340
|
schema: await this.getTableSchema(tableName),
|
|
339
341
|
config: {
|
|
340
342
|
compression: await File.isExists(join(tablePath, ".compression.config")),
|
|
@@ -344,7 +346,7 @@ export default class Inibase {
|
|
|
344
346
|
},
|
|
345
347
|
timestamp: await File.getFileDate(join(tablePath, `schema.${this.schemaFileExtension}`)),
|
|
346
348
|
});
|
|
347
|
-
return globalConfig[this.databasePath].tables
|
|
349
|
+
return globalConfig[this.databasePath].tables?.get(tableName);
|
|
348
350
|
}
|
|
349
351
|
async getTableSchema(tableName) {
|
|
350
352
|
const tablePath = join(this.databasePath, tableName);
|
|
@@ -382,7 +384,7 @@ export default class Inibase {
|
|
|
382
384
|
type: "id",
|
|
383
385
|
required: true,
|
|
384
386
|
},
|
|
385
|
-
...schema,
|
|
387
|
+
...(schema || []),
|
|
386
388
|
{
|
|
387
389
|
id: -1,
|
|
388
390
|
key: "createdAt",
|
|
@@ -398,7 +400,7 @@ export default class Inibase {
|
|
|
398
400
|
}
|
|
399
401
|
async throwErrorIfTableEmpty(tableName) {
|
|
400
402
|
const table = await this.getTable(tableName);
|
|
401
|
-
if (!table
|
|
403
|
+
if (!table?.schema)
|
|
402
404
|
throw this.createError("NO_SCHEMA", tableName);
|
|
403
405
|
if (!(await File.isExists(join(this.databasePath, tableName, `id${this.getFileExtension(tableName)}`))))
|
|
404
406
|
throw this.createError("TABLE_EMPTY", tableName);
|
|
@@ -448,27 +450,24 @@ export default class Inibase {
|
|
|
448
450
|
!regex.test(String(data[field.key])))
|
|
449
451
|
throw this.createError("INVALID_REGEX_MATCH", [field.key]);
|
|
450
452
|
}
|
|
451
|
-
if (field.unique) {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
uniqueKey = field.id;
|
|
455
|
-
else
|
|
456
|
-
uniqueKey = field.unique;
|
|
453
|
+
if (field.unique && field.id !== undefined) {
|
|
454
|
+
const fieldId = field.id;
|
|
455
|
+
const uniqueKey = typeof field.unique === "boolean" ? fieldId : field.unique;
|
|
457
456
|
if (!this.uniqueMap.has(uniqueKey))
|
|
458
457
|
this.uniqueMap.set(uniqueKey, {
|
|
459
458
|
exclude: new Set(),
|
|
460
459
|
columnsValues: new Map(),
|
|
461
460
|
});
|
|
462
|
-
if (!this.uniqueMap.get(uniqueKey)
|
|
461
|
+
if (!this.uniqueMap.get(uniqueKey)?.columnsValues.has(fieldId))
|
|
463
462
|
this.uniqueMap
|
|
464
|
-
|
|
465
|
-
|
|
463
|
+
?.get(uniqueKey)
|
|
464
|
+
?.columnsValues.set(fieldId, new Set());
|
|
466
465
|
if (data.id)
|
|
467
|
-
this.uniqueMap.get(uniqueKey)
|
|
466
|
+
this.uniqueMap.get(uniqueKey)?.exclude.add(-data.id);
|
|
468
467
|
this.uniqueMap
|
|
469
468
|
.get(uniqueKey)
|
|
470
|
-
|
|
471
|
-
|
|
469
|
+
?.columnsValues.get(fieldId)
|
|
470
|
+
?.add(data[field.key]);
|
|
472
471
|
}
|
|
473
472
|
}
|
|
474
473
|
}
|
|
@@ -477,7 +476,9 @@ export default class Inibase {
|
|
|
477
476
|
async validateTableData(tableName, data, skipRequiredField = false) {
|
|
478
477
|
const clonedData = structuredClone(data);
|
|
479
478
|
// Skip ID and (created|updated)At
|
|
480
|
-
this.validateData(clonedData, globalConfig[this.databasePath].tables
|
|
479
|
+
this.validateData(clonedData, globalConfig[this.databasePath].tables
|
|
480
|
+
?.get(tableName)
|
|
481
|
+
?.schema?.slice(1, -2) ?? [], skipRequiredField);
|
|
481
482
|
await this.checkUnique(tableName);
|
|
482
483
|
}
|
|
483
484
|
cleanObject(obj) {
|
|
@@ -491,6 +492,8 @@ export default class Inibase {
|
|
|
491
492
|
formatField(value, field, _formatOnlyAvailiableKeys) {
|
|
492
493
|
if (value === null || value === undefined || value === "")
|
|
493
494
|
return value;
|
|
495
|
+
if (!field)
|
|
496
|
+
return value;
|
|
494
497
|
let _fieldType = field.type;
|
|
495
498
|
if (Array.isArray(_fieldType))
|
|
496
499
|
_fieldType = Utils.detectFieldType(value, _fieldType) ?? _fieldType[0];
|
|
@@ -561,7 +564,7 @@ export default class Inibase {
|
|
|
561
564
|
}
|
|
562
565
|
async checkUnique(tableName) {
|
|
563
566
|
const tablePath = join(this.databasePath, tableName);
|
|
564
|
-
const flattenSchema = Utils.flattenSchema(globalConfig[this.databasePath].tables
|
|
567
|
+
const flattenSchema = Utils.flattenSchema(globalConfig[this.databasePath].tables?.get(tableName)?.schema ?? []);
|
|
565
568
|
function hasDuplicates(setA, setB) {
|
|
566
569
|
for (const value of setA)
|
|
567
570
|
if (setB.has(value))
|
|
@@ -576,12 +579,14 @@ export default class Inibase {
|
|
|
576
579
|
for await (const [columnID, values] of valueObject.columnsValues) {
|
|
577
580
|
index++;
|
|
578
581
|
const field = flattenSchema.find(({ id }) => id === columnID);
|
|
582
|
+
if (!field)
|
|
583
|
+
continue;
|
|
579
584
|
fieldsKeys.push(field.key);
|
|
580
585
|
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);
|
|
581
586
|
if (totalLines > 0) {
|
|
582
587
|
if (valueObject.columnsValues.size === 1 ||
|
|
583
588
|
(valueObject.columnsValues.size === index &&
|
|
584
|
-
hasDuplicates(lineNumbers, mergedLineNumbers))) {
|
|
589
|
+
!!(lineNumbers && hasDuplicates(lineNumbers, mergedLineNumbers)))) {
|
|
585
590
|
this.uniqueMap = new Map();
|
|
586
591
|
if (valueObject.columnsValues.size > 1)
|
|
587
592
|
throw this.createError("GROUP_UNIQUE", [
|
|
@@ -593,7 +598,7 @@ export default class Inibase {
|
|
|
593
598
|
Array.from(values).join(", "),
|
|
594
599
|
]);
|
|
595
600
|
}
|
|
596
|
-
lineNumbers
|
|
601
|
+
lineNumbers?.forEach(mergedLineNumbers.add, mergedLineNumbers);
|
|
597
602
|
}
|
|
598
603
|
else {
|
|
599
604
|
shouldContinueParent = true; // Flag to skip the rest of this inner loop
|
|
@@ -778,7 +783,8 @@ export default class Inibase {
|
|
|
778
783
|
const items = await File.get(fieldPath, linesNumber, {
|
|
779
784
|
...field,
|
|
780
785
|
type: field.key === "id" &&
|
|
781
|
-
globalConfig[this.databasePath].tables
|
|
786
|
+
globalConfig[this.databasePath].tables?.get(tableName)?.config
|
|
787
|
+
.decodeID
|
|
782
788
|
? "number"
|
|
783
789
|
: field.type,
|
|
784
790
|
databasePath: this.databasePath,
|
|
@@ -886,11 +892,11 @@ export default class Inibase {
|
|
|
886
892
|
}
|
|
887
893
|
}
|
|
888
894
|
}
|
|
889
|
-
else if (this.isSimpleField(field.children)) {
|
|
895
|
+
else if (field.children != null && this.isSimpleField(field.children)) {
|
|
890
896
|
// If `children` is FieldType, handle it as an array of simple types (no recursion needed here)
|
|
891
897
|
await this.processSimpleField(tableName, field, RETURN, linesNumber, prefix);
|
|
892
898
|
}
|
|
893
|
-
else if (this.isTableField(field.children)) {
|
|
899
|
+
else if (field.children != null && this.isTableField(field.children)) {
|
|
894
900
|
await this.processTableField(tableName, field, RETURN, linesNumber, options, prefix);
|
|
895
901
|
}
|
|
896
902
|
}
|
|
@@ -953,7 +959,7 @@ export default class Inibase {
|
|
|
953
959
|
.filter((item) => item), {
|
|
954
960
|
...options,
|
|
955
961
|
perPage: -1,
|
|
956
|
-
columns: options
|
|
962
|
+
columns: options?.columns
|
|
957
963
|
?.filter((column) => column.includes(`${field.key}.`))
|
|
958
964
|
.map((column) => column.replace(`${field.key}.`, "")),
|
|
959
965
|
});
|
|
@@ -989,7 +995,8 @@ export default class Inibase {
|
|
|
989
995
|
}
|
|
990
996
|
return acc[key];
|
|
991
997
|
}, obj);
|
|
992
|
-
|
|
998
|
+
if (lastKey !== undefined)
|
|
999
|
+
target[lastKey] = value;
|
|
993
1000
|
}
|
|
994
1001
|
async applyCriteria(tableName, options, criteria, allTrue, searchIn) {
|
|
995
1002
|
const tablePath = join(this.databasePath, tableName);
|
|
@@ -1002,7 +1009,7 @@ export default class Inibase {
|
|
|
1002
1009
|
const criteriaOR = criteria.or;
|
|
1003
1010
|
if (criteriaOR)
|
|
1004
1011
|
delete criteria.or;
|
|
1005
|
-
const schema = globalConfig[this.databasePath].tables
|
|
1012
|
+
const schema = globalConfig[this.databasePath].tables?.get(tableName)?.schema ?? [];
|
|
1006
1013
|
if (Object.keys(criteria).length) {
|
|
1007
1014
|
if (allTrue === undefined)
|
|
1008
1015
|
allTrue = true;
|
|
@@ -1030,15 +1037,17 @@ export default class Inibase {
|
|
|
1030
1037
|
if (nestedAnd || nestedOr) {
|
|
1031
1038
|
const logicalChild = nestedAnd ?? nestedOr;
|
|
1032
1039
|
const logic = nestedAnd ? "and" : "or";
|
|
1033
|
-
|
|
1034
|
-
.
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1040
|
+
if (logicalChild && !Array.isArray(logicalChild)) {
|
|
1041
|
+
const crit = Object.entries(logicalChild)
|
|
1042
|
+
.map((item) => typeof item[1] === "string"
|
|
1043
|
+
? Utils.FormatObjectCriteriaValue(item[1])
|
|
1044
|
+
: ["=", item[1]])
|
|
1045
|
+
.filter(Boolean);
|
|
1046
|
+
if (crit.length) {
|
|
1047
|
+
searchOperator = crit.map((c) => c[0]);
|
|
1048
|
+
searchComparedAtValue = crit.map((c) => c[1]);
|
|
1049
|
+
searchLogicalOperator = logic;
|
|
1050
|
+
}
|
|
1042
1051
|
}
|
|
1043
1052
|
delete value[logic];
|
|
1044
1053
|
}
|
|
@@ -1052,14 +1061,14 @@ export default class Inibase {
|
|
|
1052
1061
|
searchOperator = "=";
|
|
1053
1062
|
searchComparedAtValue = value;
|
|
1054
1063
|
}
|
|
1055
|
-
const [searchResult, totalLines, linesNumbers] = await File.search(join(tablePath, `${key}${this.getFileExtension(tableName)}`), searchOperator ?? "=", searchComparedAtValue, searchLogicalOperator, searchIn, {
|
|
1064
|
+
const [searchResult, totalLines, linesNumbers] = await File.search(join(tablePath, `${key}${this.getFileExtension(tableName)}`), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, searchIn, {
|
|
1056
1065
|
...field,
|
|
1057
1066
|
databasePath: this.databasePath,
|
|
1058
1067
|
table: field.table ?? tableName,
|
|
1059
|
-
}, options.perPage < 0 ? undefined : options.perPage, options.perPage < 0
|
|
1068
|
+
}, (options.perPage ?? 0) < 0 ? undefined : options.perPage, (options.perPage ?? 0) < 0
|
|
1060
1069
|
? undefined
|
|
1061
1070
|
: (options.page - 1) * options.perPage +
|
|
1062
|
-
(options.page > 1 ? 1 : 0), true);
|
|
1071
|
+
((options.page ?? 1) > 1 ? 1 : 0), true);
|
|
1063
1072
|
if (!searchResult) {
|
|
1064
1073
|
if (allTrue)
|
|
1065
1074
|
return null;
|
|
@@ -1153,10 +1162,10 @@ export default class Inibase {
|
|
|
1153
1162
|
options.perPage = options.perPage || 15;
|
|
1154
1163
|
let total;
|
|
1155
1164
|
let RETURN;
|
|
1156
|
-
let schema = structuredClone((await this.getTable(tableName))
|
|
1165
|
+
let schema = structuredClone((await this.getTable(tableName))?.schema);
|
|
1157
1166
|
if (!schema)
|
|
1158
1167
|
throw this.createError("NO_SCHEMA", tableName);
|
|
1159
|
-
let pagination;
|
|
1168
|
+
let pagination = [0, 0];
|
|
1160
1169
|
for await (const paginationFileName of glob("*.pagination", {
|
|
1161
1170
|
cwd: tablePath,
|
|
1162
1171
|
}))
|
|
@@ -1185,7 +1194,7 @@ export default class Inibase {
|
|
|
1185
1194
|
.map((column) => [column, true]);
|
|
1186
1195
|
let cacheKey = "";
|
|
1187
1196
|
// Criteria
|
|
1188
|
-
if (globalConfig[this.databasePath].tables
|
|
1197
|
+
if (globalConfig[this.databasePath].tables?.get(tableName)?.config.cache)
|
|
1189
1198
|
cacheKey = UtilsServer.hashString(inspect(sortArray, { sorted: true }));
|
|
1190
1199
|
if (where) {
|
|
1191
1200
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
|
|
@@ -1223,7 +1232,7 @@ export default class Inibase {
|
|
|
1223
1232
|
if (cacheKey)
|
|
1224
1233
|
await File.lock(join(tablePath, ".tmp"), cacheKey);
|
|
1225
1234
|
// Combine && Execute the commands synchronously
|
|
1226
|
-
let lines = (await UtilsServer.exec(globalConfig[this.databasePath].tables
|
|
1235
|
+
let lines = (await UtilsServer.exec(globalConfig[this.databasePath].tables?.get(tableName)?.config.cache
|
|
1227
1236
|
? (await File.isExists(join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)))
|
|
1228
1237
|
? `${awkCommand} '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}'`
|
|
1229
1238
|
: `${pasteCommand} | ${sortCommand} -o '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}' && ${awkCommand} '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}'`
|
|
@@ -1232,9 +1241,9 @@ export default class Inibase {
|
|
|
1232
1241
|
})).stdout
|
|
1233
1242
|
.trimEnd()
|
|
1234
1243
|
.split("\n");
|
|
1235
|
-
if (where)
|
|
1244
|
+
if (where && options.perPage >= 0)
|
|
1236
1245
|
lines = lines.slice((options.page - 1) * options.perPage, options.page * options.perPage);
|
|
1237
|
-
else if (!this.totalItems.has(`${tableName}-*`))
|
|
1246
|
+
else if (!where && !this.totalItems.has(`${tableName}-*`))
|
|
1238
1247
|
this.totalItems.set(`${tableName}-*`, pagination[1]);
|
|
1239
1248
|
if (!lines.length)
|
|
1240
1249
|
return null;
|
|
@@ -1247,7 +1256,7 @@ export default class Inibase {
|
|
|
1247
1256
|
const field = Utils.getField(parse(fileName).name, schema);
|
|
1248
1257
|
if (field) {
|
|
1249
1258
|
if (field.key === "id" &&
|
|
1250
|
-
globalConfig[this.databasePath].tables
|
|
1259
|
+
globalConfig[this.databasePath].tables?.get(tableName)?.config
|
|
1251
1260
|
.decodeID)
|
|
1252
1261
|
outputObject[field.key] = splitedFileColumns[index];
|
|
1253
1262
|
else
|
|
@@ -1256,7 +1265,9 @@ export default class Inibase {
|
|
|
1256
1265
|
});
|
|
1257
1266
|
return outputObject;
|
|
1258
1267
|
});
|
|
1259
|
-
const restOfColumns = await this.get(tableName, outputArray
|
|
1268
|
+
const restOfColumns = await this.get(tableName, outputArray
|
|
1269
|
+
.map(({ id }) => id)
|
|
1270
|
+
.filter((id) => id !== undefined), (({ sort, ...rest }) => rest)(options));
|
|
1260
1271
|
return restOfColumns
|
|
1261
1272
|
? outputArray.map((item) => ({
|
|
1262
1273
|
...item,
|
|
@@ -1281,7 +1292,8 @@ export default class Inibase {
|
|
|
1281
1292
|
else if (((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1282
1293
|
Utils.isNumber(where)) &&
|
|
1283
1294
|
(_whereIsLinesNumbers ||
|
|
1284
|
-
!globalConfig[this.databasePath].tables
|
|
1295
|
+
!globalConfig[this.databasePath].tables?.get(tableName)?.config
|
|
1296
|
+
.decodeID)) {
|
|
1285
1297
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1286
1298
|
let lineNumbers = where;
|
|
1287
1299
|
if (!Array.isArray(lineNumbers))
|
|
@@ -1295,7 +1307,8 @@ export default class Inibase {
|
|
|
1295
1307
|
RETURN = RETURN[0];
|
|
1296
1308
|
}
|
|
1297
1309
|
else if ((!_whereIsLinesNumbers &&
|
|
1298
|
-
globalConfig[this.databasePath].tables
|
|
1310
|
+
globalConfig[this.databasePath].tables?.get(tableName)?.config
|
|
1311
|
+
.decodeID &&
|
|
1299
1312
|
((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1300
1313
|
Utils.isNumber(where))) ||
|
|
1301
1314
|
(Array.isArray(where) && where.every(Utils.isValidID)) ||
|
|
@@ -1323,7 +1336,7 @@ export default class Inibase {
|
|
|
1323
1336
|
else if (Utils.isObject(where)) {
|
|
1324
1337
|
let cachedFilePath = "";
|
|
1325
1338
|
// Criteria
|
|
1326
|
-
if (globalConfig[this.databasePath].tables
|
|
1339
|
+
if (globalConfig[this.databasePath].tables?.get(tableName)?.config.cache) {
|
|
1327
1340
|
cachedFilePath = join(tablePath, ".cache", `${UtilsServer.hashString(inspect(where, { sorted: true }))}${this.fileExtension}`);
|
|
1328
1341
|
if (await File.isExists(cachedFilePath)) {
|
|
1329
1342
|
const cachedItems = (await readFile(cachedFilePath, "utf8")).split(",");
|
|
@@ -1354,7 +1367,7 @@ export default class Inibase {
|
|
|
1354
1367
|
for (const [key] of this.totalItems)
|
|
1355
1368
|
if (key.startsWith(`${tableName}-`) && key !== `${tableName}-id`)
|
|
1356
1369
|
this.totalItems.delete(key);
|
|
1357
|
-
if (globalConfig[this.databasePath].tables
|
|
1370
|
+
if (globalConfig[this.databasePath].tables?.get(tableName)?.config.cache)
|
|
1358
1371
|
await writeFile(cachedFilePath, Object.keys(LineNumberDataObj).join(","));
|
|
1359
1372
|
}
|
|
1360
1373
|
}
|
|
@@ -1364,7 +1377,7 @@ export default class Inibase {
|
|
|
1364
1377
|
return null;
|
|
1365
1378
|
if (total === undefined)
|
|
1366
1379
|
total = this.totalItems.has(`${tableName}-*`)
|
|
1367
|
-
? this.totalItems.get(`${tableName}-*`)
|
|
1380
|
+
? (this.totalItems.get(`${tableName}-*`) ?? 0)
|
|
1368
1381
|
: Math.max(...[...this.totalItems.entries()]
|
|
1369
1382
|
.filter(([k]) => k.startsWith(`${tableName}-`))
|
|
1370
1383
|
.map(([, v]) => v));
|
|
@@ -1384,7 +1397,7 @@ export default class Inibase {
|
|
|
1384
1397
|
};
|
|
1385
1398
|
const tablePath = join(this.databasePath, tableName);
|
|
1386
1399
|
await this.getTable(tableName);
|
|
1387
|
-
if (!globalConfig[this.databasePath].tables
|
|
1400
|
+
if (!globalConfig[this.databasePath].tables?.get(tableName)?.schema)
|
|
1388
1401
|
throw this.createError("NO_SCHEMA", tableName);
|
|
1389
1402
|
if (!returnPostedData)
|
|
1390
1403
|
returnPostedData = false;
|
|
@@ -1394,7 +1407,7 @@ export default class Inibase {
|
|
|
1394
1407
|
const renameList = [];
|
|
1395
1408
|
try {
|
|
1396
1409
|
await File.lock(join(tablePath, ".tmp"), keys);
|
|
1397
|
-
let paginationFilePath;
|
|
1410
|
+
let paginationFilePath = "";
|
|
1398
1411
|
for await (const fileName of glob("*.pagination", { cwd: tablePath }))
|
|
1399
1412
|
paginationFilePath = join(tablePath, fileName);
|
|
1400
1413
|
let [lastId, _totalItems] = parse(paginationFilePath)
|
|
@@ -1413,36 +1426,38 @@ export default class Inibase {
|
|
|
1413
1426
|
clonedData.createdAt = Date.now();
|
|
1414
1427
|
clonedData.updatedAt = undefined;
|
|
1415
1428
|
}
|
|
1416
|
-
clonedData = this.formatData(clonedData, globalConfig[this.databasePath].tables
|
|
1417
|
-
const pathesContents = this.joinPathesContents(tableName, globalConfig[this.databasePath].tables
|
|
1429
|
+
clonedData = this.formatData(clonedData, globalConfig[this.databasePath].tables?.get(tableName)?.schema ?? [], false);
|
|
1430
|
+
const pathesContents = this.joinPathesContents(tableName, globalConfig[this.databasePath].tables?.get(tableName)?.config.prepend
|
|
1418
1431
|
? Array.isArray(clonedData)
|
|
1419
1432
|
? clonedData.toReversed()
|
|
1420
1433
|
: clonedData
|
|
1421
1434
|
: clonedData);
|
|
1422
|
-
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(globalConfig[this.databasePath].tables
|
|
1435
|
+
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(globalConfig[this.databasePath].tables?.get(tableName)?.config
|
|
1436
|
+
.prepend
|
|
1423
1437
|
? await File.prepend(path, content)
|
|
1424
1438
|
: await File.append(path, content))));
|
|
1425
1439
|
await Promise.allSettled(renameList
|
|
1426
1440
|
.filter(([_, filePath]) => filePath)
|
|
1427
1441
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1428
|
-
if (globalConfig[this.databasePath].tables
|
|
1442
|
+
if (globalConfig[this.databasePath].tables?.get(tableName)?.config.cache)
|
|
1429
1443
|
await this.clearCache(tableName);
|
|
1430
1444
|
const currentValue = this.totalItems.get(`${tableName}-*`) || 0;
|
|
1431
1445
|
this.totalItems.set(`${tableName}-*`, currentValue + (Array.isArray(data) ? data.length : 1));
|
|
1432
1446
|
await rename(paginationFilePath, join(tablePath, `${lastId}-${this.totalItems.get(`${tableName}-*`)}.pagination`));
|
|
1433
1447
|
if (returnPostedData)
|
|
1434
|
-
return this.get(tableName, globalConfig[this.databasePath].tables
|
|
1448
|
+
return this.get(tableName, globalConfig[this.databasePath].tables?.get(tableName)?.config.prepend
|
|
1435
1449
|
? Array.isArray(clonedData)
|
|
1436
1450
|
? clonedData.map((_, index) => index + 1).toReversed()
|
|
1437
1451
|
: 1
|
|
1438
1452
|
: Array.isArray(clonedData)
|
|
1439
1453
|
? clonedData
|
|
1440
|
-
.map((_, index) => this.totalItems.get(`${tableName}-*`) - index)
|
|
1454
|
+
.map((_, index) => (this.totalItems.get(`${tableName}-*`) ?? 0) - index)
|
|
1441
1455
|
.toReversed()
|
|
1442
1456
|
: this.totalItems.get(`${tableName}-*`), options, !Utils.isArrayOfObjects(clonedData), // return only one item if data is not array of objects
|
|
1443
1457
|
undefined, true);
|
|
1444
1458
|
return Array.isArray(clonedData)
|
|
1445
|
-
? (globalConfig[this.databasePath].tables
|
|
1459
|
+
? (globalConfig[this.databasePath].tables?.get(tableName)?.config
|
|
1460
|
+
.prepend
|
|
1446
1461
|
? clonedData.toReversed()
|
|
1447
1462
|
: clonedData).map(({ id }) => UtilsServer.encodeID(id))
|
|
1448
1463
|
: UtilsServer.encodeID(clonedData.id);
|
|
@@ -1467,7 +1482,9 @@ export default class Inibase {
|
|
|
1467
1482
|
if (Utils.isArrayOfObjects(clonedData)) {
|
|
1468
1483
|
if (!clonedData.every((item) => Object.hasOwn(item, "id") && Utils.isValidID(item.id)))
|
|
1469
1484
|
throw this.createError("INVALID_ID");
|
|
1470
|
-
return this.put(tableName, clonedData, clonedData
|
|
1485
|
+
return this.put(tableName, clonedData, clonedData
|
|
1486
|
+
.map(({ id }) => id)
|
|
1487
|
+
.filter((id) => id !== undefined), options, returnUpdatedData);
|
|
1471
1488
|
}
|
|
1472
1489
|
if (Object.hasOwn(clonedData, "id")) {
|
|
1473
1490
|
if (!Utils.isValidID(clonedData.id))
|
|
@@ -1475,7 +1492,7 @@ export default class Inibase {
|
|
|
1475
1492
|
return this.put(tableName, clonedData, clonedData.id, options, returnUpdatedData);
|
|
1476
1493
|
}
|
|
1477
1494
|
await this.validateTableData(tableName, clonedData, true);
|
|
1478
|
-
clonedData = this.formatData(clonedData, globalConfig[this.databasePath].tables
|
|
1495
|
+
clonedData = this.formatData(clonedData, globalConfig[this.databasePath].tables?.get(tableName)?.schema ?? [], true);
|
|
1479
1496
|
const pathesContents = this.joinPathesContents(tableName, {
|
|
1480
1497
|
...(({ id, ...restOfData }) => restOfData)(clonedData),
|
|
1481
1498
|
updatedAt: Date.now(),
|
|
@@ -1490,7 +1507,7 @@ export default class Inibase {
|
|
|
1490
1507
|
await Promise.allSettled(renameList
|
|
1491
1508
|
.filter(([_, filePath]) => filePath)
|
|
1492
1509
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1493
|
-
if (globalConfig[this.databasePath].tables
|
|
1510
|
+
if (globalConfig[this.databasePath].tables?.get(tableName)?.config.cache)
|
|
1494
1511
|
await this.clearCache(join(tablePath, ".cache"));
|
|
1495
1512
|
if (returnUpdatedData)
|
|
1496
1513
|
return await this.get(tableName, undefined, options);
|
|
@@ -1506,10 +1523,11 @@ export default class Inibase {
|
|
|
1506
1523
|
else if (((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1507
1524
|
Utils.isNumber(where)) &&
|
|
1508
1525
|
(_whereIsLinesNumbers ||
|
|
1509
|
-
!globalConfig[this.databasePath].tables
|
|
1526
|
+
!globalConfig[this.databasePath].tables?.get(tableName)?.config
|
|
1527
|
+
.decodeID)) {
|
|
1510
1528
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1511
1529
|
await this.validateTableData(tableName, clonedData, true);
|
|
1512
|
-
clonedData = this.formatData(clonedData, globalConfig[this.databasePath].tables
|
|
1530
|
+
clonedData = this.formatData(clonedData, globalConfig[this.databasePath].tables?.get(tableName)?.schema ?? [], true);
|
|
1513
1531
|
const pathesContents = Object.fromEntries(Object.entries(this.joinPathesContents(tableName, Array.isArray(clonedData)
|
|
1514
1532
|
? clonedData.map((item) => ({
|
|
1515
1533
|
...item,
|
|
@@ -1531,7 +1549,7 @@ export default class Inibase {
|
|
|
1531
1549
|
await Promise.allSettled(renameList
|
|
1532
1550
|
.filter(([_, filePath]) => filePath)
|
|
1533
1551
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1534
|
-
if (globalConfig[this.databasePath].tables
|
|
1552
|
+
if (globalConfig[this.databasePath].tables?.get(tableName)?.config.cache)
|
|
1535
1553
|
await this.clearCache(tableName);
|
|
1536
1554
|
if (returnUpdatedData)
|
|
1537
1555
|
return this.get(tableName, where, options, !Array.isArray(where), undefined, true);
|
|
@@ -1545,7 +1563,8 @@ export default class Inibase {
|
|
|
1545
1563
|
}
|
|
1546
1564
|
}
|
|
1547
1565
|
else if ((!_whereIsLinesNumbers &&
|
|
1548
|
-
globalConfig[this.databasePath].tables
|
|
1566
|
+
globalConfig[this.databasePath].tables?.get(tableName)?.config
|
|
1567
|
+
.decodeID &&
|
|
1549
1568
|
((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1550
1569
|
Utils.isNumber(where))) ||
|
|
1551
1570
|
(Array.isArray(where) && where.every(Utils.isValidID)) ||
|
|
@@ -1575,8 +1594,8 @@ export default class Inibase {
|
|
|
1575
1594
|
if (!where) {
|
|
1576
1595
|
try {
|
|
1577
1596
|
await File.lock(join(tablePath, ".tmp"));
|
|
1578
|
-
let paginationFilePath;
|
|
1579
|
-
let pagination;
|
|
1597
|
+
let paginationFilePath = "";
|
|
1598
|
+
let pagination = [0, 0];
|
|
1580
1599
|
for await (const paginationFileName of glob("*.pagination", {
|
|
1581
1600
|
cwd: tablePath,
|
|
1582
1601
|
})) {
|
|
@@ -1588,7 +1607,7 @@ export default class Inibase {
|
|
|
1588
1607
|
await Promise.allSettled((await readdir(tablePath))
|
|
1589
1608
|
?.filter((fileName) => fileName.endsWith(this.getFileExtension(tableName)))
|
|
1590
1609
|
.map(async (file) => unlink(join(tablePath, file))));
|
|
1591
|
-
if (globalConfig[this.databasePath].tables
|
|
1610
|
+
if (globalConfig[this.databasePath].tables?.get(tableName)?.config.cache)
|
|
1592
1611
|
await this.clearCache(tableName);
|
|
1593
1612
|
await rename(paginationFilePath, join(tablePath, `${pagination[0]}-0.pagination`));
|
|
1594
1613
|
return true;
|
|
@@ -1600,15 +1619,16 @@ export default class Inibase {
|
|
|
1600
1619
|
if (((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1601
1620
|
Utils.isNumber(where)) &&
|
|
1602
1621
|
(_whereIsLinesNumbers ||
|
|
1603
|
-
!globalConfig[this.databasePath].tables
|
|
1622
|
+
!globalConfig[this.databasePath].tables?.get(tableName)?.config
|
|
1623
|
+
.decodeID)) {
|
|
1604
1624
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1605
1625
|
const files = (await readdir(tablePath))?.filter((fileName) => fileName.endsWith(this.getFileExtension(tableName)));
|
|
1606
1626
|
if (files.length) {
|
|
1607
1627
|
const renameList = [];
|
|
1608
1628
|
try {
|
|
1609
1629
|
await File.lock(join(tablePath, ".tmp"));
|
|
1610
|
-
let paginationFilePath;
|
|
1611
|
-
let pagination;
|
|
1630
|
+
let paginationFilePath = "";
|
|
1631
|
+
let pagination = [0, 0];
|
|
1612
1632
|
for await (const paginationFileName of glob("*.pagination", {
|
|
1613
1633
|
cwd: tablePath,
|
|
1614
1634
|
})) {
|
|
@@ -1628,7 +1648,7 @@ export default class Inibase {
|
|
|
1628
1648
|
await Promise.allSettled((await readdir(tablePath))
|
|
1629
1649
|
?.filter((fileName) => fileName.endsWith(this.getFileExtension(tableName)))
|
|
1630
1650
|
.map(async (file) => unlink(join(tablePath, file))));
|
|
1631
|
-
if (globalConfig[this.databasePath].tables
|
|
1651
|
+
if (globalConfig[this.databasePath].tables?.get(tableName)?.config.cache)
|
|
1632
1652
|
await this.clearCache(tableName);
|
|
1633
1653
|
await rename(paginationFilePath, join(tablePath, `${pagination[0]}-${pagination[1] - (Array.isArray(where) ? where.length : 1)}.pagination`));
|
|
1634
1654
|
return true;
|
|
@@ -1643,7 +1663,8 @@ export default class Inibase {
|
|
|
1643
1663
|
}
|
|
1644
1664
|
}
|
|
1645
1665
|
if ((!_whereIsLinesNumbers &&
|
|
1646
|
-
globalConfig[this.databasePath].tables
|
|
1666
|
+
globalConfig[this.databasePath].tables?.get(tableName)?.config
|
|
1667
|
+
.decodeID &&
|
|
1647
1668
|
((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1648
1669
|
Utils.isNumber(where))) ||
|
|
1649
1670
|
(Array.isArray(where) && where.every(Utils.isValidID)) ||
|