inibase 1.0.0-rc.120 → 1.0.0-rc.121
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 -3
- package/dist/file.js +1 -1
- package/dist/index.d.ts +10 -6
- package/dist/index.js +165 -132
- package/dist/utils.server.d.ts +13 -0
- package/dist/utils.server.js +26 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -726,13 +726,13 @@ await db.get("user", undefined, { sort: {age: -1, username: "asc"} });
|
|
|
726
726
|
- [x] Id
|
|
727
727
|
- [x] JSON
|
|
728
728
|
- [ ] TO-DO:
|
|
729
|
-
- [
|
|
729
|
+
- [x] Use new Map() instead of Object
|
|
730
730
|
- [ ] Ability to search in JSON fields
|
|
731
|
-
- [
|
|
731
|
+
- [x] Re-check used exec functions
|
|
732
732
|
- [ ] Use smart caching (based on N° of queries)
|
|
733
733
|
- [ ] Commenting the code
|
|
734
734
|
- [ ] Add Backup feature (generate a tar.gz)
|
|
735
|
-
- [
|
|
735
|
+
- [x] Add Custom field validation property to schema (using RegEx?)
|
|
736
736
|
- [ ] Features:
|
|
737
737
|
- [ ] Encryption
|
|
738
738
|
- [x] Data Compression
|
package/dist/file.js
CHANGED
|
@@ -542,7 +542,7 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
|
|
|
542
542
|
// Increment the line count for each line.
|
|
543
543
|
linesCount++;
|
|
544
544
|
// Search only in provided linesNumbers
|
|
545
|
-
if (searchIn && !searchIn.has(linesCount))
|
|
545
|
+
if ((searchIn && !searchIn.has(linesCount)) || searchIn.has(-linesCount))
|
|
546
546
|
continue;
|
|
547
547
|
// Decode the line for comparison.
|
|
548
548
|
const decodedLine = decode(line, fieldType, fieldChildrenType, secretKey);
|
package/dist/index.d.ts
CHANGED
|
@@ -12,8 +12,9 @@ export type Field = {
|
|
|
12
12
|
type: FieldType | FieldType[];
|
|
13
13
|
required?: boolean;
|
|
14
14
|
table?: string;
|
|
15
|
-
unique?: boolean;
|
|
15
|
+
unique?: boolean | number | string;
|
|
16
16
|
children?: FieldType | FieldType[] | Schema;
|
|
17
|
+
regex?: string;
|
|
17
18
|
};
|
|
18
19
|
export type Schema = Field[];
|
|
19
20
|
export interface Options {
|
|
@@ -49,18 +50,19 @@ declare global {
|
|
|
49
50
|
entries<T extends object>(o: T): Entries<T>;
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
|
-
export type ErrorCodes = "FIELD_UNIQUE" | "FIELD_REQUIRED" | "NO_SCHEMA" | "TABLE_EMPTY" | "INVALID_ID" | "INVALID_TYPE" | "INVALID_PARAMETERS" | "NO_ENV" | "TABLE_EXISTS" | "TABLE_NOT_EXISTS";
|
|
53
|
+
export type ErrorCodes = "FIELD_UNIQUE" | "FIELD_REQUIRED" | "NO_SCHEMA" | "TABLE_EMPTY" | "INVALID_ID" | "INVALID_TYPE" | "INVALID_PARAMETERS" | "NO_ENV" | "TABLE_EXISTS" | "TABLE_NOT_EXISTS" | "INVALID_REGEX_MATCH";
|
|
53
54
|
export type ErrorLang = "en";
|
|
54
55
|
export default class Inibase {
|
|
55
56
|
pageInfo: Record<string, pageInfo>;
|
|
56
57
|
salt: Buffer;
|
|
57
58
|
private databasePath;
|
|
58
|
-
private tables;
|
|
59
59
|
private fileExtension;
|
|
60
|
-
private
|
|
60
|
+
private tablesMap;
|
|
61
|
+
private uniqueMap;
|
|
61
62
|
private totalItems;
|
|
62
63
|
constructor(database: string, mainFolder?: string);
|
|
63
|
-
private
|
|
64
|
+
private static errorMessages;
|
|
65
|
+
createError(code: ErrorCodes, variable?: string | number | (string | number)[], language?: ErrorLang): Error;
|
|
64
66
|
clear(): void;
|
|
65
67
|
private getFileExtension;
|
|
66
68
|
private _schemaToIdsPath;
|
|
@@ -89,13 +91,15 @@ export default class Inibase {
|
|
|
89
91
|
* @param {string} tableName
|
|
90
92
|
* @return {*} {Promise<TableObject>}
|
|
91
93
|
*/
|
|
92
|
-
getTable(tableName: string): Promise<TableObject>;
|
|
94
|
+
getTable(tableName: string, encodeIDs?: boolean): Promise<TableObject>;
|
|
93
95
|
getTableSchema(tableName: string, encodeIDs?: boolean): Promise<Schema | undefined>;
|
|
94
96
|
private throwErrorIfTableEmpty;
|
|
97
|
+
private _validateData;
|
|
95
98
|
private validateData;
|
|
96
99
|
private cleanObject;
|
|
97
100
|
private formatField;
|
|
98
101
|
private checkUnique;
|
|
102
|
+
private _formatData;
|
|
99
103
|
private formatData;
|
|
100
104
|
private getDefaultValue;
|
|
101
105
|
private _combineObjectsToArray;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
|
-
import { randomBytes, scryptSync } from "node:crypto";
|
|
2
|
+
import { randomBytes, randomInt, scryptSync } from "node:crypto";
|
|
3
3
|
import { appendFileSync, existsSync, readFileSync } from "node:fs";
|
|
4
4
|
import { glob, mkdir, readFile, readdir, rename, rm, unlink, writeFile, } from "node:fs/promises";
|
|
5
5
|
import { join, parse } from "node:path";
|
|
@@ -14,45 +14,45 @@ export default class Inibase {
|
|
|
14
14
|
pageInfo;
|
|
15
15
|
salt;
|
|
16
16
|
databasePath;
|
|
17
|
-
tables;
|
|
18
17
|
fileExtension = ".txt";
|
|
19
|
-
|
|
18
|
+
tablesMap;
|
|
19
|
+
uniqueMap;
|
|
20
20
|
totalItems;
|
|
21
21
|
constructor(database, mainFolder = ".") {
|
|
22
22
|
this.databasePath = join(mainFolder, database);
|
|
23
|
-
this.
|
|
24
|
-
this.totalItems =
|
|
23
|
+
this.tablesMap = new Map();
|
|
24
|
+
this.totalItems = new Map();
|
|
25
25
|
this.pageInfo = {};
|
|
26
|
-
this.
|
|
26
|
+
this.uniqueMap = new Map();
|
|
27
27
|
if (!process.env.INIBASE_SECRET) {
|
|
28
28
|
if (existsSync(".env") &&
|
|
29
29
|
readFileSync(".env").includes("INIBASE_SECRET="))
|
|
30
|
-
throw this.
|
|
30
|
+
throw this.createError("NO_ENV");
|
|
31
31
|
this.salt = scryptSync(randomBytes(16), randomBytes(16), 32);
|
|
32
32
|
appendFileSync(".env", `\nINIBASE_SECRET=${this.salt.toString("hex")}\n`);
|
|
33
33
|
}
|
|
34
34
|
else
|
|
35
35
|
this.salt = Buffer.from(process.env.INIBASE_SECRET, "hex");
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const errorMessage = errorMessages[language][code];
|
|
37
|
+
static errorMessages = {
|
|
38
|
+
en: {
|
|
39
|
+
TABLE_EMPTY: "Table {variable} is empty",
|
|
40
|
+
TABLE_EXISTS: "Table {variable} already exists",
|
|
41
|
+
TABLE_NOT_EXISTS: "Table {variable} doesn't exist",
|
|
42
|
+
NO_SCHEMA: "Table {variable} does't have a schema",
|
|
43
|
+
FIELD_UNIQUE: "Field {variable} should be unique, got {variable} instead",
|
|
44
|
+
FIELD_REQUIRED: "Field {variable} is required",
|
|
45
|
+
INVALID_ID: "The given ID(s) is/are not valid(s)",
|
|
46
|
+
INVALID_TYPE: "Expect {variable} to be {variable}, got {variable} instead",
|
|
47
|
+
INVALID_PARAMETERS: "The given parameters are not valid",
|
|
48
|
+
INVALID_REGEX_MATCH: "Field {variable} does not match the expected pattern",
|
|
49
|
+
NO_ENV: Number(process.versions.node.split(".").reduce((a, b) => a + b)) >= 26
|
|
50
|
+
? "please run with '--env-file=.env'"
|
|
51
|
+
: "please use dotenv",
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
createError(code, variable, language = "en") {
|
|
55
|
+
const errorMessage = Inibase.errorMessages[language]?.[code];
|
|
56
56
|
if (!errorMessage)
|
|
57
57
|
return new Error("ERR");
|
|
58
58
|
return new Error(variable
|
|
@@ -62,17 +62,17 @@ export default class Inibase {
|
|
|
62
62
|
: errorMessage.replaceAll("{variable}", ""));
|
|
63
63
|
}
|
|
64
64
|
clear() {
|
|
65
|
-
this.
|
|
66
|
-
this.totalItems =
|
|
65
|
+
this.tablesMap = new Map();
|
|
66
|
+
this.totalItems = new Map();
|
|
67
67
|
this.pageInfo = {};
|
|
68
|
-
this.
|
|
68
|
+
this.uniqueMap = new Map();
|
|
69
69
|
}
|
|
70
70
|
getFileExtension(tableName) {
|
|
71
71
|
let mainExtension = this.fileExtension;
|
|
72
72
|
// TODO: ADD ENCRYPTION
|
|
73
|
-
// if(this.
|
|
73
|
+
// if(this.tablesMap.get(tableName).config.encryption)
|
|
74
74
|
// mainExtension += ".enc"
|
|
75
|
-
if (this.
|
|
75
|
+
if (this.tablesMap.get(tableName).config.compression)
|
|
76
76
|
mainExtension += ".gz";
|
|
77
77
|
return mainExtension;
|
|
78
78
|
}
|
|
@@ -99,7 +99,7 @@ export default class Inibase {
|
|
|
99
99
|
async createTable(tableName, schema, config) {
|
|
100
100
|
const tablePath = join(this.databasePath, tableName);
|
|
101
101
|
if (await File.isExists(tablePath))
|
|
102
|
-
throw this.
|
|
102
|
+
throw this.createError("TABLE_EXISTS", tableName);
|
|
103
103
|
await mkdir(join(tablePath, ".tmp"), { recursive: true });
|
|
104
104
|
await mkdir(join(tablePath, ".cache"));
|
|
105
105
|
// if config not set => load default global env config
|
|
@@ -142,7 +142,8 @@ export default class Inibase {
|
|
|
142
142
|
* @param {(Config&{name?: string})} [config]
|
|
143
143
|
*/
|
|
144
144
|
async updateTable(tableName, schema, config) {
|
|
145
|
-
const table = await this.getTable(tableName)
|
|
145
|
+
const table = await this.getTable(tableName);
|
|
146
|
+
const tablePath = join(this.databasePath, tableName);
|
|
146
147
|
if (schema) {
|
|
147
148
|
// remove id from schema
|
|
148
149
|
schema = schema.filter(({ key }) => !["id", "createdAt", "updatedAt"].includes(key));
|
|
@@ -232,7 +233,7 @@ export default class Inibase {
|
|
|
232
233
|
await this.replaceStringInFile(schemaPath, `"table": "${tableName}"`, `"table": "${config.name}"`);
|
|
233
234
|
}
|
|
234
235
|
}
|
|
235
|
-
|
|
236
|
+
this.tablesMap.delete(tableName);
|
|
236
237
|
}
|
|
237
238
|
/**
|
|
238
239
|
* Get table schema and config
|
|
@@ -240,20 +241,20 @@ export default class Inibase {
|
|
|
240
241
|
* @param {string} tableName
|
|
241
242
|
* @return {*} {Promise<TableObject>}
|
|
242
243
|
*/
|
|
243
|
-
async getTable(tableName) {
|
|
244
|
+
async getTable(tableName, encodeIDs = true) {
|
|
244
245
|
const tablePath = join(this.databasePath, tableName);
|
|
245
246
|
if (!(await File.isExists(tablePath)))
|
|
246
|
-
throw this.
|
|
247
|
-
if (!this.
|
|
248
|
-
this.
|
|
249
|
-
schema: await this.getTableSchema(tableName),
|
|
247
|
+
throw this.createError("TABLE_NOT_EXISTS", tableName);
|
|
248
|
+
if (!this.tablesMap.has(tableName))
|
|
249
|
+
this.tablesMap.set(tableName, {
|
|
250
|
+
schema: await this.getTableSchema(tableName, encodeIDs),
|
|
250
251
|
config: {
|
|
251
252
|
compression: await File.isExists(join(tablePath, ".compression.config")),
|
|
252
253
|
cache: await File.isExists(join(tablePath, ".cache.config")),
|
|
253
254
|
prepend: await File.isExists(join(tablePath, ".prepend.config")),
|
|
254
255
|
},
|
|
255
|
-
};
|
|
256
|
-
return this.
|
|
256
|
+
});
|
|
257
|
+
return this.tablesMap.get(tableName);
|
|
257
258
|
}
|
|
258
259
|
async getTableSchema(tableName, encodeIDs = true) {
|
|
259
260
|
const tablePath = join(this.databasePath, tableName);
|
|
@@ -288,17 +289,16 @@ export default class Inibase {
|
|
|
288
289
|
return UtilsServer.encodeSchemaID(schema, this.salt);
|
|
289
290
|
}
|
|
290
291
|
async throwErrorIfTableEmpty(tableName) {
|
|
291
|
-
const table = await this.getTable(tableName);
|
|
292
|
+
const table = await this.getTable(tableName, false);
|
|
292
293
|
if (!table.schema)
|
|
293
|
-
throw this.
|
|
294
|
+
throw this.createError("NO_SCHEMA", tableName);
|
|
294
295
|
if (!(await File.isExists(join(this.databasePath, tableName, `id${this.getFileExtension(tableName)}`))))
|
|
295
|
-
throw this.
|
|
296
|
-
return table;
|
|
296
|
+
throw this.createError("TABLE_EMPTY", tableName);
|
|
297
297
|
}
|
|
298
|
-
|
|
298
|
+
_validateData(data, schema, skipRequiredField = false) {
|
|
299
299
|
if (Utils.isArrayOfObjects(data))
|
|
300
300
|
for (const single_data of data)
|
|
301
|
-
this.
|
|
301
|
+
this._validateData(single_data, schema, skipRequiredField);
|
|
302
302
|
else if (Utils.isObject(data)) {
|
|
303
303
|
for (const field of schema) {
|
|
304
304
|
if (!Object.hasOwn(data, field.key) ||
|
|
@@ -306,7 +306,7 @@ export default class Inibase {
|
|
|
306
306
|
data[field.key] === undefined ||
|
|
307
307
|
data[field.key] === "") {
|
|
308
308
|
if (field.required && !skipRequiredField)
|
|
309
|
-
throw this.
|
|
309
|
+
throw this.createError("FIELD_REQUIRED", field.key);
|
|
310
310
|
return;
|
|
311
311
|
}
|
|
312
312
|
if (!Utils.validateFieldType(data[field.key], field.type, (field.type === "array" || field.type === "object") &&
|
|
@@ -314,7 +314,7 @@ export default class Inibase {
|
|
|
314
314
|
!Utils.isArrayOfObjects(field.children)
|
|
315
315
|
? field.children
|
|
316
316
|
: undefined))
|
|
317
|
-
throw this.
|
|
317
|
+
throw this.createError("INVALID_TYPE", [
|
|
318
318
|
field.key,
|
|
319
319
|
Array.isArray(field.type) ? field.type.join(", ") : field.type,
|
|
320
320
|
data[field.key],
|
|
@@ -322,15 +322,46 @@ export default class Inibase {
|
|
|
322
322
|
if ((field.type === "array" || field.type === "object") &&
|
|
323
323
|
field.children &&
|
|
324
324
|
Utils.isArrayOfObjects(field.children))
|
|
325
|
-
this.
|
|
326
|
-
else
|
|
327
|
-
if (
|
|
328
|
-
|
|
329
|
-
|
|
325
|
+
this._validateData(data[field.key], field.children, skipRequiredField);
|
|
326
|
+
else {
|
|
327
|
+
if (field.regex) {
|
|
328
|
+
const regex = UtilsServer.getCachedRegex(field.regex);
|
|
329
|
+
if (!regex.test(data[field.key]))
|
|
330
|
+
throw this.createError("INVALID_REGEX_MATCH", [field.key]);
|
|
331
|
+
}
|
|
332
|
+
if (field.unique) {
|
|
333
|
+
let uniqueKey;
|
|
334
|
+
if (typeof field.unique === "boolean")
|
|
335
|
+
uniqueKey = randomInt(55);
|
|
336
|
+
else
|
|
337
|
+
uniqueKey = field.unique;
|
|
338
|
+
if (!this.uniqueMap.has(uniqueKey))
|
|
339
|
+
this.uniqueMap.set(uniqueKey, {
|
|
340
|
+
exclude: new Set(),
|
|
341
|
+
columnsValues: new Map(),
|
|
342
|
+
});
|
|
343
|
+
if (!this.uniqueMap
|
|
344
|
+
.get(uniqueKey)
|
|
345
|
+
.columnsValues.has(field.id))
|
|
346
|
+
this.uniqueMap
|
|
347
|
+
.get(uniqueKey)
|
|
348
|
+
.columnsValues.set(field.id, new Set());
|
|
349
|
+
if (data.id)
|
|
350
|
+
this.uniqueMap.get(uniqueKey).exclude.add(-data.id);
|
|
351
|
+
this.uniqueMap
|
|
352
|
+
.get(uniqueKey)
|
|
353
|
+
.columnsValues.get(field.id)
|
|
354
|
+
.add(data[field.key]);
|
|
355
|
+
}
|
|
330
356
|
}
|
|
331
357
|
}
|
|
332
358
|
}
|
|
333
359
|
}
|
|
360
|
+
async validateData(tableName, data, skipRequiredField = false) {
|
|
361
|
+
// Skip ID and (created|updated)At
|
|
362
|
+
this._validateData(data, this.tablesMap.get(tableName).schema.slice(1, -2), skipRequiredField);
|
|
363
|
+
await this.checkUnique(tableName);
|
|
364
|
+
}
|
|
334
365
|
cleanObject(obj) {
|
|
335
366
|
const cleanedObject = Object.entries(obj).reduce((acc, [key, value]) => {
|
|
336
367
|
if (value !== undefined && value !== null && value !== "")
|
|
@@ -353,13 +384,13 @@ export default class Inibase {
|
|
|
353
384
|
if (!Array.isArray(value))
|
|
354
385
|
value = [value];
|
|
355
386
|
if (Utils.isArrayOfObjects(fieldChildrenType))
|
|
356
|
-
return this.
|
|
387
|
+
return this._formatData(value, fieldChildrenType);
|
|
357
388
|
if (!value.length)
|
|
358
389
|
return null;
|
|
359
390
|
return value.map((_value) => this.formatField(_value, fieldChildrenType));
|
|
360
391
|
case "object":
|
|
361
392
|
if (Utils.isArrayOfObjects(fieldChildrenType))
|
|
362
|
-
return this.
|
|
393
|
+
return this._formatData(value, fieldChildrenType, _formatOnlyAvailiableKeys);
|
|
363
394
|
break;
|
|
364
395
|
case "table":
|
|
365
396
|
if (Utils.isObject(value)) {
|
|
@@ -402,25 +433,30 @@ export default class Inibase {
|
|
|
402
433
|
}
|
|
403
434
|
return null;
|
|
404
435
|
}
|
|
405
|
-
async checkUnique(tableName
|
|
436
|
+
async checkUnique(tableName) {
|
|
406
437
|
const tablePath = join(this.databasePath, tableName);
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
438
|
+
const flattenSchema = Utils.flattenSchema(this.tablesMap.get(tableName).schema);
|
|
439
|
+
for await (const [_uniqueID, valueObject] of this.uniqueMap) {
|
|
440
|
+
let valueExisted = false;
|
|
441
|
+
for await (const [columnID, values] of valueObject.columnsValues) {
|
|
442
|
+
const field = flattenSchema.find(({ id }) => id === columnID);
|
|
443
|
+
const [searchResult, totalLines] = await File.search(join(tablePath, `${columnID}${this.getFileExtension(tableName)}`), "[]", values, undefined, valueObject.exclude, field.type, field.children, 1, undefined, false, this.salt);
|
|
444
|
+
if (searchResult && totalLines > 0) {
|
|
445
|
+
if (valueExisted)
|
|
446
|
+
throw this.createError("FIELD_UNIQUE", [
|
|
447
|
+
field.key,
|
|
448
|
+
Array.isArray(values) ? values.join(", ") : values,
|
|
449
|
+
]);
|
|
450
|
+
valueExisted = true;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
417
453
|
}
|
|
418
|
-
this.
|
|
454
|
+
this.uniqueMap = new Map();
|
|
419
455
|
}
|
|
420
|
-
|
|
456
|
+
_formatData(data, schema, formatOnlyAvailiableKeys) {
|
|
421
457
|
const clonedData = JSON.parse(JSON.stringify(data));
|
|
422
458
|
if (Utils.isArrayOfObjects(clonedData))
|
|
423
|
-
return clonedData.map((singleData) => this.
|
|
459
|
+
return clonedData.map((singleData) => this._formatData(singleData, schema, formatOnlyAvailiableKeys));
|
|
424
460
|
if (Utils.isObject(clonedData)) {
|
|
425
461
|
const RETURN = {};
|
|
426
462
|
for (const field of schema) {
|
|
@@ -436,6 +472,9 @@ export default class Inibase {
|
|
|
436
472
|
}
|
|
437
473
|
return [];
|
|
438
474
|
}
|
|
475
|
+
formatData(tableName, data, formatOnlyAvailiableKeys) {
|
|
476
|
+
data = this._formatData(data, this.tablesMap.get(tableName).schema, formatOnlyAvailiableKeys);
|
|
477
|
+
}
|
|
439
478
|
getDefaultValue(field) {
|
|
440
479
|
if (Array.isArray(field.type))
|
|
441
480
|
return this.getDefaultValue({
|
|
@@ -835,7 +874,7 @@ export default class Inibase {
|
|
|
835
874
|
[key]: value,
|
|
836
875
|
},
|
|
837
876
|
])));
|
|
838
|
-
this.totalItems
|
|
877
|
+
this.totalItems.set(`${tableName}-${key}`, totalLines);
|
|
839
878
|
if (linesNumbers?.size) {
|
|
840
879
|
if (searchIn) {
|
|
841
880
|
for (const lineNumber of linesNumbers)
|
|
@@ -911,9 +950,10 @@ export default class Inibase {
|
|
|
911
950
|
options.page = options.page || 1;
|
|
912
951
|
options.perPage = options.perPage || 15;
|
|
913
952
|
let RETURN;
|
|
953
|
+
await this.getTable(tableName);
|
|
914
954
|
let schema = (await this.getTable(tableName)).schema;
|
|
915
955
|
if (!schema)
|
|
916
|
-
throw this.
|
|
956
|
+
throw this.createError("NO_SCHEMA", tableName);
|
|
917
957
|
let pagination;
|
|
918
958
|
for await (const paginationFileName of glob("*.pagination", {
|
|
919
959
|
cwd: tablePath,
|
|
@@ -942,7 +982,7 @@ export default class Inibase {
|
|
|
942
982
|
.map((column) => [column, true]);
|
|
943
983
|
let cacheKey = "";
|
|
944
984
|
// Criteria
|
|
945
|
-
if (this.
|
|
985
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
946
986
|
cacheKey = UtilsServer.hashString(inspect(sortArray, { sorted: true }));
|
|
947
987
|
if (where) {
|
|
948
988
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
|
|
@@ -980,7 +1020,7 @@ export default class Inibase {
|
|
|
980
1020
|
if (cacheKey)
|
|
981
1021
|
await File.lock(join(tablePath, ".tmp"), cacheKey);
|
|
982
1022
|
// Combine && Execute the commands synchronously
|
|
983
|
-
let lines = (await UtilsServer.exec(this.
|
|
1023
|
+
let lines = (await UtilsServer.exec(this.tablesMap.get(tableName).config.cache
|
|
984
1024
|
? (await File.isExists(join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)))
|
|
985
1025
|
? `${awkCommand} '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}'`
|
|
986
1026
|
: `${pasteCommand} | ${sortCommand} -o '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}' && ${awkCommand} '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}'`
|
|
@@ -991,8 +1031,8 @@ export default class Inibase {
|
|
|
991
1031
|
.split("\n");
|
|
992
1032
|
if (where)
|
|
993
1033
|
lines = lines.slice((options.page - 1) * options.perPage, options.page * options.perPage);
|
|
994
|
-
else if (!this.totalItems
|
|
995
|
-
this.totalItems
|
|
1034
|
+
else if (!this.totalItems.has(`${tableName}-*`))
|
|
1035
|
+
this.totalItems.set(`${tableName}-*`, pagination[1]);
|
|
996
1036
|
if (!lines.length)
|
|
997
1037
|
return null;
|
|
998
1038
|
// Parse the result and extract the specified lines
|
|
@@ -1025,8 +1065,8 @@ export default class Inibase {
|
|
|
1025
1065
|
RETURN = Object.values(await this.processSchemaData(tableName, schema, Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
|
|
1026
1066
|
index +
|
|
1027
1067
|
1), options));
|
|
1028
|
-
if (!this.totalItems
|
|
1029
|
-
this.totalItems
|
|
1068
|
+
if (!this.totalItems.has(`${tableName}-*`))
|
|
1069
|
+
this.totalItems.set(`${tableName}-*`, pagination[1]);
|
|
1030
1070
|
}
|
|
1031
1071
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1032
1072
|
Utils.isNumber(where)) {
|
|
@@ -1034,8 +1074,8 @@ export default class Inibase {
|
|
|
1034
1074
|
let lineNumbers = where;
|
|
1035
1075
|
if (!Array.isArray(lineNumbers))
|
|
1036
1076
|
lineNumbers = [lineNumbers];
|
|
1037
|
-
if (!this.totalItems
|
|
1038
|
-
this.totalItems
|
|
1077
|
+
if (!this.totalItems.has(`${tableName}-*`))
|
|
1078
|
+
this.totalItems.set(`${tableName}-*`, lineNumbers.length);
|
|
1039
1079
|
// useless
|
|
1040
1080
|
if (onlyLinesNumbers)
|
|
1041
1081
|
return lineNumbers;
|
|
@@ -1048,11 +1088,11 @@ export default class Inibase {
|
|
|
1048
1088
|
let Ids = where;
|
|
1049
1089
|
if (!Array.isArray(Ids))
|
|
1050
1090
|
Ids = [Ids];
|
|
1051
|
-
const [lineNumbers, countItems] = await File.search(join(tablePath, `id${this.getFileExtension(tableName)}`), "[]", Ids.map((id) => Utils.isNumber(id) ? Number(id) : UtilsServer.decodeID(id, this.salt)), undefined, undefined, "number", undefined, Ids.length, 0, !this.totalItems
|
|
1091
|
+
const [lineNumbers, countItems] = await File.search(join(tablePath, `id${this.getFileExtension(tableName)}`), "[]", Ids.map((id) => Utils.isNumber(id) ? Number(id) : UtilsServer.decodeID(id, this.salt)), undefined, undefined, "number", undefined, Ids.length, 0, !this.totalItems.has(`${tableName}-*`), this.salt);
|
|
1052
1092
|
if (!lineNumbers)
|
|
1053
1093
|
return null;
|
|
1054
|
-
if (!this.totalItems
|
|
1055
|
-
this.totalItems
|
|
1094
|
+
if (!this.totalItems.has(`${tableName}-*`))
|
|
1095
|
+
this.totalItems.set(`${tableName}-*`, countItems);
|
|
1056
1096
|
if (onlyLinesNumbers)
|
|
1057
1097
|
return Object.keys(lineNumbers).length
|
|
1058
1098
|
? Object.keys(lineNumbers).map(Number)
|
|
@@ -1069,13 +1109,13 @@ export default class Inibase {
|
|
|
1069
1109
|
else if (Utils.isObject(where)) {
|
|
1070
1110
|
let cachedFilePath = "";
|
|
1071
1111
|
// Criteria
|
|
1072
|
-
if (this.
|
|
1112
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1073
1113
|
cachedFilePath = join(tablePath, ".cache", `${UtilsServer.hashString(inspect(where, { sorted: true }))}${this.fileExtension}`);
|
|
1074
|
-
if (this.
|
|
1114
|
+
if (this.tablesMap.get(tableName).config.cache &&
|
|
1075
1115
|
(await File.isExists(cachedFilePath))) {
|
|
1076
1116
|
const cachedItems = (await readFile(cachedFilePath, "utf8")).split(",");
|
|
1077
|
-
if (!this.totalItems
|
|
1078
|
-
this.totalItems
|
|
1117
|
+
if (!this.totalItems.has(`${tableName}-*`))
|
|
1118
|
+
this.totalItems.set(`${tableName}-*`, cachedItems.length);
|
|
1079
1119
|
if (onlyLinesNumbers)
|
|
1080
1120
|
return onlyOne ? Number(cachedItems[0]) : cachedItems.map(Number);
|
|
1081
1121
|
return this.get(tableName, cachedItems
|
|
@@ -1085,8 +1125,8 @@ export default class Inibase {
|
|
|
1085
1125
|
let linesNumbers = null;
|
|
1086
1126
|
[RETURN, linesNumbers] = await this.applyCriteria(tableName, schema, options, where);
|
|
1087
1127
|
if (RETURN && linesNumbers?.size) {
|
|
1088
|
-
if (!this.totalItems
|
|
1089
|
-
this.totalItems
|
|
1128
|
+
if (!this.totalItems.has(`${tableName}-*`))
|
|
1129
|
+
this.totalItems.set(`${tableName}-*`, linesNumbers.size);
|
|
1090
1130
|
if (onlyLinesNumbers)
|
|
1091
1131
|
return onlyOne
|
|
1092
1132
|
? linesNumbers.values().next().value
|
|
@@ -1096,7 +1136,7 @@ export default class Inibase {
|
|
|
1096
1136
|
.map(({ id }) => id);
|
|
1097
1137
|
RETURN = Object.values(Utils.deepMerge(RETURN, await this.processSchemaData(tableName, Utils.filterSchema(schema, ({ id, type, children }) => !alreadyExistsColumnsIDs.includes(id) ||
|
|
1098
1138
|
Utils.isFieldType("table", type, children)), Object.keys(RETURN).map(Number), options)));
|
|
1099
|
-
if (this.
|
|
1139
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1100
1140
|
await writeFile(cachedFilePath, Array.from(linesNumbers).join(","));
|
|
1101
1141
|
}
|
|
1102
1142
|
}
|
|
@@ -1104,8 +1144,9 @@ export default class Inibase {
|
|
|
1104
1144
|
(Utils.isObject(RETURN) && !Object.keys(RETURN).length) ||
|
|
1105
1145
|
(Array.isArray(RETURN) && !RETURN.length))
|
|
1106
1146
|
return null;
|
|
1107
|
-
const greatestTotalItems = this.totalItems
|
|
1108
|
-
|
|
1147
|
+
const greatestTotalItems = this.totalItems.has(`${tableName}-*`)
|
|
1148
|
+
? this.totalItems.get(`${tableName}-*`)
|
|
1149
|
+
: Math.max(...[...this.totalItems.entries()]
|
|
1109
1150
|
.filter(([k]) => k.startsWith(`${tableName}-`))
|
|
1110
1151
|
.map(([, v]) => v));
|
|
1111
1152
|
this.pageInfo[tableName] = {
|
|
@@ -1122,24 +1163,24 @@ export default class Inibase {
|
|
|
1122
1163
|
page: 1,
|
|
1123
1164
|
perPage: 15,
|
|
1124
1165
|
};
|
|
1125
|
-
const tablePath = join(this.databasePath, tableName)
|
|
1126
|
-
|
|
1127
|
-
|
|
1166
|
+
const tablePath = join(this.databasePath, tableName);
|
|
1167
|
+
await this.getTable(tableName);
|
|
1168
|
+
if (!this.tablesMap.get(tableName).schema)
|
|
1169
|
+
throw this.createError("NO_SCHEMA", tableName);
|
|
1128
1170
|
if (!returnPostedData)
|
|
1129
1171
|
returnPostedData = false;
|
|
1130
1172
|
const keys = UtilsServer.hashString(Object.keys(Array.isArray(data) ? data[0] : data).join("."));
|
|
1131
|
-
|
|
1132
|
-
this.validateData(data, schema.slice(1, -2));
|
|
1133
|
-
let lastId = 0;
|
|
1173
|
+
await this.validateData(tableName, data);
|
|
1134
1174
|
const renameList = [];
|
|
1135
1175
|
try {
|
|
1136
1176
|
await File.lock(join(tablePath, ".tmp"), keys);
|
|
1137
1177
|
let paginationFilePath;
|
|
1138
1178
|
for await (const fileName of glob("*.pagination", { cwd: tablePath }))
|
|
1139
1179
|
paginationFilePath = join(tablePath, fileName);
|
|
1140
|
-
[lastId,
|
|
1180
|
+
let [lastId, _totalItems] = parse(paginationFilePath)
|
|
1141
1181
|
.name.split("-")
|
|
1142
1182
|
.map(Number);
|
|
1183
|
+
this.totalItems.set(`${tableName}-*`, _totalItems);
|
|
1143
1184
|
if (Utils.isArrayOfObjects(data))
|
|
1144
1185
|
for (let index = 0; index < data.length; index++) {
|
|
1145
1186
|
const element = data[index];
|
|
@@ -1152,35 +1193,33 @@ export default class Inibase {
|
|
|
1152
1193
|
data.createdAt = Date.now();
|
|
1153
1194
|
data.updatedAt = undefined;
|
|
1154
1195
|
}
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
const pathesContents = this.joinPathesContents(tableName, this.tables[tableName].config.prepend
|
|
1196
|
+
this.formatData(tableName, data);
|
|
1197
|
+
const pathesContents = this.joinPathesContents(tableName, this.tablesMap.get(tableName).config.prepend
|
|
1158
1198
|
? Array.isArray(data)
|
|
1159
1199
|
? data.toReversed()
|
|
1160
1200
|
: data
|
|
1161
1201
|
: data);
|
|
1162
|
-
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(this.
|
|
1202
|
+
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(this.tablesMap.get(tableName).config.prepend
|
|
1163
1203
|
? await File.prepend(path, content)
|
|
1164
1204
|
: await File.append(path, content))));
|
|
1165
1205
|
await Promise.allSettled(renameList
|
|
1166
1206
|
.filter(([_, filePath]) => filePath)
|
|
1167
1207
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1168
|
-
if (this.
|
|
1208
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1169
1209
|
await this.clearCache(tableName);
|
|
1170
|
-
this.totalItems
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
await rename(paginationFilePath, join(tablePath, `${lastId}-${this.totalItems[`${tableName}-*`]}.pagination`));
|
|
1210
|
+
const currentValue = this.totalItems.get(`${tableName}-*`) || 0;
|
|
1211
|
+
this.totalItems.set(`${tableName}-*`, currentValue + (Array.isArray(data) ? data.length : 1));
|
|
1212
|
+
await rename(paginationFilePath, join(tablePath, `${lastId}-${this.totalItems.get(`${tableName}-*`)}.pagination`));
|
|
1174
1213
|
if (returnPostedData)
|
|
1175
|
-
return this.get(tableName, this.
|
|
1214
|
+
return this.get(tableName, this.tablesMap.get(tableName).config.prepend
|
|
1176
1215
|
? Array.isArray(data)
|
|
1177
1216
|
? data.map((_, index) => index + 1).toReversed()
|
|
1178
1217
|
: 1
|
|
1179
1218
|
: Array.isArray(data)
|
|
1180
1219
|
? data
|
|
1181
|
-
.map((_, index) => this.totalItems
|
|
1220
|
+
.map((_, index) => this.totalItems.get(`${tableName}-*`) - index)
|
|
1182
1221
|
.toReversed()
|
|
1183
|
-
: this.totalItems
|
|
1222
|
+
: this.totalItems.get(`${tableName}-*`), options, !Utils.isArrayOfObjects(data));
|
|
1184
1223
|
}
|
|
1185
1224
|
finally {
|
|
1186
1225
|
if (renameList.length)
|
|
@@ -1194,23 +1233,20 @@ export default class Inibase {
|
|
|
1194
1233
|
}, returnUpdatedData) {
|
|
1195
1234
|
const renameList = [];
|
|
1196
1235
|
const tablePath = join(this.databasePath, tableName);
|
|
1197
|
-
|
|
1198
|
-
.schema;
|
|
1236
|
+
await this.throwErrorIfTableEmpty(tableName);
|
|
1199
1237
|
if (!where) {
|
|
1200
1238
|
if (Utils.isArrayOfObjects(data)) {
|
|
1201
1239
|
if (!data.every((item) => Object.hasOwn(item, "id") && Utils.isValidID(item.id)))
|
|
1202
|
-
throw this.
|
|
1240
|
+
throw this.createError("INVALID_ID");
|
|
1203
1241
|
return this.put(tableName, data, data.map(({ id }) => id), options, returnUpdatedData || undefined);
|
|
1204
1242
|
}
|
|
1205
1243
|
if (Object.hasOwn(data, "id")) {
|
|
1206
1244
|
if (!Utils.isValidID(data.id))
|
|
1207
|
-
throw this.
|
|
1245
|
+
throw this.createError("INVALID_ID", data.id);
|
|
1208
1246
|
return this.put(tableName, data, data.id, options, returnUpdatedData || undefined);
|
|
1209
1247
|
}
|
|
1210
|
-
|
|
1211
|
-
this.
|
|
1212
|
-
await this.checkUnique(tableName, schema);
|
|
1213
|
-
data = this.formatData(data, schema, true);
|
|
1248
|
+
await this.validateData(tableName, data, true);
|
|
1249
|
+
this.formatData(tableName, data, true);
|
|
1214
1250
|
const pathesContents = this.joinPathesContents(tableName, {
|
|
1215
1251
|
...(({ id, ...restOfData }) => restOfData)(data),
|
|
1216
1252
|
updatedAt: Date.now(),
|
|
@@ -1220,14 +1256,12 @@ export default class Inibase {
|
|
|
1220
1256
|
for await (const paginationFileName of glob("*.pagination", {
|
|
1221
1257
|
cwd: tablePath,
|
|
1222
1258
|
}))
|
|
1223
|
-
this.totalItems
|
|
1224
|
-
|
|
1225
|
-
.map(Number)[1];
|
|
1226
|
-
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(await File.replace(path, content, this.totalItems[`${tableName}-*`]))));
|
|
1259
|
+
this.totalItems.set(`${tableName}-*`, parse(paginationFileName).name.split("-").map(Number)[1]);
|
|
1260
|
+
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(await File.replace(path, content, this.totalItems.get(`${tableName}-*`)))));
|
|
1227
1261
|
await Promise.allSettled(renameList
|
|
1228
1262
|
.filter(([_, filePath]) => filePath)
|
|
1229
1263
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1230
|
-
if (this.
|
|
1264
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1231
1265
|
await this.clearCache(join(tablePath, ".cache"));
|
|
1232
1266
|
if (returnUpdatedData)
|
|
1233
1267
|
return await this.get(tableName, undefined, options);
|
|
@@ -1246,9 +1280,8 @@ export default class Inibase {
|
|
|
1246
1280
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1247
1281
|
Utils.isNumber(where)) {
|
|
1248
1282
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1249
|
-
this.validateData(
|
|
1250
|
-
|
|
1251
|
-
data = this.formatData(data, schema, true);
|
|
1283
|
+
await this.validateData(tableName, data, true);
|
|
1284
|
+
this.formatData(tableName, data, true);
|
|
1252
1285
|
const pathesContents = Object.fromEntries(Object.entries(this.joinPathesContents(tableName, Utils.isArrayOfObjects(data)
|
|
1253
1286
|
? data.map((item) => ({
|
|
1254
1287
|
...item,
|
|
@@ -1269,7 +1302,7 @@ export default class Inibase {
|
|
|
1269
1302
|
await Promise.allSettled(renameList
|
|
1270
1303
|
.filter(([_, filePath]) => filePath)
|
|
1271
1304
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1272
|
-
if (this.
|
|
1305
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1273
1306
|
await this.clearCache(tableName);
|
|
1274
1307
|
if (returnUpdatedData)
|
|
1275
1308
|
return this.get(tableName, where, options, !Array.isArray(where));
|
|
@@ -1286,7 +1319,7 @@ export default class Inibase {
|
|
|
1286
1319
|
return this.put(tableName, data, lineNumbers, options, returnUpdatedData || undefined);
|
|
1287
1320
|
}
|
|
1288
1321
|
else
|
|
1289
|
-
throw this.
|
|
1322
|
+
throw this.createError("INVALID_PARAMETERS");
|
|
1290
1323
|
}
|
|
1291
1324
|
/**
|
|
1292
1325
|
* Delete item(s) in a table
|
|
@@ -1314,7 +1347,7 @@ export default class Inibase {
|
|
|
1314
1347
|
await Promise.all((await readdir(tablePath))
|
|
1315
1348
|
?.filter((fileName) => fileName.endsWith(this.getFileExtension(tableName)))
|
|
1316
1349
|
.map(async (file) => unlink(join(tablePath, file))));
|
|
1317
|
-
if (this.
|
|
1350
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1318
1351
|
await this.clearCache(tableName);
|
|
1319
1352
|
await rename(paginationFilePath, join(tablePath, `${pagination[0]}-0.pagination`));
|
|
1320
1353
|
return true;
|
|
@@ -1357,7 +1390,7 @@ export default class Inibase {
|
|
|
1357
1390
|
await Promise.all((await readdir(tablePath))
|
|
1358
1391
|
?.filter((fileName) => fileName.endsWith(this.getFileExtension(tableName)))
|
|
1359
1392
|
.map(async (file) => unlink(join(tablePath, file))));
|
|
1360
|
-
if (this.
|
|
1393
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1361
1394
|
await this.clearCache(tableName);
|
|
1362
1395
|
await rename(paginationFilePath, join(tablePath, `${pagination[0]}-${pagination[1] - (Array.isArray(where) ? where.length : 1)}.pagination`));
|
|
1363
1396
|
return true;
|
|
@@ -1375,7 +1408,7 @@ export default class Inibase {
|
|
|
1375
1408
|
return this.delete(tableName, lineNumbers);
|
|
1376
1409
|
}
|
|
1377
1410
|
else
|
|
1378
|
-
throw this.
|
|
1411
|
+
throw this.createError("INVALID_PARAMETERS");
|
|
1379
1412
|
return false;
|
|
1380
1413
|
}
|
|
1381
1414
|
async sum(tableName, columns, where) {
|
package/dist/utils.server.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { exec as execSync, execFile as execFileSync } from "node:child_process";
|
|
2
2
|
import { gunzip as gunzipSync, gzip as gzipSync } from "node:zlib";
|
|
3
3
|
import type { ComparisonOperator, Field, FieldType, Schema } from "./index.js";
|
|
4
|
+
import RE2 from "re2";
|
|
4
5
|
export declare const exec: typeof execSync.__promisify__;
|
|
5
6
|
export declare const execFile: typeof execFileSync.__promisify__;
|
|
6
7
|
export declare const gzip: typeof gzipSync.__promisify__;
|
|
@@ -83,3 +84,15 @@ export declare const isArrayEqual: (originalValue: string | number | boolean | n
|
|
|
83
84
|
* @returns boolean - Result of the wildcard pattern matching.
|
|
84
85
|
*/
|
|
85
86
|
export declare const isWildcardMatch: (originalValue: string | number | boolean | null | (string | number | boolean | null)[], comparedValue: string | number | boolean | null | (string | number | boolean | null)[]) => boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Retrieves a cached compiled regex or compiles and caches a new one.
|
|
89
|
+
*
|
|
90
|
+
* This function checks if a given regex pattern is already compiled and cached.
|
|
91
|
+
* If it is, the cached instance is returned. If not, the function attempts to compile
|
|
92
|
+
* the regex using RE2, caches the compiled instance, and then returns it. If the pattern
|
|
93
|
+
* is invalid, it returns a fallback object with a `test` method that always returns `false`.
|
|
94
|
+
*
|
|
95
|
+
* @param {string} pattern - The regex pattern to compile or retrieve from the cache.
|
|
96
|
+
* @returns {RE2} - The compiled regex instance or a fallback object on error.
|
|
97
|
+
*/
|
|
98
|
+
export declare const getCachedRegex: (pattern: string) => RE2;
|
package/dist/utils.server.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createCipheriv, createDecipheriv, createHash, randomBytes, scryptSync,
|
|
|
3
3
|
import { gunzip as gunzipSync, gzip as gzipSync } from "node:zlib";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import { detectFieldType, isArrayOfObjects, isNumber, isPassword, isValidID, } from "./utils.js";
|
|
6
|
+
import RE2 from "re2";
|
|
6
7
|
export const exec = promisify(execSync);
|
|
7
8
|
export const execFile = promisify(execFileSync);
|
|
8
9
|
export const gzip = promisify(gzipSync);
|
|
@@ -247,3 +248,28 @@ export const isWildcardMatch = (originalValue, comparedValue) => {
|
|
|
247
248
|
const wildcardPattern = `^${(comparedValueStr.includes("%") ? comparedValueStr : `%${comparedValueStr}%`).replace(/%/g, ".*")}$`;
|
|
248
249
|
return new RegExp(wildcardPattern, "i").test(originalValueStr);
|
|
249
250
|
};
|
|
251
|
+
const regexCache = new Map();
|
|
252
|
+
/**
|
|
253
|
+
* Retrieves a cached compiled regex or compiles and caches a new one.
|
|
254
|
+
*
|
|
255
|
+
* This function checks if a given regex pattern is already compiled and cached.
|
|
256
|
+
* If it is, the cached instance is returned. If not, the function attempts to compile
|
|
257
|
+
* the regex using RE2, caches the compiled instance, and then returns it. If the pattern
|
|
258
|
+
* is invalid, it returns a fallback object with a `test` method that always returns `false`.
|
|
259
|
+
*
|
|
260
|
+
* @param {string} pattern - The regex pattern to compile or retrieve from the cache.
|
|
261
|
+
* @returns {RE2} - The compiled regex instance or a fallback object on error.
|
|
262
|
+
*/
|
|
263
|
+
export const getCachedRegex = (pattern) => {
|
|
264
|
+
if (regexCache.has(pattern)) {
|
|
265
|
+
return regexCache.get(pattern);
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
const compiledRegex = new RE2(pattern);
|
|
269
|
+
regexCache.set(pattern, compiledRegex);
|
|
270
|
+
return compiledRegex;
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
return { test: (_str) => false };
|
|
274
|
+
}
|
|
275
|
+
};
|
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.121",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Karim Amahtil",
|
|
@@ -70,12 +70,13 @@
|
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/bun": "^1.1.10",
|
|
72
72
|
"@types/node": "^22.7.4",
|
|
73
|
-
"tinybench": "^
|
|
74
|
-
"typescript": "^5.
|
|
73
|
+
"tinybench": "^3.0.7",
|
|
74
|
+
"typescript": "^5.7.2"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
77
|
"dotenv": "^16.4.5",
|
|
78
|
-
"inison": "latest"
|
|
78
|
+
"inison": "latest",
|
|
79
|
+
"re2": "^1.21.4"
|
|
79
80
|
},
|
|
80
81
|
"scripts": {
|
|
81
82
|
"prepublish": "npx tsc",
|