inibase 1.0.0-rc.120 → 1.0.0-rc.122
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 -133
- 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,42 @@ 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 = {};
|
|
25
|
-
this.pageInfo = {};
|
|
26
|
-
this.checkIFunique = {};
|
|
23
|
+
this.clear();
|
|
27
24
|
if (!process.env.INIBASE_SECRET) {
|
|
28
25
|
if (existsSync(".env") &&
|
|
29
26
|
readFileSync(".env").includes("INIBASE_SECRET="))
|
|
30
|
-
throw this.
|
|
27
|
+
throw this.createError("NO_ENV");
|
|
31
28
|
this.salt = scryptSync(randomBytes(16), randomBytes(16), 32);
|
|
32
29
|
appendFileSync(".env", `\nINIBASE_SECRET=${this.salt.toString("hex")}\n`);
|
|
33
30
|
}
|
|
34
31
|
else
|
|
35
32
|
this.salt = Buffer.from(process.env.INIBASE_SECRET, "hex");
|
|
36
33
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const errorMessage = errorMessages[language][code];
|
|
34
|
+
static errorMessages = {
|
|
35
|
+
en: {
|
|
36
|
+
TABLE_EMPTY: "Table {variable} is empty",
|
|
37
|
+
TABLE_EXISTS: "Table {variable} already exists",
|
|
38
|
+
TABLE_NOT_EXISTS: "Table {variable} doesn't exist",
|
|
39
|
+
NO_SCHEMA: "Table {variable} does't have a schema",
|
|
40
|
+
FIELD_UNIQUE: "Field {variable} should be unique, got {variable} instead",
|
|
41
|
+
FIELD_REQUIRED: "Field {variable} is required",
|
|
42
|
+
INVALID_ID: "The given ID(s) is/are not valid(s)",
|
|
43
|
+
INVALID_TYPE: "Expect {variable} to be {variable}, got {variable} instead",
|
|
44
|
+
INVALID_PARAMETERS: "The given parameters are not valid",
|
|
45
|
+
INVALID_REGEX_MATCH: "Field {variable} does not match the expected pattern",
|
|
46
|
+
NO_ENV: Number(process.versions.node.split(".").reduce((a, b) => a + b)) >= 26
|
|
47
|
+
? "please run with '--env-file=.env'"
|
|
48
|
+
: "please use dotenv",
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
createError(code, variable, language = "en") {
|
|
52
|
+
const errorMessage = Inibase.errorMessages[language]?.[code];
|
|
56
53
|
if (!errorMessage)
|
|
57
54
|
return new Error("ERR");
|
|
58
55
|
return new Error(variable
|
|
@@ -62,17 +59,17 @@ export default class Inibase {
|
|
|
62
59
|
: errorMessage.replaceAll("{variable}", ""));
|
|
63
60
|
}
|
|
64
61
|
clear() {
|
|
65
|
-
this.
|
|
66
|
-
this.totalItems =
|
|
62
|
+
this.tablesMap = new Map();
|
|
63
|
+
this.totalItems = new Map();
|
|
67
64
|
this.pageInfo = {};
|
|
68
|
-
this.
|
|
65
|
+
this.uniqueMap = new Map();
|
|
69
66
|
}
|
|
70
67
|
getFileExtension(tableName) {
|
|
71
68
|
let mainExtension = this.fileExtension;
|
|
72
69
|
// TODO: ADD ENCRYPTION
|
|
73
|
-
// if(this.
|
|
70
|
+
// if(this.tablesMap.get(tableName).config.encryption)
|
|
74
71
|
// mainExtension += ".enc"
|
|
75
|
-
if (this.
|
|
72
|
+
if (this.tablesMap.get(tableName).config.compression)
|
|
76
73
|
mainExtension += ".gz";
|
|
77
74
|
return mainExtension;
|
|
78
75
|
}
|
|
@@ -99,7 +96,7 @@ export default class Inibase {
|
|
|
99
96
|
async createTable(tableName, schema, config) {
|
|
100
97
|
const tablePath = join(this.databasePath, tableName);
|
|
101
98
|
if (await File.isExists(tablePath))
|
|
102
|
-
throw this.
|
|
99
|
+
throw this.createError("TABLE_EXISTS", tableName);
|
|
103
100
|
await mkdir(join(tablePath, ".tmp"), { recursive: true });
|
|
104
101
|
await mkdir(join(tablePath, ".cache"));
|
|
105
102
|
// if config not set => load default global env config
|
|
@@ -142,7 +139,8 @@ export default class Inibase {
|
|
|
142
139
|
* @param {(Config&{name?: string})} [config]
|
|
143
140
|
*/
|
|
144
141
|
async updateTable(tableName, schema, config) {
|
|
145
|
-
const table = await this.getTable(tableName)
|
|
142
|
+
const table = await this.getTable(tableName);
|
|
143
|
+
const tablePath = join(this.databasePath, tableName);
|
|
146
144
|
if (schema) {
|
|
147
145
|
// remove id from schema
|
|
148
146
|
schema = schema.filter(({ key }) => !["id", "createdAt", "updatedAt"].includes(key));
|
|
@@ -232,7 +230,7 @@ export default class Inibase {
|
|
|
232
230
|
await this.replaceStringInFile(schemaPath, `"table": "${tableName}"`, `"table": "${config.name}"`);
|
|
233
231
|
}
|
|
234
232
|
}
|
|
235
|
-
|
|
233
|
+
this.tablesMap.delete(tableName);
|
|
236
234
|
}
|
|
237
235
|
/**
|
|
238
236
|
* Get table schema and config
|
|
@@ -240,20 +238,20 @@ export default class Inibase {
|
|
|
240
238
|
* @param {string} tableName
|
|
241
239
|
* @return {*} {Promise<TableObject>}
|
|
242
240
|
*/
|
|
243
|
-
async getTable(tableName) {
|
|
241
|
+
async getTable(tableName, encodeIDs = true) {
|
|
244
242
|
const tablePath = join(this.databasePath, tableName);
|
|
245
243
|
if (!(await File.isExists(tablePath)))
|
|
246
|
-
throw this.
|
|
247
|
-
if (!this.
|
|
248
|
-
this.
|
|
249
|
-
schema: await this.getTableSchema(tableName),
|
|
244
|
+
throw this.createError("TABLE_NOT_EXISTS", tableName);
|
|
245
|
+
if (!this.tablesMap.has(tableName))
|
|
246
|
+
this.tablesMap.set(tableName, {
|
|
247
|
+
schema: await this.getTableSchema(tableName, encodeIDs),
|
|
250
248
|
config: {
|
|
251
249
|
compression: await File.isExists(join(tablePath, ".compression.config")),
|
|
252
250
|
cache: await File.isExists(join(tablePath, ".cache.config")),
|
|
253
251
|
prepend: await File.isExists(join(tablePath, ".prepend.config")),
|
|
254
252
|
},
|
|
255
|
-
};
|
|
256
|
-
return this.
|
|
253
|
+
});
|
|
254
|
+
return this.tablesMap.get(tableName);
|
|
257
255
|
}
|
|
258
256
|
async getTableSchema(tableName, encodeIDs = true) {
|
|
259
257
|
const tablePath = join(this.databasePath, tableName);
|
|
@@ -288,17 +286,16 @@ export default class Inibase {
|
|
|
288
286
|
return UtilsServer.encodeSchemaID(schema, this.salt);
|
|
289
287
|
}
|
|
290
288
|
async throwErrorIfTableEmpty(tableName) {
|
|
291
|
-
const table = await this.getTable(tableName);
|
|
289
|
+
const table = await this.getTable(tableName, false);
|
|
292
290
|
if (!table.schema)
|
|
293
|
-
throw this.
|
|
291
|
+
throw this.createError("NO_SCHEMA", tableName);
|
|
294
292
|
if (!(await File.isExists(join(this.databasePath, tableName, `id${this.getFileExtension(tableName)}`))))
|
|
295
|
-
throw this.
|
|
296
|
-
return table;
|
|
293
|
+
throw this.createError("TABLE_EMPTY", tableName);
|
|
297
294
|
}
|
|
298
|
-
|
|
295
|
+
_validateData(data, schema, skipRequiredField = false) {
|
|
299
296
|
if (Utils.isArrayOfObjects(data))
|
|
300
297
|
for (const single_data of data)
|
|
301
|
-
this.
|
|
298
|
+
this._validateData(single_data, schema, skipRequiredField);
|
|
302
299
|
else if (Utils.isObject(data)) {
|
|
303
300
|
for (const field of schema) {
|
|
304
301
|
if (!Object.hasOwn(data, field.key) ||
|
|
@@ -306,7 +303,7 @@ export default class Inibase {
|
|
|
306
303
|
data[field.key] === undefined ||
|
|
307
304
|
data[field.key] === "") {
|
|
308
305
|
if (field.required && !skipRequiredField)
|
|
309
|
-
throw this.
|
|
306
|
+
throw this.createError("FIELD_REQUIRED", field.key);
|
|
310
307
|
return;
|
|
311
308
|
}
|
|
312
309
|
if (!Utils.validateFieldType(data[field.key], field.type, (field.type === "array" || field.type === "object") &&
|
|
@@ -314,7 +311,7 @@ export default class Inibase {
|
|
|
314
311
|
!Utils.isArrayOfObjects(field.children)
|
|
315
312
|
? field.children
|
|
316
313
|
: undefined))
|
|
317
|
-
throw this.
|
|
314
|
+
throw this.createError("INVALID_TYPE", [
|
|
318
315
|
field.key,
|
|
319
316
|
Array.isArray(field.type) ? field.type.join(", ") : field.type,
|
|
320
317
|
data[field.key],
|
|
@@ -322,15 +319,46 @@ export default class Inibase {
|
|
|
322
319
|
if ((field.type === "array" || field.type === "object") &&
|
|
323
320
|
field.children &&
|
|
324
321
|
Utils.isArrayOfObjects(field.children))
|
|
325
|
-
this.
|
|
326
|
-
else
|
|
327
|
-
if (
|
|
328
|
-
|
|
329
|
-
|
|
322
|
+
this._validateData(data[field.key], field.children, skipRequiredField);
|
|
323
|
+
else {
|
|
324
|
+
if (field.regex) {
|
|
325
|
+
const regex = UtilsServer.getCachedRegex(field.regex);
|
|
326
|
+
if (!regex.test(data[field.key]))
|
|
327
|
+
throw this.createError("INVALID_REGEX_MATCH", [field.key]);
|
|
328
|
+
}
|
|
329
|
+
if (field.unique) {
|
|
330
|
+
let uniqueKey;
|
|
331
|
+
if (typeof field.unique === "boolean")
|
|
332
|
+
uniqueKey = randomInt(55);
|
|
333
|
+
else
|
|
334
|
+
uniqueKey = field.unique;
|
|
335
|
+
if (!this.uniqueMap.has(uniqueKey))
|
|
336
|
+
this.uniqueMap.set(uniqueKey, {
|
|
337
|
+
exclude: new Set(),
|
|
338
|
+
columnsValues: new Map(),
|
|
339
|
+
});
|
|
340
|
+
if (!this.uniqueMap
|
|
341
|
+
.get(uniqueKey)
|
|
342
|
+
.columnsValues.has(field.id))
|
|
343
|
+
this.uniqueMap
|
|
344
|
+
.get(uniqueKey)
|
|
345
|
+
.columnsValues.set(field.id, new Set());
|
|
346
|
+
if (data.id)
|
|
347
|
+
this.uniqueMap.get(uniqueKey).exclude.add(-data.id);
|
|
348
|
+
this.uniqueMap
|
|
349
|
+
.get(uniqueKey)
|
|
350
|
+
.columnsValues.get(field.id)
|
|
351
|
+
.add(data[field.key]);
|
|
352
|
+
}
|
|
330
353
|
}
|
|
331
354
|
}
|
|
332
355
|
}
|
|
333
356
|
}
|
|
357
|
+
async validateData(tableName, data, skipRequiredField = false) {
|
|
358
|
+
// Skip ID and (created|updated)At
|
|
359
|
+
this._validateData(data, this.tablesMap.get(tableName).schema.slice(1, -2), skipRequiredField);
|
|
360
|
+
await this.checkUnique(tableName);
|
|
361
|
+
}
|
|
334
362
|
cleanObject(obj) {
|
|
335
363
|
const cleanedObject = Object.entries(obj).reduce((acc, [key, value]) => {
|
|
336
364
|
if (value !== undefined && value !== null && value !== "")
|
|
@@ -353,13 +381,13 @@ export default class Inibase {
|
|
|
353
381
|
if (!Array.isArray(value))
|
|
354
382
|
value = [value];
|
|
355
383
|
if (Utils.isArrayOfObjects(fieldChildrenType))
|
|
356
|
-
return this.
|
|
384
|
+
return this._formatData(value, fieldChildrenType);
|
|
357
385
|
if (!value.length)
|
|
358
386
|
return null;
|
|
359
387
|
return value.map((_value) => this.formatField(_value, fieldChildrenType));
|
|
360
388
|
case "object":
|
|
361
389
|
if (Utils.isArrayOfObjects(fieldChildrenType))
|
|
362
|
-
return this.
|
|
390
|
+
return this._formatData(value, fieldChildrenType, _formatOnlyAvailiableKeys);
|
|
363
391
|
break;
|
|
364
392
|
case "table":
|
|
365
393
|
if (Utils.isObject(value)) {
|
|
@@ -402,25 +430,32 @@ export default class Inibase {
|
|
|
402
430
|
}
|
|
403
431
|
return null;
|
|
404
432
|
}
|
|
405
|
-
async checkUnique(tableName
|
|
433
|
+
async checkUnique(tableName) {
|
|
406
434
|
const tablePath = join(this.databasePath, tableName);
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
435
|
+
const flattenSchema = Utils.flattenSchema(this.tablesMap.get(tableName).schema);
|
|
436
|
+
for await (const [_uniqueID, valueObject] of this.uniqueMap) {
|
|
437
|
+
let index = 0;
|
|
438
|
+
for await (const [columnID, values] of valueObject.columnsValues) {
|
|
439
|
+
index++;
|
|
440
|
+
const field = flattenSchema.find(({ id }) => id === columnID);
|
|
441
|
+
const [searchResult, totalLines] = await File.search(join(tablePath, `${field.key}${this.getFileExtension(tableName)}`), "[]", values, undefined, valueObject.exclude, field.type, field.children, 1, undefined, false, this.salt);
|
|
442
|
+
if (searchResult && totalLines > 0) {
|
|
443
|
+
if (index === valueObject.columnsValues.size)
|
|
444
|
+
throw this.createError("FIELD_UNIQUE", [
|
|
445
|
+
field.key,
|
|
446
|
+
Array.isArray(values) ? values.join(", ") : values,
|
|
447
|
+
]);
|
|
448
|
+
}
|
|
449
|
+
else
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
417
452
|
}
|
|
418
|
-
this.
|
|
453
|
+
this.uniqueMap = new Map();
|
|
419
454
|
}
|
|
420
|
-
|
|
455
|
+
_formatData(data, schema, formatOnlyAvailiableKeys) {
|
|
421
456
|
const clonedData = JSON.parse(JSON.stringify(data));
|
|
422
457
|
if (Utils.isArrayOfObjects(clonedData))
|
|
423
|
-
return clonedData.map((singleData) => this.
|
|
458
|
+
return clonedData.map((singleData) => this._formatData(singleData, schema, formatOnlyAvailiableKeys));
|
|
424
459
|
if (Utils.isObject(clonedData)) {
|
|
425
460
|
const RETURN = {};
|
|
426
461
|
for (const field of schema) {
|
|
@@ -436,6 +471,9 @@ export default class Inibase {
|
|
|
436
471
|
}
|
|
437
472
|
return [];
|
|
438
473
|
}
|
|
474
|
+
formatData(tableName, data, formatOnlyAvailiableKeys) {
|
|
475
|
+
data = this._formatData(data, this.tablesMap.get(tableName).schema, formatOnlyAvailiableKeys);
|
|
476
|
+
}
|
|
439
477
|
getDefaultValue(field) {
|
|
440
478
|
if (Array.isArray(field.type))
|
|
441
479
|
return this.getDefaultValue({
|
|
@@ -835,7 +873,7 @@ export default class Inibase {
|
|
|
835
873
|
[key]: value,
|
|
836
874
|
},
|
|
837
875
|
])));
|
|
838
|
-
this.totalItems
|
|
876
|
+
this.totalItems.set(`${tableName}-${key}`, totalLines);
|
|
839
877
|
if (linesNumbers?.size) {
|
|
840
878
|
if (searchIn) {
|
|
841
879
|
for (const lineNumber of linesNumbers)
|
|
@@ -911,9 +949,10 @@ export default class Inibase {
|
|
|
911
949
|
options.page = options.page || 1;
|
|
912
950
|
options.perPage = options.perPage || 15;
|
|
913
951
|
let RETURN;
|
|
952
|
+
await this.getTable(tableName);
|
|
914
953
|
let schema = (await this.getTable(tableName)).schema;
|
|
915
954
|
if (!schema)
|
|
916
|
-
throw this.
|
|
955
|
+
throw this.createError("NO_SCHEMA", tableName);
|
|
917
956
|
let pagination;
|
|
918
957
|
for await (const paginationFileName of glob("*.pagination", {
|
|
919
958
|
cwd: tablePath,
|
|
@@ -942,7 +981,7 @@ export default class Inibase {
|
|
|
942
981
|
.map((column) => [column, true]);
|
|
943
982
|
let cacheKey = "";
|
|
944
983
|
// Criteria
|
|
945
|
-
if (this.
|
|
984
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
946
985
|
cacheKey = UtilsServer.hashString(inspect(sortArray, { sorted: true }));
|
|
947
986
|
if (where) {
|
|
948
987
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
|
|
@@ -980,7 +1019,7 @@ export default class Inibase {
|
|
|
980
1019
|
if (cacheKey)
|
|
981
1020
|
await File.lock(join(tablePath, ".tmp"), cacheKey);
|
|
982
1021
|
// Combine && Execute the commands synchronously
|
|
983
|
-
let lines = (await UtilsServer.exec(this.
|
|
1022
|
+
let lines = (await UtilsServer.exec(this.tablesMap.get(tableName).config.cache
|
|
984
1023
|
? (await File.isExists(join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)))
|
|
985
1024
|
? `${awkCommand} '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}'`
|
|
986
1025
|
: `${pasteCommand} | ${sortCommand} -o '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}' && ${awkCommand} '${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}'`
|
|
@@ -991,8 +1030,8 @@ export default class Inibase {
|
|
|
991
1030
|
.split("\n");
|
|
992
1031
|
if (where)
|
|
993
1032
|
lines = lines.slice((options.page - 1) * options.perPage, options.page * options.perPage);
|
|
994
|
-
else if (!this.totalItems
|
|
995
|
-
this.totalItems
|
|
1033
|
+
else if (!this.totalItems.has(`${tableName}-*`))
|
|
1034
|
+
this.totalItems.set(`${tableName}-*`, pagination[1]);
|
|
996
1035
|
if (!lines.length)
|
|
997
1036
|
return null;
|
|
998
1037
|
// Parse the result and extract the specified lines
|
|
@@ -1025,8 +1064,8 @@ export default class Inibase {
|
|
|
1025
1064
|
RETURN = Object.values(await this.processSchemaData(tableName, schema, Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
|
|
1026
1065
|
index +
|
|
1027
1066
|
1), options));
|
|
1028
|
-
if (!this.totalItems
|
|
1029
|
-
this.totalItems
|
|
1067
|
+
if (!this.totalItems.has(`${tableName}-*`))
|
|
1068
|
+
this.totalItems.set(`${tableName}-*`, pagination[1]);
|
|
1030
1069
|
}
|
|
1031
1070
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1032
1071
|
Utils.isNumber(where)) {
|
|
@@ -1034,8 +1073,8 @@ export default class Inibase {
|
|
|
1034
1073
|
let lineNumbers = where;
|
|
1035
1074
|
if (!Array.isArray(lineNumbers))
|
|
1036
1075
|
lineNumbers = [lineNumbers];
|
|
1037
|
-
if (!this.totalItems
|
|
1038
|
-
this.totalItems
|
|
1076
|
+
if (!this.totalItems.has(`${tableName}-*`))
|
|
1077
|
+
this.totalItems.set(`${tableName}-*`, lineNumbers.length);
|
|
1039
1078
|
// useless
|
|
1040
1079
|
if (onlyLinesNumbers)
|
|
1041
1080
|
return lineNumbers;
|
|
@@ -1048,11 +1087,11 @@ export default class Inibase {
|
|
|
1048
1087
|
let Ids = where;
|
|
1049
1088
|
if (!Array.isArray(Ids))
|
|
1050
1089
|
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
|
|
1090
|
+
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
1091
|
if (!lineNumbers)
|
|
1053
1092
|
return null;
|
|
1054
|
-
if (!this.totalItems
|
|
1055
|
-
this.totalItems
|
|
1093
|
+
if (!this.totalItems.has(`${tableName}-*`))
|
|
1094
|
+
this.totalItems.set(`${tableName}-*`, countItems);
|
|
1056
1095
|
if (onlyLinesNumbers)
|
|
1057
1096
|
return Object.keys(lineNumbers).length
|
|
1058
1097
|
? Object.keys(lineNumbers).map(Number)
|
|
@@ -1069,13 +1108,13 @@ export default class Inibase {
|
|
|
1069
1108
|
else if (Utils.isObject(where)) {
|
|
1070
1109
|
let cachedFilePath = "";
|
|
1071
1110
|
// Criteria
|
|
1072
|
-
if (this.
|
|
1111
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1073
1112
|
cachedFilePath = join(tablePath, ".cache", `${UtilsServer.hashString(inspect(where, { sorted: true }))}${this.fileExtension}`);
|
|
1074
|
-
if (this.
|
|
1113
|
+
if (this.tablesMap.get(tableName).config.cache &&
|
|
1075
1114
|
(await File.isExists(cachedFilePath))) {
|
|
1076
1115
|
const cachedItems = (await readFile(cachedFilePath, "utf8")).split(",");
|
|
1077
|
-
if (!this.totalItems
|
|
1078
|
-
this.totalItems
|
|
1116
|
+
if (!this.totalItems.has(`${tableName}-*`))
|
|
1117
|
+
this.totalItems.set(`${tableName}-*`, cachedItems.length);
|
|
1079
1118
|
if (onlyLinesNumbers)
|
|
1080
1119
|
return onlyOne ? Number(cachedItems[0]) : cachedItems.map(Number);
|
|
1081
1120
|
return this.get(tableName, cachedItems
|
|
@@ -1085,8 +1124,8 @@ export default class Inibase {
|
|
|
1085
1124
|
let linesNumbers = null;
|
|
1086
1125
|
[RETURN, linesNumbers] = await this.applyCriteria(tableName, schema, options, where);
|
|
1087
1126
|
if (RETURN && linesNumbers?.size) {
|
|
1088
|
-
if (!this.totalItems
|
|
1089
|
-
this.totalItems
|
|
1127
|
+
if (!this.totalItems.has(`${tableName}-*`))
|
|
1128
|
+
this.totalItems.set(`${tableName}-*`, linesNumbers.size);
|
|
1090
1129
|
if (onlyLinesNumbers)
|
|
1091
1130
|
return onlyOne
|
|
1092
1131
|
? linesNumbers.values().next().value
|
|
@@ -1096,7 +1135,7 @@ export default class Inibase {
|
|
|
1096
1135
|
.map(({ id }) => id);
|
|
1097
1136
|
RETURN = Object.values(Utils.deepMerge(RETURN, await this.processSchemaData(tableName, Utils.filterSchema(schema, ({ id, type, children }) => !alreadyExistsColumnsIDs.includes(id) ||
|
|
1098
1137
|
Utils.isFieldType("table", type, children)), Object.keys(RETURN).map(Number), options)));
|
|
1099
|
-
if (this.
|
|
1138
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1100
1139
|
await writeFile(cachedFilePath, Array.from(linesNumbers).join(","));
|
|
1101
1140
|
}
|
|
1102
1141
|
}
|
|
@@ -1104,8 +1143,9 @@ export default class Inibase {
|
|
|
1104
1143
|
(Utils.isObject(RETURN) && !Object.keys(RETURN).length) ||
|
|
1105
1144
|
(Array.isArray(RETURN) && !RETURN.length))
|
|
1106
1145
|
return null;
|
|
1107
|
-
const greatestTotalItems = this.totalItems
|
|
1108
|
-
|
|
1146
|
+
const greatestTotalItems = this.totalItems.has(`${tableName}-*`)
|
|
1147
|
+
? this.totalItems.get(`${tableName}-*`)
|
|
1148
|
+
: Math.max(...[...this.totalItems.entries()]
|
|
1109
1149
|
.filter(([k]) => k.startsWith(`${tableName}-`))
|
|
1110
1150
|
.map(([, v]) => v));
|
|
1111
1151
|
this.pageInfo[tableName] = {
|
|
@@ -1122,24 +1162,24 @@ export default class Inibase {
|
|
|
1122
1162
|
page: 1,
|
|
1123
1163
|
perPage: 15,
|
|
1124
1164
|
};
|
|
1125
|
-
const tablePath = join(this.databasePath, tableName)
|
|
1126
|
-
|
|
1127
|
-
|
|
1165
|
+
const tablePath = join(this.databasePath, tableName);
|
|
1166
|
+
await this.getTable(tableName);
|
|
1167
|
+
if (!this.tablesMap.get(tableName).schema)
|
|
1168
|
+
throw this.createError("NO_SCHEMA", tableName);
|
|
1128
1169
|
if (!returnPostedData)
|
|
1129
1170
|
returnPostedData = false;
|
|
1130
1171
|
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;
|
|
1172
|
+
await this.validateData(tableName, data);
|
|
1134
1173
|
const renameList = [];
|
|
1135
1174
|
try {
|
|
1136
1175
|
await File.lock(join(tablePath, ".tmp"), keys);
|
|
1137
1176
|
let paginationFilePath;
|
|
1138
1177
|
for await (const fileName of glob("*.pagination", { cwd: tablePath }))
|
|
1139
1178
|
paginationFilePath = join(tablePath, fileName);
|
|
1140
|
-
[lastId,
|
|
1179
|
+
let [lastId, _totalItems] = parse(paginationFilePath)
|
|
1141
1180
|
.name.split("-")
|
|
1142
1181
|
.map(Number);
|
|
1182
|
+
this.totalItems.set(`${tableName}-*`, _totalItems);
|
|
1143
1183
|
if (Utils.isArrayOfObjects(data))
|
|
1144
1184
|
for (let index = 0; index < data.length; index++) {
|
|
1145
1185
|
const element = data[index];
|
|
@@ -1152,35 +1192,33 @@ export default class Inibase {
|
|
|
1152
1192
|
data.createdAt = Date.now();
|
|
1153
1193
|
data.updatedAt = undefined;
|
|
1154
1194
|
}
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
const pathesContents = this.joinPathesContents(tableName, this.tables[tableName].config.prepend
|
|
1195
|
+
this.formatData(tableName, data);
|
|
1196
|
+
const pathesContents = this.joinPathesContents(tableName, this.tablesMap.get(tableName).config.prepend
|
|
1158
1197
|
? Array.isArray(data)
|
|
1159
1198
|
? data.toReversed()
|
|
1160
1199
|
: data
|
|
1161
1200
|
: data);
|
|
1162
|
-
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(this.
|
|
1201
|
+
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(this.tablesMap.get(tableName).config.prepend
|
|
1163
1202
|
? await File.prepend(path, content)
|
|
1164
1203
|
: await File.append(path, content))));
|
|
1165
1204
|
await Promise.allSettled(renameList
|
|
1166
1205
|
.filter(([_, filePath]) => filePath)
|
|
1167
1206
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1168
|
-
if (this.
|
|
1207
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1169
1208
|
await this.clearCache(tableName);
|
|
1170
|
-
this.totalItems
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
await rename(paginationFilePath, join(tablePath, `${lastId}-${this.totalItems[`${tableName}-*`]}.pagination`));
|
|
1209
|
+
const currentValue = this.totalItems.get(`${tableName}-*`) || 0;
|
|
1210
|
+
this.totalItems.set(`${tableName}-*`, currentValue + (Array.isArray(data) ? data.length : 1));
|
|
1211
|
+
await rename(paginationFilePath, join(tablePath, `${lastId}-${this.totalItems.get(`${tableName}-*`)}.pagination`));
|
|
1174
1212
|
if (returnPostedData)
|
|
1175
|
-
return this.get(tableName, this.
|
|
1213
|
+
return this.get(tableName, this.tablesMap.get(tableName).config.prepend
|
|
1176
1214
|
? Array.isArray(data)
|
|
1177
1215
|
? data.map((_, index) => index + 1).toReversed()
|
|
1178
1216
|
: 1
|
|
1179
1217
|
: Array.isArray(data)
|
|
1180
1218
|
? data
|
|
1181
|
-
.map((_, index) => this.totalItems
|
|
1219
|
+
.map((_, index) => this.totalItems.get(`${tableName}-*`) - index)
|
|
1182
1220
|
.toReversed()
|
|
1183
|
-
: this.totalItems
|
|
1221
|
+
: this.totalItems.get(`${tableName}-*`), options, !Utils.isArrayOfObjects(data));
|
|
1184
1222
|
}
|
|
1185
1223
|
finally {
|
|
1186
1224
|
if (renameList.length)
|
|
@@ -1194,23 +1232,20 @@ export default class Inibase {
|
|
|
1194
1232
|
}, returnUpdatedData) {
|
|
1195
1233
|
const renameList = [];
|
|
1196
1234
|
const tablePath = join(this.databasePath, tableName);
|
|
1197
|
-
|
|
1198
|
-
.schema;
|
|
1235
|
+
await this.throwErrorIfTableEmpty(tableName);
|
|
1199
1236
|
if (!where) {
|
|
1200
1237
|
if (Utils.isArrayOfObjects(data)) {
|
|
1201
1238
|
if (!data.every((item) => Object.hasOwn(item, "id") && Utils.isValidID(item.id)))
|
|
1202
|
-
throw this.
|
|
1239
|
+
throw this.createError("INVALID_ID");
|
|
1203
1240
|
return this.put(tableName, data, data.map(({ id }) => id), options, returnUpdatedData || undefined);
|
|
1204
1241
|
}
|
|
1205
1242
|
if (Object.hasOwn(data, "id")) {
|
|
1206
1243
|
if (!Utils.isValidID(data.id))
|
|
1207
|
-
throw this.
|
|
1244
|
+
throw this.createError("INVALID_ID", data.id);
|
|
1208
1245
|
return this.put(tableName, data, data.id, options, returnUpdatedData || undefined);
|
|
1209
1246
|
}
|
|
1210
|
-
|
|
1211
|
-
this.
|
|
1212
|
-
await this.checkUnique(tableName, schema);
|
|
1213
|
-
data = this.formatData(data, schema, true);
|
|
1247
|
+
await this.validateData(tableName, data, true);
|
|
1248
|
+
this.formatData(tableName, data, true);
|
|
1214
1249
|
const pathesContents = this.joinPathesContents(tableName, {
|
|
1215
1250
|
...(({ id, ...restOfData }) => restOfData)(data),
|
|
1216
1251
|
updatedAt: Date.now(),
|
|
@@ -1220,14 +1255,12 @@ export default class Inibase {
|
|
|
1220
1255
|
for await (const paginationFileName of glob("*.pagination", {
|
|
1221
1256
|
cwd: tablePath,
|
|
1222
1257
|
}))
|
|
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}-*`]))));
|
|
1258
|
+
this.totalItems.set(`${tableName}-*`, parse(paginationFileName).name.split("-").map(Number)[1]);
|
|
1259
|
+
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(await File.replace(path, content, this.totalItems.get(`${tableName}-*`)))));
|
|
1227
1260
|
await Promise.allSettled(renameList
|
|
1228
1261
|
.filter(([_, filePath]) => filePath)
|
|
1229
1262
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1230
|
-
if (this.
|
|
1263
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1231
1264
|
await this.clearCache(join(tablePath, ".cache"));
|
|
1232
1265
|
if (returnUpdatedData)
|
|
1233
1266
|
return await this.get(tableName, undefined, options);
|
|
@@ -1246,9 +1279,8 @@ export default class Inibase {
|
|
|
1246
1279
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1247
1280
|
Utils.isNumber(where)) {
|
|
1248
1281
|
// "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);
|
|
1282
|
+
await this.validateData(tableName, data, true);
|
|
1283
|
+
this.formatData(tableName, data, true);
|
|
1252
1284
|
const pathesContents = Object.fromEntries(Object.entries(this.joinPathesContents(tableName, Utils.isArrayOfObjects(data)
|
|
1253
1285
|
? data.map((item) => ({
|
|
1254
1286
|
...item,
|
|
@@ -1269,7 +1301,7 @@ export default class Inibase {
|
|
|
1269
1301
|
await Promise.allSettled(renameList
|
|
1270
1302
|
.filter(([_, filePath]) => filePath)
|
|
1271
1303
|
.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1272
|
-
if (this.
|
|
1304
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1273
1305
|
await this.clearCache(tableName);
|
|
1274
1306
|
if (returnUpdatedData)
|
|
1275
1307
|
return this.get(tableName, where, options, !Array.isArray(where));
|
|
@@ -1286,7 +1318,7 @@ export default class Inibase {
|
|
|
1286
1318
|
return this.put(tableName, data, lineNumbers, options, returnUpdatedData || undefined);
|
|
1287
1319
|
}
|
|
1288
1320
|
else
|
|
1289
|
-
throw this.
|
|
1321
|
+
throw this.createError("INVALID_PARAMETERS");
|
|
1290
1322
|
}
|
|
1291
1323
|
/**
|
|
1292
1324
|
* Delete item(s) in a table
|
|
@@ -1314,7 +1346,7 @@ export default class Inibase {
|
|
|
1314
1346
|
await Promise.all((await readdir(tablePath))
|
|
1315
1347
|
?.filter((fileName) => fileName.endsWith(this.getFileExtension(tableName)))
|
|
1316
1348
|
.map(async (file) => unlink(join(tablePath, file))));
|
|
1317
|
-
if (this.
|
|
1349
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1318
1350
|
await this.clearCache(tableName);
|
|
1319
1351
|
await rename(paginationFilePath, join(tablePath, `${pagination[0]}-0.pagination`));
|
|
1320
1352
|
return true;
|
|
@@ -1357,7 +1389,7 @@ export default class Inibase {
|
|
|
1357
1389
|
await Promise.all((await readdir(tablePath))
|
|
1358
1390
|
?.filter((fileName) => fileName.endsWith(this.getFileExtension(tableName)))
|
|
1359
1391
|
.map(async (file) => unlink(join(tablePath, file))));
|
|
1360
|
-
if (this.
|
|
1392
|
+
if (this.tablesMap.get(tableName).config.cache)
|
|
1361
1393
|
await this.clearCache(tableName);
|
|
1362
1394
|
await rename(paginationFilePath, join(tablePath, `${pagination[0]}-${pagination[1] - (Array.isArray(where) ? where.length : 1)}.pagination`));
|
|
1363
1395
|
return true;
|
|
@@ -1375,7 +1407,7 @@ export default class Inibase {
|
|
|
1375
1407
|
return this.delete(tableName, lineNumbers);
|
|
1376
1408
|
}
|
|
1377
1409
|
else
|
|
1378
|
-
throw this.
|
|
1410
|
+
throw this.createError("INVALID_PARAMETERS");
|
|
1379
1411
|
return false;
|
|
1380
1412
|
}
|
|
1381
1413
|
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.122",
|
|
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",
|