blackcat.js-database 1.0.2 → 1.0.4
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 +7 -3
- package/dist/index.d.mts +42 -10
- package/dist/index.d.ts +42 -10
- package/dist/index.js +58 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +58 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# 🐈⬛ blackcat.js-database
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
> Một **database nhẹ, typed và hỗ trợ autocomplete path cho TypeScript**.
|
|
9
|
+
> `blackcat.js-database` cho phép bạn lưu trữ và truy vấn dữ liệu bằng **dot notation** với **type inference mạnh mẽ trong IDE**.
|
|
6
10
|
|
|
7
|
-
> [Xem tài liệu ở đây](blackcat-js-database.vercel.app)
|
|
11
|
+
> [Xem tài liệu ở đây.](https://blackcat-js-database.vercel.app)
|
|
8
12
|
---
|
|
9
13
|
|
|
10
14
|
# Tính năng
|
package/dist/index.d.mts
CHANGED
|
@@ -663,25 +663,57 @@ declare class Database<V = any> {
|
|
|
663
663
|
*/
|
|
664
664
|
deleteMany<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, query: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<number>;
|
|
665
665
|
/**
|
|
666
|
-
* Cập nhật
|
|
666
|
+
* Cập nhật dữ liệu trong database theo đường dẫn key.
|
|
667
667
|
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
668
|
+
* Hàm này sẽ tìm đến vị trí của `key` trong database và gán `value` vào đó.
|
|
669
|
+
* Nếu `value` và giá trị hiện tại tại key đều là object thì sẽ thực hiện
|
|
670
|
+
* **shallow merge** thay vì ghi đè toàn bộ object.
|
|
670
671
|
*
|
|
671
|
-
*
|
|
672
|
-
* thì chúng sẽ được tự động tạo.
|
|
672
|
+
* Điều này giúp tránh việc làm mất các thuộc tính đã tồn tại.
|
|
673
673
|
*
|
|
674
|
-
* @template P
|
|
674
|
+
* @template P - Đường dẫn key hợp lệ trong object database.
|
|
675
|
+
*
|
|
676
|
+
* @param key - Đường dẫn tới giá trị cần cập nhật.
|
|
677
|
+
* Hỗ trợ nested path dạng `"a.b.c"`.
|
|
675
678
|
*
|
|
676
|
-
* @param
|
|
677
|
-
* @param value Giá trị mới.
|
|
679
|
+
* @param value - Giá trị mới sẽ được cập nhật tại key.
|
|
678
680
|
*
|
|
679
|
-
* @returns
|
|
681
|
+
* @returns
|
|
682
|
+
* Trả về giá trị cuối cùng sau khi cập nhật.
|
|
680
683
|
*
|
|
681
684
|
* @example
|
|
685
|
+
* Database ban đầu:
|
|
686
|
+
* ```json
|
|
687
|
+
* {
|
|
688
|
+
* "123": {
|
|
689
|
+
* "guildID": "123",
|
|
690
|
+
* "guildName": "BlackCat",
|
|
691
|
+
* "history": []
|
|
692
|
+
* }
|
|
693
|
+
* }
|
|
694
|
+
* ```
|
|
695
|
+
*
|
|
696
|
+
* Cập nhật:
|
|
682
697
|
* ```ts
|
|
683
|
-
* await db.update("
|
|
698
|
+
* await db.update("123", {
|
|
699
|
+
* history: [1,2,3]
|
|
700
|
+
* });
|
|
701
|
+
* ```
|
|
702
|
+
*
|
|
703
|
+
* Kết quả:
|
|
704
|
+
* ```json
|
|
705
|
+
* {
|
|
706
|
+
* "123": {
|
|
707
|
+
* "guildID": "123",
|
|
708
|
+
* "guildName": "BlackCat",
|
|
709
|
+
* "history": [1,2,3]
|
|
710
|
+
* }
|
|
711
|
+
* }
|
|
684
712
|
* ```
|
|
713
|
+
*
|
|
714
|
+
* @throws {BlackCatError}
|
|
715
|
+
* - `REQUIRED_PARAMETER_MISSING` nếu key không được cung cấp
|
|
716
|
+
* - `INVALID_TYPE` nếu key không phải string
|
|
685
717
|
*/
|
|
686
718
|
update<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, value: ObjectValue<V, P>): Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>>;
|
|
687
719
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -663,25 +663,57 @@ declare class Database<V = any> {
|
|
|
663
663
|
*/
|
|
664
664
|
deleteMany<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, query: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<number>;
|
|
665
665
|
/**
|
|
666
|
-
* Cập nhật
|
|
666
|
+
* Cập nhật dữ liệu trong database theo đường dẫn key.
|
|
667
667
|
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
668
|
+
* Hàm này sẽ tìm đến vị trí của `key` trong database và gán `value` vào đó.
|
|
669
|
+
* Nếu `value` và giá trị hiện tại tại key đều là object thì sẽ thực hiện
|
|
670
|
+
* **shallow merge** thay vì ghi đè toàn bộ object.
|
|
670
671
|
*
|
|
671
|
-
*
|
|
672
|
-
* thì chúng sẽ được tự động tạo.
|
|
672
|
+
* Điều này giúp tránh việc làm mất các thuộc tính đã tồn tại.
|
|
673
673
|
*
|
|
674
|
-
* @template P
|
|
674
|
+
* @template P - Đường dẫn key hợp lệ trong object database.
|
|
675
|
+
*
|
|
676
|
+
* @param key - Đường dẫn tới giá trị cần cập nhật.
|
|
677
|
+
* Hỗ trợ nested path dạng `"a.b.c"`.
|
|
675
678
|
*
|
|
676
|
-
* @param
|
|
677
|
-
* @param value Giá trị mới.
|
|
679
|
+
* @param value - Giá trị mới sẽ được cập nhật tại key.
|
|
678
680
|
*
|
|
679
|
-
* @returns
|
|
681
|
+
* @returns
|
|
682
|
+
* Trả về giá trị cuối cùng sau khi cập nhật.
|
|
680
683
|
*
|
|
681
684
|
* @example
|
|
685
|
+
* Database ban đầu:
|
|
686
|
+
* ```json
|
|
687
|
+
* {
|
|
688
|
+
* "123": {
|
|
689
|
+
* "guildID": "123",
|
|
690
|
+
* "guildName": "BlackCat",
|
|
691
|
+
* "history": []
|
|
692
|
+
* }
|
|
693
|
+
* }
|
|
694
|
+
* ```
|
|
695
|
+
*
|
|
696
|
+
* Cập nhật:
|
|
682
697
|
* ```ts
|
|
683
|
-
* await db.update("
|
|
698
|
+
* await db.update("123", {
|
|
699
|
+
* history: [1,2,3]
|
|
700
|
+
* });
|
|
701
|
+
* ```
|
|
702
|
+
*
|
|
703
|
+
* Kết quả:
|
|
704
|
+
* ```json
|
|
705
|
+
* {
|
|
706
|
+
* "123": {
|
|
707
|
+
* "guildID": "123",
|
|
708
|
+
* "guildName": "BlackCat",
|
|
709
|
+
* "history": [1,2,3]
|
|
710
|
+
* }
|
|
711
|
+
* }
|
|
684
712
|
* ```
|
|
713
|
+
*
|
|
714
|
+
* @throws {BlackCatError}
|
|
715
|
+
* - `REQUIRED_PARAMETER_MISSING` nếu key không được cung cấp
|
|
716
|
+
* - `INVALID_TYPE` nếu key không phải string
|
|
685
717
|
*/
|
|
686
718
|
update<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, value: ObjectValue<V, P>): Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>>;
|
|
687
719
|
/**
|
package/dist/index.js
CHANGED
|
@@ -466,41 +466,86 @@ var _Database = class _Database {
|
|
|
466
466
|
return originalLength - filtered.length;
|
|
467
467
|
}
|
|
468
468
|
/**
|
|
469
|
-
* Cập nhật
|
|
469
|
+
* Cập nhật dữ liệu trong database theo đường dẫn key.
|
|
470
470
|
*
|
|
471
|
-
*
|
|
472
|
-
*
|
|
471
|
+
* Hàm này sẽ tìm đến vị trí của `key` trong database và gán `value` vào đó.
|
|
472
|
+
* Nếu `value` và giá trị hiện tại tại key đều là object thì sẽ thực hiện
|
|
473
|
+
* **shallow merge** thay vì ghi đè toàn bộ object.
|
|
473
474
|
*
|
|
474
|
-
*
|
|
475
|
-
* thì chúng sẽ được tự động tạo.
|
|
475
|
+
* Điều này giúp tránh việc làm mất các thuộc tính đã tồn tại.
|
|
476
476
|
*
|
|
477
|
-
* @template P
|
|
477
|
+
* @template P - Đường dẫn key hợp lệ trong object database.
|
|
478
|
+
*
|
|
479
|
+
* @param key - Đường dẫn tới giá trị cần cập nhật.
|
|
480
|
+
* Hỗ trợ nested path dạng `"a.b.c"`.
|
|
478
481
|
*
|
|
479
|
-
* @param
|
|
480
|
-
* @param value Giá trị mới.
|
|
482
|
+
* @param value - Giá trị mới sẽ được cập nhật tại key.
|
|
481
483
|
*
|
|
482
|
-
* @returns
|
|
484
|
+
* @returns
|
|
485
|
+
* Trả về giá trị cuối cùng sau khi cập nhật.
|
|
483
486
|
*
|
|
484
487
|
* @example
|
|
488
|
+
* Database ban đầu:
|
|
489
|
+
* ```json
|
|
490
|
+
* {
|
|
491
|
+
* "123": {
|
|
492
|
+
* "guildID": "123",
|
|
493
|
+
* "guildName": "BlackCat",
|
|
494
|
+
* "history": []
|
|
495
|
+
* }
|
|
496
|
+
* }
|
|
497
|
+
* ```
|
|
498
|
+
*
|
|
499
|
+
* Cập nhật:
|
|
485
500
|
* ```ts
|
|
486
|
-
* await db.update("
|
|
501
|
+
* await db.update("123", {
|
|
502
|
+
* history: [1,2,3]
|
|
503
|
+
* });
|
|
487
504
|
* ```
|
|
505
|
+
*
|
|
506
|
+
* Kết quả:
|
|
507
|
+
* ```json
|
|
508
|
+
* {
|
|
509
|
+
* "123": {
|
|
510
|
+
* "guildID": "123",
|
|
511
|
+
* "guildName": "BlackCat",
|
|
512
|
+
* "history": [1,2,3]
|
|
513
|
+
* }
|
|
514
|
+
* }
|
|
515
|
+
* ```
|
|
516
|
+
*
|
|
517
|
+
* @throws {BlackCatError}
|
|
518
|
+
* - `REQUIRED_PARAMETER_MISSING` nếu key không được cung cấp
|
|
519
|
+
* - `INVALID_TYPE` nếu key không phải string
|
|
488
520
|
*/
|
|
489
521
|
async update(key, value) {
|
|
522
|
+
if (!key) {
|
|
523
|
+
throw new BlackCatError("REQUIRED_PARAMETER_MISSING", "key");
|
|
524
|
+
}
|
|
525
|
+
if (typeof key !== "string") {
|
|
526
|
+
throw new BlackCatError("INVALID_TYPE", "key", "string", typeOf(key));
|
|
527
|
+
}
|
|
490
528
|
const allDatabase = await this.all();
|
|
491
529
|
const keys = key.split(".");
|
|
492
530
|
let current = allDatabase;
|
|
493
531
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
494
532
|
const part = keys[i];
|
|
495
|
-
if (!(part
|
|
533
|
+
if (!isObject(current[part])) {
|
|
496
534
|
current[part] = {};
|
|
497
535
|
}
|
|
498
536
|
current = current[part];
|
|
499
537
|
}
|
|
500
538
|
const lastKey = keys[keys.length - 1];
|
|
501
|
-
current[lastKey]
|
|
539
|
+
if (isObject(value) && isObject(current[lastKey])) {
|
|
540
|
+
current[lastKey] = {
|
|
541
|
+
...current[lastKey],
|
|
542
|
+
...value
|
|
543
|
+
};
|
|
544
|
+
} else {
|
|
545
|
+
current[lastKey] = value;
|
|
546
|
+
}
|
|
502
547
|
await this.driver.set(allDatabase);
|
|
503
|
-
return current;
|
|
548
|
+
return current[lastKey];
|
|
504
549
|
}
|
|
505
550
|
/**
|
|
506
551
|
* Cộng thêm giá trị vào một key dạng number.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils/isObject.function.ts","../src/utils/typeOf.function.ts","../src/utils/isNumber.function.ts","../src/utils/BlackCatError.ts","../src/utils/TypedObject.ts","../src/utils/Emitter.ts","../src/Database.ts","../src/drivers/JSONDriver.ts","../src/drivers/MemoryDriver.ts","../src/drivers/SQLiteDriver.ts","../src/drivers/MongoDriver.ts"],"sourcesContent":["export * from \"./Database.ts\";\nexport * from \"./drivers\";","/**\n * Checks for is the item object and returns it.\n * @param {any} item The item to check.\n * @returns {boolean} Is the item object or not.\n */\nexport const isObject = (item: any): boolean => !Array.isArray(item) && item !== null && typeof item == \"object\";","/**\n * Returns the exact type of a given input.\n * @param input - The value to check.\n * @returns A string representing the exact type of the input.\n */\nexport const typeOf = (input: any): string => {\n // ✅ Handle special cases: null, undefined, and NaN\n if (input == null || (typeof input === \"number\" && Number.isNaN(input))) return String(input);\n // ✅ If it's a class constructor (has a prototype)\n if (typeof input === \"function\" && input.prototype) return `${input.name} class instance`;\n // ✅ If it's an object or function, return the constructor name if available\n return input?.constructor?.name ?? typeof input;\n};","import { typeOf } from \"./typeOf.function\";\n\n/**\n * Determines if the specified value is a number.\n *\n * A small hack to actually determine if the input is a number since\n * empty strings and arrays are considered as numbers too.\n * @param {any} input The input to check.\n * @returns {boolean} Whether the specified input is a number.\n */\nexport const isNumber = (input: any): boolean => !isNaN(input as number) && input !== \"\" && input !== null && typeOf(input) !== \"Array\";","import { typeOf } from \"./typeOf.function\";\n\nexport type TargetParamType = \"string\" | \"number\" | \"object\" | \"array\" | `${string} class instance`;\n\nexport const errors = {\n DEVICE_IS_OFFLINE: 'Your device appears to be offline so it\\'s impossible to proceed with ' + 'connection to your online MongoDB cluster. Please connect your device to the internet or switch to the ' + 'local MongoDB database and try again.',\n CONNECTION_NOT_ESTABLISHED: 'Failed to connect to MongoDB. Please double-check the specified ' + 'connection URI and make sure that you\\'re performing the ' + 'database connection using the `QuickMongoClient.connect()` method.',\n CONNECTION_URI_NOT_SPECIFIED: 'The MongoDB connection URI must be specified.',\n INVALID_CONNECTION_URI: 'The specified MongoDB connection URI is invalid.',\n UNKNOWN_ERROR: 'Unknown error.',\n REQUIRED_PARAMETER_MISSING: '\\'{1}\\' parameter is required but is missing.',\n REQUIRED_CONSTRUCTOR_PARAMETER_MISSING: '\\'{1}\\' parameter in constructor \\'{2}\\' is required but is missing.',\n INVALID_CONSTRUCTOR_PARAMETER_TYPE: '\\'{1}\\' parameter in constructor \\'{2}\\' must be ' + 'a type of {3}. Received type: {4}.',\n INVALID_TYPE: '\\'{1}\\' must be a type of {2}. Received type: {3}.',\n ONE_OR_MORE_ARRAY_TYPES_INVALID: 'All specified elements from array in \\'{1}\\' parameter ' + 'must be a type of {2}. Received array of types: {3}.',\n INVALID_TARGET: 'The target in database must be a type of {1}. Received target type: {2}.',\n INVALID_KEY: \"{1}\",\n INVALID_PARAMETER: \"{1} {2}\",\n DATABASE_CONNECTION_FAILED: \"{1}\"\n}\n\nexport interface ErrorParams extends Record<keyof typeof errors, string[]> {\n CONNECTION_NOT_ESTABLISHED: [];\n UNKNOWN_ERROR: [];\n CONNECTION_URI_NOT_SPECIFIED: [];\n INVALID_CONNECTION_URI: [];\n REQUIRED_PARAMETER_MISSING: [missingParam: string];\n REQUIRED_CONSTRUCTOR_PARAMETER_MISSING: [missingParam: string, className: string];\n INVALID_TYPE: [paramName: string, targetType: TargetParamType, receivedType: string];\n INVALID_CONSTRUCTOR_PARAMETER_TYPE: [paramName: string, className: string, targetType: TargetParamType, receivedType: string];\n ONE_OR_MORE_ARRAY_TYPES_INVALID: [paramName: string, targetType: TargetParamType, receivedTypesArray: string];\n INVALID_TARGET: [targetType: TargetParamType, receivedType: string];\n INVALID_KEY: [paramName: string];\n INVALID_PARAMETER: [paramName: string, receivedType: string];\n DATABASE_CONNECTION_FAILED: [paramName: string]\n}\nexport const createTypesArray = <T>(...elements: any): string => `[${elements.map((element: any) => typeOf(element))}]`;\n/**\n * BlackCatError class.\n */\nexport class BlackCatError<TErrorCode extends keyof typeof errors> extends Error {\n /** \n * Creates a BlackCatError instance.\n * @param {string} errorCode Quick Mongo error code.\n * @param {any[]} params Additional parameters to replace the placeholders in the error message.\n */\n public constructor(errorCode: TErrorCode, ...params: ErrorParams[TErrorCode]) {\n const code = errors[errorCode] ? errorCode : \"UNKNOWN_ERROR\" as TErrorCode;\n let message = errors[code];\n for (let i = 0; i < params.length; i++) {\n message = message.replaceAll(`{${i + 1}}`, params[i]);\n };\n super(message);\n /**\n * The name of the error.\n */\n this.name = `BlackCatError [${code}]`;\n }\n}","import { ExtractObjectKeys, ExtractObjectValues, ExtractObjectEntries } from \"../types\";\n\n/**\n * Utility class for working with objects.\n *\n * Provides **static** methods for retrieving keys and values of an object with addition of types.\n *\n * This class enhances type safety by providing better typings for object keys and values.\n */\nexport class TypedObject {\n /**\n * Returns the names of the enumerable string properties and methods of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object keys types from.\n *\n * @param {TObject} obj Object to get the keys from.\n *\n * @returns {Array<ExtractObjectKeys<TObject>>}\n * Array of names of the enumerable string properties and methods of the specified object.\n */\n public static keys<TObject extends Record<string, any>>(obj: TObject): ExtractObjectKeys<TObject>[] {\n return Object.keys(obj || {});\n }\n /**\n * Returns an array of values of the enumerable properties of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object values types from.\n *\n * @param {TObject} obj Object to get the values from.\n *\n * @returns {Array<ExtractObjectValues<TObject>>}\n * Array of values of the enumerable properties of the specified object.\n */\n public static values<TObject extends Record<string, any>>(obj: TObject): ExtractObjectValues<TObject>[] {\n return Object.values(obj || {});\n }\n /**\n * Returns an array of entries (key-value pairs) of the enumerable properties of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object entries types (key-value pairs types) from.\n *\n * @param {TObject} obj Object to get the entries from.\n *\n * @returns {ExtractObjectEntries<TObject>[]}\n * Array of entries (key-value pairs) of the enumerable properties of the specified object.\n */\n public static entries<TObject extends Record<string, any>>(obj: TObject): ExtractObjectEntries<TObject>[] {\n return Object.entries(obj || {})\n }\n}","import { EventEmitter } from \"node:events\";\n\nexport class Emitter<E extends Record<string, any>> {\n private _emitter = new EventEmitter();\n /**\n * Listens to the event.\n * @param {string} event Event name.\n * @param {Function} listener Listener function.\n */\n public on<K extends Exclude<keyof E, number>>(event: K, listener: (...args: E[K]) => any): Emitter<E> {\n this._emitter.on(event, listener);\n return this;\n }\n /**\n * Listens to the event only for once.\n * @param {string} event Event name.\n * @param {Function} listener Listener function.\n */\n public once<K extends Exclude<keyof E, number>>(event: K, listener: (...args: E[K]) => any): Emitter<E> {\n this._emitter.once(event, listener);\n return this;\n }\n /**\n * Emits the event.\n * @param {string} event Event name.\n * @param {any[]} args Listener arguments.\n * @returns {boolean} `true` if the event had listeners, `false` otherwise.\n */\n public emit<K extends Exclude<keyof E, number>>(event: K, ...args: E[K]): boolean {\n return this._emitter.emit(event, ...args as any[]);\n }\n}","import { DatabaseConfiguration, AutocompletableString, FirstObjectKey, If, IsObject, ObjectPath, ObjectValue, Maybe, QueryFunction, RestOrArray, ExtractFromArray, DatabaseDriver, ArrayElement } from \"./types\";\nimport { BlackCatError, createTypesArray, isNumber, typeOf, TypedObject, isObject } from \"./utils\";\n\n/**\n * Class Database cung cấp API thao tác dữ liệu dạng key-path\n * trên nhiều loại storage khác nhau thông qua `DatabaseDriver`.\n *\n * Đây là **lớp database chính (logic layer)** của hệ thống.\n *\n * Class này chịu trách nhiệm:\n * - parse key path (`user.profile.name`)\n * - validate dữ liệu\n * - thao tác object\n * - query dữ liệu (find, filter, map...)\n *\n * Việc lưu trữ dữ liệu thực tế sẽ được thực hiện bởi các **driver phụ trợ**\n * như:\n *\n * - `JSONDriver`\n * - `MemoryDriver`\n * - `SQLiteDriver`\n * - `MongoDriver`\n *\n * Các driver này chỉ chịu trách nhiệm:\n * - đọc toàn bộ dữ liệu database\n * - ghi toàn bộ dữ liệu database\n *\n * @template V Kiểu dữ liệu tổng thể của database.\n */\nexport class Database<V = any> {\n /**\n * Storage driver được sử dụng để đọc và ghi dữ liệu database.\n *\n * Driver phải implement interface `DatabaseDriver`.\n *\n * Ví dụ:\n * ```ts\n * const db = new Database({\n * driver: new JSONDriver({ filePath: \"./database.json\" }),\n * })\n * ```\n */\n public driver: DatabaseDriver;\n /**\n * Khởi tạo Database instance.\n *\n * @param options Cấu hình database.\n * @param options.driver Driver lưu trữ dữ liệu.\n *\n * @example\n * ```ts\n * const db = new Database({\n * driver: new JSONDriver({ filePath: \"./database.json\" }),\n * })\n * ```\n *\n * Ví dụ với MongoDB:\n *\n * ```ts\n * const db = new Database({\n * driver: new MongoDriver({\n * uri: \"mongodb://localhost:27017\",\n * databaseName: \"mydb\"\n * })\n * });\n * ```\n */\n constructor(options: DatabaseConfiguration) {\n this.driver = options.driver;\n }\n /**\n * Lấy toàn bộ dữ liệu từ database thông qua driver.\n *\n * @template T Kiểu dữ liệu object database trả về.\n *\n * @returns Promise chứa toàn bộ dữ liệu database.\n *\n * @example\n * ```ts\n * const data = await db.all();\n * console.log(data.users);\n * ```\n */\n public async all<T extends Record<string, any> = Record<string, any>>(): Promise<T> {\n return await this.driver.all<T>();\n }\n /**\n * Lấy giá trị từ database theo key-path.\n *\n * Key có thể là chuỗi dạng path:\n *\n * ```\n * user.profile.name\n * economy.users.123.balance\n * ```\n *\n * Nếu không truyền `key`, method sẽ trả về **toàn bộ database**.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần lấy.\n *\n * @returns Giá trị tại key hoặc `null` nếu không tồn tại.\n *\n * @example\n * ```ts\n * const name = await db.get(\"user.profile.name\");\n * ```\n *\n * @example\n * ```ts\n * const all = await db.get();\n * ```\n */\n public async get<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>): Promise<Maybe<ObjectValue<V, P>> | V> {\n const data = await this.all();\n if (key === undefined) return data as V;\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeOf(key));\n }\n const keys = key.split(\".\");\n let result: any = data;\n for (const k of keys) {\n if (!isObject(result) && !Array.isArray(result)) return null;\n result = result[k];\n if (result === undefined) return null;\n }\n return result;\n }\n /**\n * Tìm và trả về một bản ghi đầu tiên khớp với điều kiện trong database.\n *\n * Hàm này có hai cách sử dụng:\n *\n * 1. **Chỉ truyền `key`**\n * → Trả về toàn bộ dữ liệu của key (tương tự `get()`).\n *\n * 2. **Truyền `key` và `query`**\n * → Tìm phần tử đầu tiên trong mảng dữ liệu của key khớp với điều kiện.\n *\n * @template V - Kiểu dữ liệu của database.\n * @template P - Đường dẫn key trong object (`ObjectPath<V>`).\n *\n * @param key - Key hoặc đường dẫn đến dữ liệu cần truy vấn.\n * @param query - Đối tượng điều kiện để tìm bản ghi phù hợp.\n *\n * @returns\n * - Nếu chỉ có `key`: trả về toàn bộ dữ liệu của key.\n * - Nếu có `query`: trả về bản ghi đầu tiên khớp điều kiện.\n * - Nếu không tìm thấy: trả về `null`.\n *\n * @example\n * Chỉ lấy dữ liệu theo key\n * ```ts\n * const users = await db.findOne(\"user\");\n * ```\n *\n * @example\n * Tìm một bản ghi theo điều kiện\n * ```ts\n * const user = await db.findOne(\"user\", {\n * guild: 1234566\n * });\n * ```\n */\n public async findOne<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>, query?: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<Maybe<ObjectValue<V, P>> | V> {\n const data = await this.get(key as any);\n if (!query) return data;\n if (!Array.isArray(data)) return null as Maybe<ObjectValue<V, P>>;\n const result = data.find((item) => {\n return Object.entries(query as Record<string, any>).every(([k, v]) => item[k] == v);\n });\n return (result ?? null) as Maybe<ObjectValue<V, P>>;\n }\n /**\n * Kiểm tra một key-path có tồn tại trong database hay không.\n *\n * Method này sử dụng `get()` để xác định giá trị có tồn tại.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần kiểm tra.\n *\n * @returns `true` nếu key tồn tại, ngược lại `false`.\n *\n * @example\n * ```ts\n * const exists = await db.has(\"users.123\");\n * ```\n */\n public async has<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const value = await this.get(key);\n return value !== null && value !== undefined;\n }\n /**\n * Gán giá trị cho một key-path trong database.\n *\n * Nếu key-path chưa tồn tại, các object trung gian\n * sẽ được tự động tạo.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần gán giá trị.\n * @param {ObjectValue<V, P>} value Giá trị mới.\n *\n * @returns {Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>>} Giá trị vừa được set hoặc object root nếu value là object.\n *\n * @example\n * ```ts\n * await db.set(\"users.123.name\", \"Alice\");\n * ```\n *\n * @example\n * ```ts\n * await db.set(\"config.prefix\", \"!\");\n * ```\n */\n public async set<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, value: ObjectValue<V, P>): Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>> {\n const allDatabase = await this.all();\n if (!key) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"key\");\n }\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeOf(key));\n }\n const keys = key.split(\".\");\n let currentObj = allDatabase;\n\n for (let i = 0; i < keys.length; i++) {\n if (keys.length - 1 === i) {\n currentObj[keys[i]] = value\n } else {\n if (!isObject(currentObj[keys[i]])) {\n currentObj[keys[i]] = {};\n }\n currentObj = currentObj[keys[i]];\n };\n };\n await this.driver.set(allDatabase);\n return typeof value == \"object\" && value !== null ? await this.get(keys[0]) as any : value as any;\n }\n /**\n * Xóa một key khỏi database.\n *\n * Hỗ trợ nested path bằng dot notation.\n *\n * @typeParam P - Path của object.\n *\n * @param key - Đường dẫn key cần xóa.\n *\n * @returns\n * - `true` nếu xóa thành công\n * - `false` nếu key không tồn tại\n *\n * @throws BlackCatError\n * - INVALID_TYPE nếu key không phải string\n *\n * @example\n * await db.delete(\"user.name\");\n */\n public async delete<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>): Promise<boolean> {\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeof key);\n }\n const allDatabase = await this.all();\n const keys = key.split(\".\");\n const lastKey = keys.pop() as string;\n let currentObj: any = allDatabase;\n for (const k of keys) {\n if (!isObject(currentObj[k])) {\n return false;\n }\n currentObj = currentObj[k];\n }\n if (!(lastKey in currentObj)) return false;\n delete currentObj[lastKey];\n await this.driver.set(allDatabase);\n return true;\n }\n /**\n * Xóa toàn bộ dữ liệu trong database.\n *\n * Method này gọi trực tiếp `driver.delete()` để reset storage.\n *\n * @returns `true` sau khi dữ liệu đã được xóa.\n *\n * @example\n * await db.deleteAll();\n */\n public async deleteAll(): Promise<boolean> {\n await this.driver.delete();\n return true;\n }\n /**\n * Xóa nhiều bản ghi trong một mảng dữ liệu dựa trên điều kiện truy vấn.\n *\n * ⚠️ Method này **chỉ hoạt động với dữ liệu dạng mảng (array)**.\n * Nếu dữ liệu tại `key` không phải là mảng, method sẽ **không thực hiện xóa**\n * và trả về `0`.\n *\n * Method sẽ duyệt qua toàn bộ phần tử trong mảng và xóa những phần tử\n * khớp với điều kiện `query`.\n *\n * @template V - Kiểu dữ liệu của database.\n * @template P - Đường dẫn key trong object (`ObjectPath<V>`).\n *\n * @param key - Đường dẫn đến mảng dữ liệu cần thao tác.\n * @param query - Điều kiện để xác định các phần tử cần xóa.\n * Có thể truyền:\n * - Một object điều kiện\n *\n * @returns Số lượng phần tử đã bị xóa khỏi mảng.\n *\n * @example\n * Database mẫu:\n * ```json\n * {\n * \"member\": {\n * \"user\": {\n * \"database\": [\n * { \"guild\": \"123\", \"username\": \"vinh\" },\n * { \"guild\": \"456\", \"username\": \"test\" }\n * ]\n * }\n * }\n * }\n * ```\n *\n * @example\n * Xóa tất cả user có guild = \"123\"\n * ```ts\n * await db.deleteMany(\"member.user.database\", {\n * guild: \"123\"\n * });\n * ```\n */\n public async deleteMany<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, query: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<number> {\n const data = await this.get(key as any);\n if (!Array.isArray(data)) return 0;\n const originalLength = data.length;\n const filtered = data.filter((item: any) => {\n return !Object.entries(query as Record<string, any>).every(([k, v]) => item[k] == v);\n });\n await this.set(key, filtered as any);\n\n return originalLength - filtered.length;\n }\n /**\n * Cập nhật giá trị của một key-path trong database.\n *\n * Khác với `set()`, method này chỉ ghi đè giá trị của key cuối cùng\n * trong path mà không thay đổi cấu trúc object phía trên.\n *\n * Nếu các object trung gian trong path chưa tồn tại\n * thì chúng sẽ được tự động tạo.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn dữ liệu cần cập nhật.\n * @param value Giá trị mới.\n *\n * @returns Object cha của key vừa cập nhật.\n *\n * @example\n * ```ts\n * await db.update(\"users.123.name\", \"Alice\");\n * ```\n */\n public async update<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, value: ObjectValue<V, P>): Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>> {\n const allDatabase = await this.all();\n const keys = key.split(\".\");\n let current: any = allDatabase;\n\n for (let i = 0; i < keys.length - 1; i++) {\n const part = keys[i];\n if (!(part in current)) {\n current[part] = {};\n }\n current = current[part];\n }\n\n const lastKey = keys[keys.length - 1];\n current[lastKey] = value;\n\n await this.driver.set(allDatabase);\n return current;\n }\n /**\n * Cộng thêm giá trị vào một key dạng number.\n *\n * Nếu key chưa tồn tại, giá trị mặc định sẽ là `0`.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn dữ liệu dạng number.\n * @param numberToAdd Số cần cộng thêm.\n *\n * @returns Giá trị mới sau khi cộng.\n *\n * @example\n * ```ts\n * await db.add(\"economy.users.123.balance\", 50);\n * ```\n */\n public async add<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, numberToAdd: number): Promise<number> {\n const targetNumber = await this.get(key) as any ?? 0;\n\n if (!isNumber(targetNumber)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"number\", typeOf(targetNumber));\n }\n if (numberToAdd === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"numberToAdd\");\n }\n if (!isNumber(numberToAdd)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"numberToAdd\", \"number\", typeOf(numberToAdd));\n }\n return await this.set(key, targetNumber + numberToAdd) as Promise<number>;\n }\n /**\n * Trừ giá trị khỏi một key dạng number.\n *\n * Nếu key chưa tồn tại, giá trị mặc định sẽ là `0`.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn dữ liệu dạng number.\n * @param numberToSubtract Số cần trừ.\n *\n * @returns Giá trị mới sau khi trừ.\n *\n * @example\n * ```ts\n * await db.subtract(\"economy.users.123.balance\", 20);\n * ```\n */\n public async subtract<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, numberToSubtract: number): Promise<number> {\n const targetNumber = await this.get(key) as any ?? 0;\n\n if (!isNumber(targetNumber)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"number\", typeOf(targetNumber));\n }\n if (numberToSubtract === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"numberToSubtract\");\n }\n if (!isNumber(numberToSubtract)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"numberToSubtract\", \"number\", typeOf(numberToSubtract));\n }\n return await this.set(key, targetNumber - numberToSubtract as any) as Promise<number>;\n }\n /**\n * Thêm một hoặc nhiều phần tử vào cuối array tại key-path.\n *\n * Method này sẽ:\n * - kiểm tra target có phải array không\n * - chỉ thêm các giá trị **chưa tồn tại** trong array\n *\n * ⚠️ Nếu key không tồn tại hoặc target không phải array\n * thì sẽ ném lỗi.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn tới array cần thêm phần tử.\n * @param values Một hoặc nhiều giá trị cần thêm.\n *\n * @returns Array sau khi thêm phần tử.\n *\n * @example\n * ```ts\n * await db.push(\"users.123.roles\", \"admin\");\n * ```\n *\n * @example\n * ```ts\n * await db.push(\"queue.songs\", song1, song2);\n * ```\n */\n public async push<P extends ObjectPath<V>>(key: AutocompletableString<P>, ...values: RestOrArray<ExtractFromArray<ObjectValue<V, P>>>): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n if (!values.length) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"values\");\n }\n const root = await this.all();\n const pathParts = key.split(\".\");\n let target = root;\n for (let i = 0; i < pathParts.length; i++) {\n const part = pathParts[i];\n if (!(part in target)) {\n throw new BlackCatError(\"INVALID_KEY\", key);\n }\n if (i === pathParts.length - 1) {\n if (!Array.isArray(target[part])) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(target[part]));\n }\n const uniqueValues = (values as any[]).filter(v => !target[part].includes(v));\n target[part].push(...uniqueValues);\n } else {\n target = target[part];\n }\n };\n const topKey = pathParts[0];\n await this.set(topKey, root[topKey]);\n return target[pathParts[pathParts.length - 1]];\n }\n /**\n * Thay thế phần tử trong array theo index.\n *\n * @typeParam P - Path trỏ đến array.\n *\n * @param key - Đường dẫn array.\n * @param targetArrayElementIndex - Index cần thay.\n * @param value - Giá trị mới.\n *\n * @returns Array sau khi thay thế.\n *\n * @throws BlackCatError\n * - INVALID_TYPE nếu index không phải number\n * - REQUIRED_PARAMETER_MISSING nếu thiếu value\n * - INVALID_KEY nếu path không tồn tại\n * - INVALID_TARGET nếu target không phải array\n *\n * @example\n * await db.pull(\"users\", 0, { id: 2 });\n */\n public async pull<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, targetArrayElementIndex: number, value: ExtractFromArray<ObjectValue<V, P>>,): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n if (!isNumber(targetArrayElementIndex)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"targetArrayElementIndex\", \"number\", typeOf(targetArrayElementIndex));\n };\n if (value === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"value\");\n };\n const root = await this.all();\n const pathParts = key.split(\".\");\n let target: any = root;\n for (let i = 0; i < pathParts.length; i++) {\n const part = pathParts[i];\n if (!(part in target)) {\n throw new BlackCatError(\"INVALID_KEY\", `Path \"${key}\" does not exist`);\n }\n if (i === pathParts.length - 1) {\n if (!Array.isArray(target[part])) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(target[part]));\n };\n const arr = target[part];\n const index = targetArrayElementIndex >= 0 ? targetArrayElementIndex : arr.length + targetArrayElementIndex;\n if (index < 0 || index >= arr.length) {\n console.error(`Index ${targetArrayElementIndex} is out of bounds`);\n };\n arr[index] = value;\n } else {\n target = target[part];\n };\n };\n await this.set(pathParts[0], root[pathParts[0]]);\n return target[pathParts[pathParts.length - 1]];\n }\n /**\n * Xóa phần tử khỏi array theo index.\n *\n * Có thể truyền nhiều index hoặc một array index.\n *\n * @typeParam P - Path trỏ đến array.\n *\n * @param key - Đường dẫn array.\n * @param targetArrayElementIndexes - Các index cần xóa.\n *\n * @returns Danh sách phần tử đã bị xóa.\n *\n * @throws BlackCatError\n * - INVALID_TARGET nếu target không phải array\n * - REQUIRED_PARAMETER_MISSING nếu thiếu index\n * - ONE_OR_MORE_ARRAY_TYPES_INVALID nếu index không phải number\n *\n * @example\n * await db.pop(\"users\", 0);\n * await db.pop(\"numbers\", [1, 2, 3]);\n */\n public async pop<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, ...targetArrayElementIndexes: RestOrArray<ExtractFromArray<number>>): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n const targetArray = await this.get(key) ?? [];\n\n if (!Array.isArray(targetArray)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(targetArray));\n };\n\n if (!targetArrayElementIndexes.length) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"targetArrayElementIndex\");\n };\n const indexes = Array.isArray(targetArrayElementIndexes[0]) ? (targetArrayElementIndexes[0] as number[]) : (targetArrayElementIndexes as number[]);\n if (indexes.some(index => !isNumber(index))) {\n throw new BlackCatError(\"ONE_OR_MORE_ARRAY_TYPES_INVALID\", \"targetArrayElementIndexes\", \"number\", createTypesArray(indexes));\n };\n\n const sortedIndexes = [...indexes].sort((a, b) => b - a);\n const removedElements: any[] = [];\n\n for (const index of sortedIndexes) {\n const removed = targetArray.splice(index, 1);\n removedElements.push(...removed);\n };\n\n const parentPath = key.split(\".\").slice(0, -1).join(\".\") as AutocompletableString<any>;\n const fieldName = key.split(\".\").slice(-1)[0];\n\n if (parentPath) {\n const parentObject = await this.get(parentPath) as Record<string, any> ?? {};\n parentObject[fieldName] = targetArray;\n await this.set(parentPath, parentObject as NonNullable<Exclude<ObjectValue<V, P>, undefined>>);\n } else {\n await this.set(key, targetArray as NonNullable<Exclude<ObjectValue<V, P>, undefined>>);\n };\n return removedElements;\n }\n /**\n * Kiểm tra xem giá trị tại key có phải là Array hay không.\n *\n * @typeParam P - Path của object trong database.\n * @param key - Đường dẫn key cần kiểm tra.\n *\n * @returns `true` nếu giá trị là Array, ngược lại `false`.\n *\n * @example\n * const result = await db.isTargetArray(\"users\");\n * console.log(result);\n */\n public async isTargetArray<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const target = await this.get(key);\n return Array.isArray(target);\n }\n /**\n * Kiểm tra xem giá trị tại key có phải là Number hay không.\n *\n * @typeParam P - Path của object trong database.\n *\n * @param key - Đường dẫn key cần kiểm tra.\n *\n * @returns `true` nếu giá trị là Number, ngược lại `false`.\n *\n * @example\n * const result = await db.isTargetNumber(\"stats.score\");\n * console.log(result);\n */\n public async isTargetNumber<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const target = await this.get(key);\n return isNumber(target);\n }\n /**\n * Lấy danh sách các key của object trong database.\n *\n * Nếu không truyền `key` → trả về các key cấp cao nhất của database.\n *\n * @typeParam P - Path của object.\n *\n * @param key - Path của object cần lấy danh sách key.\n *\n * @returns Mảng các key tồn tại (không bao gồm `null` hoặc `undefined`).\n *\n * @example\n * const rootKeys = await db.keys();\n * const userKeys = await db.keys(\"user\");\n */\n public async keys<P extends AutocompletableString<ObjectPath<V>>>(key?: P): Promise<ObjectPath<P>[]> {\n if (!key) return TypedObject.keys(await this.all()) as ObjectPath<P>[];\n const data = await this.get(key) as Record<string, any>;\n return TypedObject.keys(data).filter((key) => data[key] !== undefined && data[key] !== null) as any\n }\n /**\n * Lấy số lượng key cấp cao nhất trong database.\n *\n * @returns Tổng số key ở root level.\n *\n * @example\n * const count = await db.size();\n */\n public async size(): Promise<number> {\n const keys = await this.keys();\n return keys.length;\n }\n /**\n * Lấy danh sách các giá trị từ database.\n *\n * Nếu không truyền `key` → trả về toàn bộ values ở root level.\n * Nếu truyền `key` → trả về values của object tại path đó.\n *\n * @typeParam P - Path của object trong database.\n *\n * @param key - Đường dẫn object cần lấy values.\n *\n * @returns Mảng các giá trị.\n *\n * @example\n * const allValues = await db.values();\n *\n * const userValues = await db.values(\"users\");\n */\n public async values<P extends AutocompletableString<ObjectPath<V>>>(key?: P): Promise<ObjectValue<V, P>[]> {\n if (!key) return TypedObject.values(await this.all());\n const data = await this.get(key) as Record<string, any>;\n return TypedObject.values(data) as ObjectValue<V, P>[];\n }\n /**\n * Lấy ngẫu nhiên một phần tử từ array tại path được chỉ định.\n *\n * @typeParam P - Path trỏ đến array trong database.\n *\n * @param key - Đường dẫn đến array.\n *\n * @returns Một phần tử ngẫu nhiên trong array hoặc `null` nếu array rỗng.\n *\n * @throws BlackCatError\n * - INVALID_TARGET nếu giá trị tại key không phải array\n *\n * @example\n * const randomUser = await db.random(\"users\");\n */\n public async random<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<Maybe<ObjectValue<V, P>>> {\n const array = await this.get(key);\n if (!Array.isArray(array)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(array));\n }\n return array[Math.floor(Math.random() * array.length)] ?? null;\n }\n /**\n * Tìm phần tử đầu tiên thỏa điều kiện.\n *\n * Hoạt động tương tự `Array.prototype.find`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Phần tử đầu tiên thỏa điều kiện hoặc `null` nếu không tìm thấy.\n *\n * @example\n * const user = await db.find(u => u.id === 1);\n */\n public async find(queryFunction: QueryFunction<V>): Promise<Maybe<V>> {\n const values = await this.values();\n return values.find(queryFunction as QueryFunction<ObjectValue<V, any>>) as Promise<Maybe<V>> ?? null;\n }\n /**\n * Biến đổi tất cả giá trị trong database thành một mảng mới.\n *\n * Hoạt động giống `Array.prototype.map`.\n *\n * @typeParam TReturnType - Kiểu dữ liệu của phần tử trả về.\n *\n * @param queryFunction - Hàm transform từng phần tử.\n *\n * @returns Mảng kết quả sau khi transform.\n *\n * @example\n * const names = await db.map(user => user.name);\n */\n public async map<TReturnType>(queryFunction: QueryFunction<V, TReturnType>): Promise<TReturnType[]> {\n const values = await this.values();\n return values.map(queryFunction as QueryFunction<ObjectValue<V, any>, TReturnType>);\n }\n /**\n * Tìm index của phần tử đầu tiên thỏa điều kiện.\n *\n * Hoạt động giống `Array.prototype.findIndex`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Index của phần tử hoặc `-1` nếu không tìm thấy.\n *\n * @example\n * const index = await db.findIndex(user => user.id === 1);\n */\n public async findIndex(queryFunction: QueryFunction<V>): Promise<number> {\n const values = await this.values();\n return values.findIndex(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n /**\n * Lọc các phần tử thỏa điều kiện.\n *\n * Hoạt động giống `Array.prototype.filter`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Mảng các phần tử thỏa điều kiện.\n *\n * @example\n * const admins = await db.filter(user => user.role === \"admin\");\n */\n public async filter(queryFunction: QueryFunction<V>): Promise<V[]> {\n const values = await this.values();\n return values.filter(queryFunction as QueryFunction<ObjectValue<V, any>>) as any;\n }\n /**\n * Kiểm tra có ít nhất một phần tử thỏa điều kiện hay không.\n *\n * Hoạt động giống `Array.prototype.some`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns `true` nếu tồn tại phần tử thỏa điều kiện.\n *\n * @example\n * const hasAdmin = await db.some(user => user.role === \"admin\");\n */\n public async some(queryFunction: QueryFunction<V>): Promise<boolean> {\n const values = await this.values();\n return values.some(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n /**\n * Kiểm tra tất cả phần tử có thỏa điều kiện hay không.\n *\n * Hoạt động giống `Array.prototype.every`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns `true` nếu tất cả phần tử đều thỏa điều kiện.\n *\n * @example\n * const allActive = await db.every(user => user.active === true);\n */\n public async every(queryFunction: QueryFunction<V>): Promise<boolean> {\n const values = await this.values();\n return values.every(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n}","import { promises as fs } from \"fs\";\nimport { DatabaseDriver } from \"../types\";\n\n/**\n * Cấu hình khởi tạo cho {@link JSONDriver}.\n */\ninterface JSONDriverOptions {\n /**\n * Đường dẫn tới file JSON dùng làm database.\n *\n * Ví dụ:\n * ```ts\n * \"./database.json\"\n * \"./data/users.json\"\n * ```\n */\n filePath: string;\n /**\n * Nếu bật, nội dung JSON sẽ được **minify**\n * (không format khoảng trắng) để giảm dung lượng file.\n *\n * Nếu tắt, JSON sẽ được format với indentation để dễ đọc.\n *\n * @default false\n */\n minifyJSON?: boolean;\n}\n\n/**\n * Driver lưu trữ dữ liệu dạng JSON.\n *\n * ⚠️ Đây **không phải database hoàn chỉnh**.\n * Class này chỉ đóng vai trò **driver lưu trữ (storage layer)**\n * cho class chính `Database`.\n *\n * Toàn bộ logic xử lý key path (`a.b.c`), validate dữ liệu,\n * và các thao tác database sẽ được thực hiện trong class `Database`.\n *\n * `JSONDriver` chỉ chịu trách nhiệm:\n *\n * - Đọc dữ liệu từ file JSON\n * - Ghi dữ liệu xuống file JSON\n * \n * @example \n * ```ts\n * const database = new Database({\n * driber: new JSONDriver({\\\n * filePath: \"./database.json\",\n * minifyJSON: false\n * })\n * });\n * ```\n */\nexport class JSONDriver implements DatabaseDriver {\n /**\n * Đường dẫn tới file database JSON.\n */\n private filePath: string;\n /**\n * Cho biết có minify JSON khi ghi file hay không.\n */\n public minifyJSON: boolean;\n /**\n * Khởi tạo một instance mới của {@link JSONDriver}.\n *\n * @param options - Cấu hình driver\n *\n * @param options.filePath\n * Đường dẫn tới file JSON dùng làm database.\n *\n * @param options.minifyJSON\n * Nếu `true`, nội dung JSON sẽ được minify khi ghi ra file để giảm dung lượng.\n *\n * @example\n * ```ts\n * const database = new Database({\n * driver: db = new JSONDriver({\n * filePath: \"./database.json\"\n * })\n * });\n * ```\n */\n constructor(options: JSONDriverOptions) {\n this.filePath = options.filePath || \"database.json\";\n this.minifyJSON = options.minifyJSON || false;\n\n }\n /**\n * Đảm bảo file database tồn tại.\n * Nếu file chưa tồn tại sẽ tự động tạo file `{}`.\n */\n private async ensureFile(): Promise<void> {\n try {\n await fs.access(this.filePath);\n } catch {\n await fs.writeFile(this.filePath, \"{}\");\n }\n }\n /**\n * Đọc toàn bộ dữ liệu từ file database JSON.\n *\n * Nếu file không tồn tại hoặc lỗi parse,\n * method sẽ trả về object rỗng.\n *\n * @template V Kiểu dữ liệu database.\n * @returns Promise chứa toàn bộ dữ liệu database.\n */\n public async all<V>(): Promise<V> {\n await this.ensureFile();\n return fs.readFile(this.filePath, \"utf-8\").then((content) => JSON.parse(content) as V).catch((error) => {\n console.error(`Không thể đọc file database: ${this.filePath}`, error);\n return {} as V;\n });\n }\n /**\n * Ghi toàn bộ dữ liệu database xuống file JSON.\n *\n * Method này **không xử lý key path**.\n * Logic cập nhật dữ liệu sẽ được xử lý ở class `Database`\n * trước khi truyền object hoàn chỉnh vào đây.\n *\n * @param data Toàn bộ dữ liệu database sau khi đã được cập nhật.\n *\n * @template R Kiểu dữ liệu database.\n * @returns Promise chứa dữ liệu đã ghi.\n */\n public async set<R = any>(data: R): Promise<R> {\n await this.ensureFile();\n await fs.writeFile(this.filePath, JSON.stringify(data, null, this.minifyJSON ? undefined : \"\\t\"));\n return data;\n }\n /**\n * Xóa toàn bộ database.\n *\n * Method này chỉ reset file JSON về `{}`.\n *\n * @returns `true` nếu reset thành công.\n */\n public async delete(): Promise<boolean> {\n await this.ensureFile();\n await fs.writeFile(this.filePath, \"{}\");\n return true;\n }\n}","import { DatabaseDriver } from \"../types\";\r\n\r\n/**\r\n * Driver lưu trữ dữ liệu trong RAM.\r\n *\r\n * ⚠️ Đây **không phải database chính**.\r\n * Class này chỉ là **storage driver phụ trợ** cho class `Database`.\r\n *\r\n * Toàn bộ logic xử lý:\r\n * - key path (`a.b.c`)\r\n * - validation\r\n * - update dữ liệu\r\n *\r\n * đều được thực hiện trong class `Database`.\r\n *\r\n * `MemoryDriver` chỉ chịu trách nhiệm:\r\n * - lưu trữ object database trong RAM\r\n * - trả về toàn bộ dữ liệu\r\n *\r\n * Dữ liệu sẽ **mất khi ứng dụng restart**.\r\n *\r\n * Phù hợp cho:\r\n * - testing\r\n * - cache runtime\r\n * - development\r\n * \r\n * @example\r\n * ```ts\r\n * const database = new Database({\r\n * driver: new MemoryDriver({\r\n * users: {},\r\n * guilds: {},\r\n * settings: {\r\n * prefix: \"!\"\r\n * }\r\n * })\r\n * });\r\n * ```\r\n * \r\n * hoặc \r\n * \r\n * ```ts\r\n * const database = new Database({\r\n * driver: new MemoryDriver()\r\n * });\r\n * ```\r\n */\r\nexport class MemoryDriver implements DatabaseDriver {\r\n /**\r\n * Object chứa toàn bộ dữ liệu database trong RAM.\r\n */\r\n private store: Record<string, any>;\r\n /**\r\n * Khởi tạo MemoryDriver.\r\n *\r\n * @param initialData Dữ liệu khởi tạo ban đầu.\r\n * * @example\r\n * ```ts\r\n * const database = new Database({\r\n * driver: new MemoryDriver({\r\n * users: {},\r\n * guilds: {},\r\n * settings: {\r\n * prefix: \"!\"\r\n * }\r\n * })\r\n * });\r\n * ```\r\n * \r\n * hoặc \r\n * \r\n * ```ts\r\n * const database = new Database({\r\n * driver: new MemoryDriver()\r\n * });\r\n * ```\r\n */\r\n constructor(initialData: Record<string, any> = {}) {\r\n this.store = initialData;\r\n }\r\n /**\r\n * Trả về toàn bộ dữ liệu database.\r\n *\r\n * @template T Kiểu dữ liệu database.\r\n */\r\n public async all<T = any>(): Promise<T> {\r\n return this.store as T;\r\n }\r\n /**\r\n * Ghi toàn bộ database vào memory.\r\n *\r\n * ⚠️ Method này **không xử lý key-path**.\r\n * Dữ liệu đã được xử lý trước bởi `Database`.\r\n *\r\n * @param data Toàn bộ database object\r\n */\r\n public async set<T = any>(data: T): Promise<T> {\r\n this.store = data as any;\r\n return data;\r\n }\r\n /**\r\n * Xóa toàn bộ dữ liệu database trong memory.\r\n */\r\n public async delete(): Promise<boolean> {\r\n this.store = {};\r\n return true;\r\n }\r\n}","import SQLite from \"better-sqlite3\";\r\nimport { DatabaseDriver } from \"../types\";\r\n\r\n/**\r\n * Các tùy chọn cấu hình cho SQLiteDriver.\r\n * @hidden\r\n *\r\n * Interface này định nghĩa các thiết lập được sử dụng khi\r\n * khởi tạo driver SQLite cho hệ thống database.\r\n */\r\ninterface SQLiteDriverOptions {\r\n /**\r\n * Đường dẫn đến file cơ sở dữ liệu SQLite.\r\n *\r\n * Nếu không được cung cấp, driver có thể tạo\r\n * một file database mặc định tùy theo cách triển khai.\r\n *\r\n * Ví dụ:\r\n * `\"./database.sqlite\"`\r\n */\r\n filePath?: string;\r\n /**\r\n * Tên bảng được sử dụng để lưu trữ dữ liệu key-value.\r\n *\r\n * Nếu không được chỉ định, driver có thể sử dụng\r\n * một tên bảng mặc định (ví dụ: `\"data\"`).\r\n *\r\n * Ví dụ:\r\n * `\"storage\"`\r\n */\r\n table?: string;\r\n}\r\n/**\r\n * Driver lưu trữ dữ liệu bằng SQLite.\r\n *\r\n * ⚠️ Đây **không phải database chính**.\r\n * Class này chỉ là **driver lưu trữ phụ trợ** cho `Database`.\r\n *\r\n * Logic xử lý dữ liệu như:\r\n * - parse key path\r\n * - update object\r\n * - validation\r\n *\r\n * sẽ được thực hiện bởi class `Database`.\r\n *\r\n * Driver này chỉ:\r\n * - serialize database thành JSON\r\n * - lưu JSON vào SQLite\r\n * - trả về JSON khi đọc\r\n *\r\n * Toàn bộ database được lưu trong **một row duy nhất**.\r\n * \r\n * @example\r\n * ```ts\r\n * const database = new Database({\r\n * driver: new SQLiteDriver({\r\n * filePath: \"database.sqlite\",\r\n * table: \"json_store\"\r\n * })\r\n * })\r\n * ```\r\n */\r\nexport class SQLiteDriver implements DatabaseDriver {\r\n /**\r\n * SQLite database instance.\r\n */\r\n private db: SQLite.Database;\r\n /**\r\n * Tên table lưu trữ dữ liệu JSON.\r\n */\r\n private table: string;\r\n /**\r\n * Khởi tạo SQLiteDriver.\r\n *\r\n * @param filePath Đường dẫn file SQLite\r\n * @param table Tên table lưu JSON database\r\n * @example\r\n * ```ts\r\n * const database = new Database({\r\n * driver: new SQLiteDriver({\r\n * filePath: \"database.sqlite\",\r\n * table: \"json_store\"\r\n * })\r\n * })\r\n * ```\r\n */\r\n constructor(options: SQLiteDriverOptions = {}) {\r\n this.db = new SQLite(options.filePath ?? \"database.sqlite\");\r\n this.table = options.table ?? \"json_store\";\r\n this.db.prepare(`CREATE TABLE IF NOT EXISTS ${this.table} (id INTEGER PRIMARY KEY, data TEXT)`).run();\r\n const row = this.db.prepare(`SELECT * FROM ${this.table} WHERE id = 1`).get();\r\n if (!row) {\r\n this.db.prepare(`INSERT INTO ${this.table} (id, data) VALUES (1, '{}')`).run();\r\n }\r\n }\r\n /**\r\n * Lấy toàn bộ dữ liệu database từ SQLite.\r\n *\r\n * @template T Kiểu dữ liệu database.\r\n */\r\n public async all<T = any>(): Promise<T> {\r\n const row = this.db.prepare(`SELECT data FROM ${this.table} WHERE id = 1`).get() as { data: string };\r\n return JSON.parse(row.data) as T;\r\n }\r\n /**\r\n * Ghi toàn bộ database vào SQLite.\r\n *\r\n * ⚠️ Method này **không xử lý key-path**.\r\n * `Database` đã cập nhật object trước khi truyền vào đây.\r\n *\r\n * @param data Toàn bộ database object\r\n */\r\n public async set<T = any>(data: T): Promise<T> {\r\n this.db.prepare(`UPDATE ${this.table} SET data = ? WHERE id = 1`).run(JSON.stringify(data));\r\n return data;\r\n }\r\n /**\r\n * Reset toàn bộ database.\r\n */\r\n public async delete(): Promise<boolean> {\r\n this.db.prepare(`UPDATE ${this.table} SET data = '{}' WHERE id = 1`).run();\r\n return true;\r\n }\r\n}","import { MongoClient, Db, Collection } from \"mongodb\";\r\nimport type { DatabaseDriver } from \"../types\";\r\n\r\n/**\r\n * Cấu hình cho MongoDriver.\r\n */\r\ninterface MongoDriverOptions {\r\n /**\r\n * Chuỗi kết nối MongoDB.\r\n *\r\n * @default \"mongodb://localhost:27017\"\r\n */\r\n mongourl?: string;\r\n /**\r\n * Tên database MongoDB.\r\n *\r\n * @default \"database\"\r\n */\r\n databaseName?: string;\r\n /**\r\n * Tên collection lưu dữ liệu JSON.\r\n *\r\n * @default \"json_store\"\r\n */\r\n collectionName?: string;\r\n}\r\n/**\r\n * Schema document dùng để lưu trữ database trong MongoDB.\r\n */\r\ninterface DatabaseDocument<V = any> {\r\n _id: string;\r\n data: V;\r\n}\r\n/**\r\n * Driver lưu trữ dữ liệu bằng MongoDB.\r\n *\r\n * ⚠️ Đây **không phải database chính**.\r\n * Class này chỉ là **driver lưu trữ phụ trợ** cho class `Database`.\r\n *\r\n * Logic xử lý:\r\n * - parse key path\r\n * - validate dữ liệu\r\n * - cập nhật object\r\n *\r\n * sẽ được xử lý bởi class `Database`.\r\n *\r\n * `MongoDriver` chỉ chịu trách nhiệm:\r\n * - lưu toàn bộ database object\r\n * - trả về database object\r\n *\r\n * Toàn bộ database được lưu trong **một document duy nhất**.\r\n * \r\n * @example \r\n * ```ts\r\n * const database = new Database({ \r\n * driver: new MongoDriver({\r\n * mongourl: \"mongodb://localhost:27017\", \r\n * databaseName: \"mydb\", \r\n * collectionName: \"store\" \r\n * })\r\n * });\r\n * ```\r\n */\r\nexport class MongoDriver implements DatabaseDriver {\r\n /**\r\n * MongoDB client instance.\r\n */\r\n private client: MongoClient;\r\n /**\r\n * MongoDB database instance.\r\n */\r\n private db!: Db;\r\n /**\r\n * Collection lưu dữ liệu JSON.\r\n */\r\n private collection!: Collection<DatabaseDocument>;\r\n /**\r\n * Tên database MongoDB.\r\n */\r\n private databaseName: string;\r\n /**\r\n * Tên collection MongoDB.\r\n */\r\n private collectionName: string;\r\n /**\r\n * Khởi tạo MongoDriver.\r\n *\r\n * @param options Cấu hình MongoDB driver.\r\n * \r\n * @example \r\n * ```ts\r\n * const database = new Database({ \r\n * driver: new MongoDriver({\r\n * mongourl: \"mongodb://localhost:27017\", \r\n * databaseName: \"mydb\", \r\n * collectionName: \"store\" \r\n * })\r\n * });\r\n */\r\n constructor(options: MongoDriverOptions = {}) {\r\n const {\r\n mongourl = \"mongodb://localhost:27017\",\r\n databaseName = \"database\",\r\n collectionName = \"json_store\"\r\n } = options;\r\n this.client = new MongoClient(mongourl);\r\n this.databaseName = databaseName;\r\n this.collectionName = collectionName;\r\n }\r\n /**\r\n * Thiết lập kết nối MongoDB nếu chưa kết nối.\r\n */\r\n private async connect(): Promise<void> {\r\n if (!this.db) {\r\n await this.client.connect();\r\n this.db = this.client.db(this.databaseName);\r\n this.collection = this.db.collection(this.collectionName);\r\n const doc = await this.collection.findOne({ _id: \"database\" });\r\n if (!doc) {\r\n await this.collection.insertOne({\r\n _id: \"database\",\r\n data: {}\r\n });\r\n }\r\n }\r\n }\r\n /**\r\n * Lấy toàn bộ dữ liệu database từ MongoDB.\r\n */\r\n public async all<T = any>(): Promise<T> {\r\n await this.connect();\r\n const doc = await this.collection.findOne({ _id: \"database\" });\r\n return (doc?.data ?? {}) as T;\r\n }\r\n /**\r\n * Ghi toàn bộ database vào MongoDB.\r\n *\r\n * ⚠️ Method này **không xử lý key-path**.\r\n * Object database đã được xử lý bởi class `Database`.\r\n * \r\n * @param data Toàn bộ object database\r\n */\r\n public async set<T = any>(data: T): Promise<T> {\r\n await this.connect();\r\n await this.collection.updateOne(\r\n { _id: \"database\" },\r\n { $set: { data } }\r\n );\r\n return data;\r\n }\r\n /**\r\n * Reset toàn bộ database về object rỗng.\r\n */\r\n public async delete(): Promise<boolean> {\r\n await this.connect();\r\n await this.collection.updateOne(\r\n { _id: \"database\" },\r\n { $set: { data: {} } }\r\n );\r\n return true;\r\n }\r\n}"],"mappings":"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","names":["key","fs","SQLite"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils/isObject.function.ts","../src/utils/typeOf.function.ts","../src/utils/isNumber.function.ts","../src/utils/BlackCatError.ts","../src/utils/TypedObject.ts","../src/utils/Emitter.ts","../src/Database.ts","../src/drivers/JSONDriver.ts","../src/drivers/MemoryDriver.ts","../src/drivers/SQLiteDriver.ts","../src/drivers/MongoDriver.ts"],"sourcesContent":["export * from \"./Database.ts\";\nexport * from \"./drivers\";","/**\n * Checks for is the item object and returns it.\n * @param {any} item The item to check.\n * @returns {boolean} Is the item object or not.\n */\nexport const isObject = (item: any): boolean => !Array.isArray(item) && item !== null && typeof item == \"object\";","/**\n * Returns the exact type of a given input.\n * @param input - The value to check.\n * @returns A string representing the exact type of the input.\n */\nexport const typeOf = (input: any): string => {\n // ✅ Handle special cases: null, undefined, and NaN\n if (input == null || (typeof input === \"number\" && Number.isNaN(input))) return String(input);\n // ✅ If it's a class constructor (has a prototype)\n if (typeof input === \"function\" && input.prototype) return `${input.name} class instance`;\n // ✅ If it's an object or function, return the constructor name if available\n return input?.constructor?.name ?? typeof input;\n};","import { typeOf } from \"./typeOf.function\";\n\n/**\n * Determines if the specified value is a number.\n *\n * A small hack to actually determine if the input is a number since\n * empty strings and arrays are considered as numbers too.\n * @param {any} input The input to check.\n * @returns {boolean} Whether the specified input is a number.\n */\nexport const isNumber = (input: any): boolean => !isNaN(input as number) && input !== \"\" && input !== null && typeOf(input) !== \"Array\";","import { typeOf } from \"./typeOf.function\";\n\nexport type TargetParamType = \"string\" | \"number\" | \"object\" | \"array\" | `${string} class instance`;\n\nexport const errors = {\n DEVICE_IS_OFFLINE: 'Your device appears to be offline so it\\'s impossible to proceed with ' + 'connection to your online MongoDB cluster. Please connect your device to the internet or switch to the ' + 'local MongoDB database and try again.',\n CONNECTION_NOT_ESTABLISHED: 'Failed to connect to MongoDB. Please double-check the specified ' + 'connection URI and make sure that you\\'re performing the ' + 'database connection using the `QuickMongoClient.connect()` method.',\n CONNECTION_URI_NOT_SPECIFIED: 'The MongoDB connection URI must be specified.',\n INVALID_CONNECTION_URI: 'The specified MongoDB connection URI is invalid.',\n UNKNOWN_ERROR: 'Unknown error.',\n REQUIRED_PARAMETER_MISSING: '\\'{1}\\' parameter is required but is missing.',\n REQUIRED_CONSTRUCTOR_PARAMETER_MISSING: '\\'{1}\\' parameter in constructor \\'{2}\\' is required but is missing.',\n INVALID_CONSTRUCTOR_PARAMETER_TYPE: '\\'{1}\\' parameter in constructor \\'{2}\\' must be ' + 'a type of {3}. Received type: {4}.',\n INVALID_TYPE: '\\'{1}\\' must be a type of {2}. Received type: {3}.',\n ONE_OR_MORE_ARRAY_TYPES_INVALID: 'All specified elements from array in \\'{1}\\' parameter ' + 'must be a type of {2}. Received array of types: {3}.',\n INVALID_TARGET: 'The target in database must be a type of {1}. Received target type: {2}.',\n INVALID_KEY: \"{1}\",\n INVALID_PARAMETER: \"{1} {2}\",\n DATABASE_CONNECTION_FAILED: \"{1}\"\n}\n\nexport interface ErrorParams extends Record<keyof typeof errors, string[]> {\n CONNECTION_NOT_ESTABLISHED: [];\n UNKNOWN_ERROR: [];\n CONNECTION_URI_NOT_SPECIFIED: [];\n INVALID_CONNECTION_URI: [];\n REQUIRED_PARAMETER_MISSING: [missingParam: string];\n REQUIRED_CONSTRUCTOR_PARAMETER_MISSING: [missingParam: string, className: string];\n INVALID_TYPE: [paramName: string, targetType: TargetParamType, receivedType: string];\n INVALID_CONSTRUCTOR_PARAMETER_TYPE: [paramName: string, className: string, targetType: TargetParamType, receivedType: string];\n ONE_OR_MORE_ARRAY_TYPES_INVALID: [paramName: string, targetType: TargetParamType, receivedTypesArray: string];\n INVALID_TARGET: [targetType: TargetParamType, receivedType: string];\n INVALID_KEY: [paramName: string];\n INVALID_PARAMETER: [paramName: string, receivedType: string];\n DATABASE_CONNECTION_FAILED: [paramName: string]\n}\nexport const createTypesArray = <T>(...elements: any): string => `[${elements.map((element: any) => typeOf(element))}]`;\n/**\n * BlackCatError class.\n */\nexport class BlackCatError<TErrorCode extends keyof typeof errors> extends Error {\n /** \n * Creates a BlackCatError instance.\n * @param {string} errorCode Quick Mongo error code.\n * @param {any[]} params Additional parameters to replace the placeholders in the error message.\n */\n public constructor(errorCode: TErrorCode, ...params: ErrorParams[TErrorCode]) {\n const code = errors[errorCode] ? errorCode : \"UNKNOWN_ERROR\" as TErrorCode;\n let message = errors[code];\n for (let i = 0; i < params.length; i++) {\n message = message.replaceAll(`{${i + 1}}`, params[i]);\n };\n super(message);\n /**\n * The name of the error.\n */\n this.name = `BlackCatError [${code}]`;\n }\n}","import { ExtractObjectKeys, ExtractObjectValues, ExtractObjectEntries } from \"../types\";\n\n/**\n * Utility class for working with objects.\n *\n * Provides **static** methods for retrieving keys and values of an object with addition of types.\n *\n * This class enhances type safety by providing better typings for object keys and values.\n */\nexport class TypedObject {\n /**\n * Returns the names of the enumerable string properties and methods of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object keys types from.\n *\n * @param {TObject} obj Object to get the keys from.\n *\n * @returns {Array<ExtractObjectKeys<TObject>>}\n * Array of names of the enumerable string properties and methods of the specified object.\n */\n public static keys<TObject extends Record<string, any>>(obj: TObject): ExtractObjectKeys<TObject>[] {\n return Object.keys(obj || {});\n }\n /**\n * Returns an array of values of the enumerable properties of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object values types from.\n *\n * @param {TObject} obj Object to get the values from.\n *\n * @returns {Array<ExtractObjectValues<TObject>>}\n * Array of values of the enumerable properties of the specified object.\n */\n public static values<TObject extends Record<string, any>>(obj: TObject): ExtractObjectValues<TObject>[] {\n return Object.values(obj || {});\n }\n /**\n * Returns an array of entries (key-value pairs) of the enumerable properties of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object entries types (key-value pairs types) from.\n *\n * @param {TObject} obj Object to get the entries from.\n *\n * @returns {ExtractObjectEntries<TObject>[]}\n * Array of entries (key-value pairs) of the enumerable properties of the specified object.\n */\n public static entries<TObject extends Record<string, any>>(obj: TObject): ExtractObjectEntries<TObject>[] {\n return Object.entries(obj || {})\n }\n}","import { EventEmitter } from \"node:events\";\n\nexport class Emitter<E extends Record<string, any>> {\n private _emitter = new EventEmitter();\n /**\n * Listens to the event.\n * @param {string} event Event name.\n * @param {Function} listener Listener function.\n */\n public on<K extends Exclude<keyof E, number>>(event: K, listener: (...args: E[K]) => any): Emitter<E> {\n this._emitter.on(event, listener);\n return this;\n }\n /**\n * Listens to the event only for once.\n * @param {string} event Event name.\n * @param {Function} listener Listener function.\n */\n public once<K extends Exclude<keyof E, number>>(event: K, listener: (...args: E[K]) => any): Emitter<E> {\n this._emitter.once(event, listener);\n return this;\n }\n /**\n * Emits the event.\n * @param {string} event Event name.\n * @param {any[]} args Listener arguments.\n * @returns {boolean} `true` if the event had listeners, `false` otherwise.\n */\n public emit<K extends Exclude<keyof E, number>>(event: K, ...args: E[K]): boolean {\n return this._emitter.emit(event, ...args as any[]);\n }\n}","import { DatabaseConfiguration, AutocompletableString, FirstObjectKey, If, IsObject, ObjectPath, ObjectValue, Maybe, QueryFunction, RestOrArray, ExtractFromArray, DatabaseDriver, ArrayElement } from \"./types\";\nimport { BlackCatError, createTypesArray, isNumber, typeOf, TypedObject, isObject } from \"./utils\";\n\n/**\n * Class Database cung cấp API thao tác dữ liệu dạng key-path\n * trên nhiều loại storage khác nhau thông qua `DatabaseDriver`.\n *\n * Đây là **lớp database chính (logic layer)** của hệ thống.\n *\n * Class này chịu trách nhiệm:\n * - parse key path (`user.profile.name`)\n * - validate dữ liệu\n * - thao tác object\n * - query dữ liệu (find, filter, map...)\n *\n * Việc lưu trữ dữ liệu thực tế sẽ được thực hiện bởi các **driver phụ trợ**\n * như:\n *\n * - `JSONDriver`\n * - `MemoryDriver`\n * - `SQLiteDriver`\n * - `MongoDriver`\n *\n * Các driver này chỉ chịu trách nhiệm:\n * - đọc toàn bộ dữ liệu database\n * - ghi toàn bộ dữ liệu database\n *\n * @template V Kiểu dữ liệu tổng thể của database.\n */\nexport class Database<V = any> {\n /**\n * Storage driver được sử dụng để đọc và ghi dữ liệu database.\n *\n * Driver phải implement interface `DatabaseDriver`.\n *\n * Ví dụ:\n * ```ts\n * const db = new Database({\n * driver: new JSONDriver({ filePath: \"./database.json\" }),\n * })\n * ```\n */\n public driver: DatabaseDriver;\n /**\n * Khởi tạo Database instance.\n *\n * @param options Cấu hình database.\n * @param options.driver Driver lưu trữ dữ liệu.\n *\n * @example\n * ```ts\n * const db = new Database({\n * driver: new JSONDriver({ filePath: \"./database.json\" }),\n * })\n * ```\n *\n * Ví dụ với MongoDB:\n *\n * ```ts\n * const db = new Database({\n * driver: new MongoDriver({\n * uri: \"mongodb://localhost:27017\",\n * databaseName: \"mydb\"\n * })\n * });\n * ```\n */\n constructor(options: DatabaseConfiguration) {\n this.driver = options.driver;\n }\n /**\n * Lấy toàn bộ dữ liệu từ database thông qua driver.\n *\n * @template T Kiểu dữ liệu object database trả về.\n *\n * @returns Promise chứa toàn bộ dữ liệu database.\n *\n * @example\n * ```ts\n * const data = await db.all();\n * console.log(data.users);\n * ```\n */\n public async all<T extends Record<string, any> = Record<string, any>>(): Promise<T> {\n return await this.driver.all<T>();\n }\n /**\n * Lấy giá trị từ database theo key-path.\n *\n * Key có thể là chuỗi dạng path:\n *\n * ```\n * user.profile.name\n * economy.users.123.balance\n * ```\n *\n * Nếu không truyền `key`, method sẽ trả về **toàn bộ database**.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần lấy.\n *\n * @returns Giá trị tại key hoặc `null` nếu không tồn tại.\n *\n * @example\n * ```ts\n * const name = await db.get(\"user.profile.name\");\n * ```\n *\n * @example\n * ```ts\n * const all = await db.get();\n * ```\n */\n public async get<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>): Promise<Maybe<ObjectValue<V, P>> | V> {\n const data = await this.all();\n if (key === undefined) return data as V;\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeOf(key));\n }\n const keys = key.split(\".\");\n let result: any = data;\n for (const k of keys) {\n if (!isObject(result) && !Array.isArray(result)) return null;\n result = result[k];\n if (result === undefined) return null;\n }\n return result;\n }\n /**\n * Tìm và trả về một bản ghi đầu tiên khớp với điều kiện trong database.\n *\n * Hàm này có hai cách sử dụng:\n *\n * 1. **Chỉ truyền `key`**\n * → Trả về toàn bộ dữ liệu của key (tương tự `get()`).\n *\n * 2. **Truyền `key` và `query`**\n * → Tìm phần tử đầu tiên trong mảng dữ liệu của key khớp với điều kiện.\n *\n * @template V - Kiểu dữ liệu của database.\n * @template P - Đường dẫn key trong object (`ObjectPath<V>`).\n *\n * @param key - Key hoặc đường dẫn đến dữ liệu cần truy vấn.\n * @param query - Đối tượng điều kiện để tìm bản ghi phù hợp.\n *\n * @returns\n * - Nếu chỉ có `key`: trả về toàn bộ dữ liệu của key.\n * - Nếu có `query`: trả về bản ghi đầu tiên khớp điều kiện.\n * - Nếu không tìm thấy: trả về `null`.\n *\n * @example\n * Chỉ lấy dữ liệu theo key\n * ```ts\n * const users = await db.findOne(\"user\");\n * ```\n *\n * @example\n * Tìm một bản ghi theo điều kiện\n * ```ts\n * const user = await db.findOne(\"user\", {\n * guild: 1234566\n * });\n * ```\n */\n public async findOne<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>, query?: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<Maybe<ObjectValue<V, P>> | V> {\n const data = await this.get(key as any);\n if (!query) return data;\n if (!Array.isArray(data)) return null as Maybe<ObjectValue<V, P>>;\n const result = data.find((item) => {\n return Object.entries(query as Record<string, any>).every(([k, v]) => item[k] == v);\n });\n return (result ?? null) as Maybe<ObjectValue<V, P>>;\n }\n /**\n * Kiểm tra một key-path có tồn tại trong database hay không.\n *\n * Method này sử dụng `get()` để xác định giá trị có tồn tại.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần kiểm tra.\n *\n * @returns `true` nếu key tồn tại, ngược lại `false`.\n *\n * @example\n * ```ts\n * const exists = await db.has(\"users.123\");\n * ```\n */\n public async has<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const value = await this.get(key);\n return value !== null && value !== undefined;\n }\n /**\n * Gán giá trị cho một key-path trong database.\n *\n * Nếu key-path chưa tồn tại, các object trung gian\n * sẽ được tự động tạo.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần gán giá trị.\n * @param {ObjectValue<V, P>} value Giá trị mới.\n *\n * @returns {Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>>} Giá trị vừa được set hoặc object root nếu value là object.\n *\n * @example\n * ```ts\n * await db.set(\"users.123.name\", \"Alice\");\n * ```\n *\n * @example\n * ```ts\n * await db.set(\"config.prefix\", \"!\");\n * ```\n */\n public async set<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, value: ObjectValue<V, P>): Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>> {\n const allDatabase = await this.all();\n if (!key) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"key\");\n }\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeOf(key));\n }\n const keys = key.split(\".\");\n let currentObj = allDatabase;\n\n for (let i = 0; i < keys.length; i++) {\n if (keys.length - 1 === i) {\n currentObj[keys[i]] = value\n } else {\n if (!isObject(currentObj[keys[i]])) {\n currentObj[keys[i]] = {};\n }\n currentObj = currentObj[keys[i]];\n };\n };\n await this.driver.set(allDatabase);\n return typeof value == \"object\" && value !== null ? await this.get(keys[0]) as any : value as any;\n }\n /**\n * Xóa một key khỏi database.\n *\n * Hỗ trợ nested path bằng dot notation.\n *\n * @typeParam P - Path của object.\n *\n * @param key - Đường dẫn key cần xóa.\n *\n * @returns\n * - `true` nếu xóa thành công\n * - `false` nếu key không tồn tại\n *\n * @throws BlackCatError\n * - INVALID_TYPE nếu key không phải string\n *\n * @example\n * await db.delete(\"user.name\");\n */\n public async delete<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>): Promise<boolean> {\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeof key);\n }\n const allDatabase = await this.all();\n const keys = key.split(\".\");\n const lastKey = keys.pop() as string;\n let currentObj: any = allDatabase;\n for (const k of keys) {\n if (!isObject(currentObj[k])) {\n return false;\n }\n currentObj = currentObj[k];\n }\n if (!(lastKey in currentObj)) return false;\n delete currentObj[lastKey];\n await this.driver.set(allDatabase);\n return true;\n }\n /**\n * Xóa toàn bộ dữ liệu trong database.\n *\n * Method này gọi trực tiếp `driver.delete()` để reset storage.\n *\n * @returns `true` sau khi dữ liệu đã được xóa.\n *\n * @example\n * await db.deleteAll();\n */\n public async deleteAll(): Promise<boolean> {\n await this.driver.delete();\n return true;\n }\n /**\n * Xóa nhiều bản ghi trong một mảng dữ liệu dựa trên điều kiện truy vấn.\n *\n * ⚠️ Method này **chỉ hoạt động với dữ liệu dạng mảng (array)**.\n * Nếu dữ liệu tại `key` không phải là mảng, method sẽ **không thực hiện xóa**\n * và trả về `0`.\n *\n * Method sẽ duyệt qua toàn bộ phần tử trong mảng và xóa những phần tử\n * khớp với điều kiện `query`.\n *\n * @template V - Kiểu dữ liệu của database.\n * @template P - Đường dẫn key trong object (`ObjectPath<V>`).\n *\n * @param key - Đường dẫn đến mảng dữ liệu cần thao tác.\n * @param query - Điều kiện để xác định các phần tử cần xóa.\n * Có thể truyền:\n * - Một object điều kiện\n *\n * @returns Số lượng phần tử đã bị xóa khỏi mảng.\n *\n * @example\n * Database mẫu:\n * ```json\n * {\n * \"member\": {\n * \"user\": {\n * \"database\": [\n * { \"guild\": \"123\", \"username\": \"vinh\" },\n * { \"guild\": \"456\", \"username\": \"test\" }\n * ]\n * }\n * }\n * }\n * ```\n *\n * @example\n * Xóa tất cả user có guild = \"123\"\n * ```ts\n * await db.deleteMany(\"member.user.database\", {\n * guild: \"123\"\n * });\n * ```\n */\n public async deleteMany<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, query: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<number> {\n const data = await this.get(key as any);\n if (!Array.isArray(data)) return 0;\n const originalLength = data.length;\n const filtered = data.filter((item: any) => {\n return !Object.entries(query as Record<string, any>).every(([k, v]) => item[k] == v);\n });\n await this.set(key, filtered as any);\n\n return originalLength - filtered.length;\n }\n /**\n * Cập nhật dữ liệu trong database theo đường dẫn key.\n *\n * Hàm này sẽ tìm đến vị trí của `key` trong database và gán `value` vào đó.\n * Nếu `value` và giá trị hiện tại tại key đều là object thì sẽ thực hiện\n * **shallow merge** thay vì ghi đè toàn bộ object.\n *\n * Điều này giúp tránh việc làm mất các thuộc tính đã tồn tại.\n *\n * @template P - Đường dẫn key hợp lệ trong object database.\n *\n * @param key - Đường dẫn tới giá trị cần cập nhật.\n * Hỗ trợ nested path dạng `\"a.b.c\"`.\n *\n * @param value - Giá trị mới sẽ được cập nhật tại key.\n *\n * @returns\n * Trả về giá trị cuối cùng sau khi cập nhật.\n *\n * @example\n * Database ban đầu:\n * ```json\n * {\n * \"123\": {\n * \"guildID\": \"123\",\n * \"guildName\": \"BlackCat\",\n * \"history\": []\n * }\n * }\n * ```\n *\n * Cập nhật:\n * ```ts\n * await db.update(\"123\", {\n * history: [1,2,3]\n * });\n * ```\n *\n * Kết quả:\n * ```json\n * {\n * \"123\": {\n * \"guildID\": \"123\",\n * \"guildName\": \"BlackCat\",\n * \"history\": [1,2,3]\n * }\n * }\n * ```\n *\n * @throws {BlackCatError}\n * - `REQUIRED_PARAMETER_MISSING` nếu key không được cung cấp\n * - `INVALID_TYPE` nếu key không phải string\n */\n public async update<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, value: ObjectValue<V, P>): Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>> {\n if (!key) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"key\");\n }\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeOf(key));\n }\n const allDatabase = await this.all();\n const keys = key.split(\".\");\n let current: any = allDatabase;\n for (let i = 0; i < keys.length - 1; i++) {\n const part = keys[i];\n if (!isObject(current[part])) {\n current[part] = {};\n }\n current = current[part];\n }\n\n const lastKey = keys[keys.length - 1];\n if (isObject(value) && isObject(current[lastKey])) {\n current[lastKey] = {\n ...current[lastKey],\n ...value\n };\n } else {\n current[lastKey] = value;\n }\n await this.driver.set(allDatabase);\n return current[lastKey];\n }\n /**\n * Cộng thêm giá trị vào một key dạng number.\n *\n * Nếu key chưa tồn tại, giá trị mặc định sẽ là `0`.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn dữ liệu dạng number.\n * @param numberToAdd Số cần cộng thêm.\n *\n * @returns Giá trị mới sau khi cộng.\n *\n * @example\n * ```ts\n * await db.add(\"economy.users.123.balance\", 50);\n * ```\n */\n public async add<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, numberToAdd: number): Promise<number> {\n const targetNumber = await this.get(key) as any ?? 0;\n\n if (!isNumber(targetNumber)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"number\", typeOf(targetNumber));\n }\n if (numberToAdd === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"numberToAdd\");\n }\n if (!isNumber(numberToAdd)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"numberToAdd\", \"number\", typeOf(numberToAdd));\n }\n return await this.set(key, targetNumber + numberToAdd) as Promise<number>;\n }\n /**\n * Trừ giá trị khỏi một key dạng number.\n *\n * Nếu key chưa tồn tại, giá trị mặc định sẽ là `0`.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn dữ liệu dạng number.\n * @param numberToSubtract Số cần trừ.\n *\n * @returns Giá trị mới sau khi trừ.\n *\n * @example\n * ```ts\n * await db.subtract(\"economy.users.123.balance\", 20);\n * ```\n */\n public async subtract<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, numberToSubtract: number): Promise<number> {\n const targetNumber = await this.get(key) as any ?? 0;\n\n if (!isNumber(targetNumber)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"number\", typeOf(targetNumber));\n }\n if (numberToSubtract === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"numberToSubtract\");\n }\n if (!isNumber(numberToSubtract)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"numberToSubtract\", \"number\", typeOf(numberToSubtract));\n }\n return await this.set(key, targetNumber - numberToSubtract as any) as Promise<number>;\n }\n /**\n * Thêm một hoặc nhiều phần tử vào cuối array tại key-path.\n *\n * Method này sẽ:\n * - kiểm tra target có phải array không\n * - chỉ thêm các giá trị **chưa tồn tại** trong array\n *\n * ⚠️ Nếu key không tồn tại hoặc target không phải array\n * thì sẽ ném lỗi.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn tới array cần thêm phần tử.\n * @param values Một hoặc nhiều giá trị cần thêm.\n *\n * @returns Array sau khi thêm phần tử.\n *\n * @example\n * ```ts\n * await db.push(\"users.123.roles\", \"admin\");\n * ```\n *\n * @example\n * ```ts\n * await db.push(\"queue.songs\", song1, song2);\n * ```\n */\n public async push<P extends ObjectPath<V>>(key: AutocompletableString<P>, ...values: RestOrArray<ExtractFromArray<ObjectValue<V, P>>>): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n if (!values.length) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"values\");\n }\n const root = await this.all();\n const pathParts = key.split(\".\");\n let target = root;\n for (let i = 0; i < pathParts.length; i++) {\n const part = pathParts[i];\n if (!(part in target)) {\n throw new BlackCatError(\"INVALID_KEY\", key);\n }\n if (i === pathParts.length - 1) {\n if (!Array.isArray(target[part])) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(target[part]));\n }\n const uniqueValues = (values as any[]).filter(v => !target[part].includes(v));\n target[part].push(...uniqueValues);\n } else {\n target = target[part];\n }\n };\n const topKey = pathParts[0];\n await this.set(topKey, root[topKey]);\n return target[pathParts[pathParts.length - 1]];\n }\n /**\n * Thay thế phần tử trong array theo index.\n *\n * @typeParam P - Path trỏ đến array.\n *\n * @param key - Đường dẫn array.\n * @param targetArrayElementIndex - Index cần thay.\n * @param value - Giá trị mới.\n *\n * @returns Array sau khi thay thế.\n *\n * @throws BlackCatError\n * - INVALID_TYPE nếu index không phải number\n * - REQUIRED_PARAMETER_MISSING nếu thiếu value\n * - INVALID_KEY nếu path không tồn tại\n * - INVALID_TARGET nếu target không phải array\n *\n * @example\n * await db.pull(\"users\", 0, { id: 2 });\n */\n public async pull<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, targetArrayElementIndex: number, value: ExtractFromArray<ObjectValue<V, P>>,): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n if (!isNumber(targetArrayElementIndex)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"targetArrayElementIndex\", \"number\", typeOf(targetArrayElementIndex));\n };\n if (value === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"value\");\n };\n const root = await this.all();\n const pathParts = key.split(\".\");\n let target: any = root;\n for (let i = 0; i < pathParts.length; i++) {\n const part = pathParts[i];\n if (!(part in target)) {\n throw new BlackCatError(\"INVALID_KEY\", `Path \"${key}\" does not exist`);\n }\n if (i === pathParts.length - 1) {\n if (!Array.isArray(target[part])) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(target[part]));\n };\n const arr = target[part];\n const index = targetArrayElementIndex >= 0 ? targetArrayElementIndex : arr.length + targetArrayElementIndex;\n if (index < 0 || index >= arr.length) {\n console.error(`Index ${targetArrayElementIndex} is out of bounds`);\n };\n arr[index] = value;\n } else {\n target = target[part];\n };\n };\n await this.set(pathParts[0], root[pathParts[0]]);\n return target[pathParts[pathParts.length - 1]];\n }\n /**\n * Xóa phần tử khỏi array theo index.\n *\n * Có thể truyền nhiều index hoặc một array index.\n *\n * @typeParam P - Path trỏ đến array.\n *\n * @param key - Đường dẫn array.\n * @param targetArrayElementIndexes - Các index cần xóa.\n *\n * @returns Danh sách phần tử đã bị xóa.\n *\n * @throws BlackCatError\n * - INVALID_TARGET nếu target không phải array\n * - REQUIRED_PARAMETER_MISSING nếu thiếu index\n * - ONE_OR_MORE_ARRAY_TYPES_INVALID nếu index không phải number\n *\n * @example\n * await db.pop(\"users\", 0);\n * await db.pop(\"numbers\", [1, 2, 3]);\n */\n public async pop<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, ...targetArrayElementIndexes: RestOrArray<ExtractFromArray<number>>): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n const targetArray = await this.get(key) ?? [];\n\n if (!Array.isArray(targetArray)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(targetArray));\n };\n\n if (!targetArrayElementIndexes.length) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"targetArrayElementIndex\");\n };\n const indexes = Array.isArray(targetArrayElementIndexes[0]) ? (targetArrayElementIndexes[0] as number[]) : (targetArrayElementIndexes as number[]);\n if (indexes.some(index => !isNumber(index))) {\n throw new BlackCatError(\"ONE_OR_MORE_ARRAY_TYPES_INVALID\", \"targetArrayElementIndexes\", \"number\", createTypesArray(indexes));\n };\n\n const sortedIndexes = [...indexes].sort((a, b) => b - a);\n const removedElements: any[] = [];\n\n for (const index of sortedIndexes) {\n const removed = targetArray.splice(index, 1);\n removedElements.push(...removed);\n };\n\n const parentPath = key.split(\".\").slice(0, -1).join(\".\") as AutocompletableString<any>;\n const fieldName = key.split(\".\").slice(-1)[0];\n\n if (parentPath) {\n const parentObject = await this.get(parentPath) as Record<string, any> ?? {};\n parentObject[fieldName] = targetArray;\n await this.set(parentPath, parentObject as NonNullable<Exclude<ObjectValue<V, P>, undefined>>);\n } else {\n await this.set(key, targetArray as NonNullable<Exclude<ObjectValue<V, P>, undefined>>);\n };\n return removedElements;\n }\n /**\n * Kiểm tra xem giá trị tại key có phải là Array hay không.\n *\n * @typeParam P - Path của object trong database.\n * @param key - Đường dẫn key cần kiểm tra.\n *\n * @returns `true` nếu giá trị là Array, ngược lại `false`.\n *\n * @example\n * const result = await db.isTargetArray(\"users\");\n * console.log(result);\n */\n public async isTargetArray<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const target = await this.get(key);\n return Array.isArray(target);\n }\n /**\n * Kiểm tra xem giá trị tại key có phải là Number hay không.\n *\n * @typeParam P - Path của object trong database.\n *\n * @param key - Đường dẫn key cần kiểm tra.\n *\n * @returns `true` nếu giá trị là Number, ngược lại `false`.\n *\n * @example\n * const result = await db.isTargetNumber(\"stats.score\");\n * console.log(result);\n */\n public async isTargetNumber<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const target = await this.get(key);\n return isNumber(target);\n }\n /**\n * Lấy danh sách các key của object trong database.\n *\n * Nếu không truyền `key` → trả về các key cấp cao nhất của database.\n *\n * @typeParam P - Path của object.\n *\n * @param key - Path của object cần lấy danh sách key.\n *\n * @returns Mảng các key tồn tại (không bao gồm `null` hoặc `undefined`).\n *\n * @example\n * const rootKeys = await db.keys();\n * const userKeys = await db.keys(\"user\");\n */\n public async keys<P extends AutocompletableString<ObjectPath<V>>>(key?: P): Promise<ObjectPath<P>[]> {\n if (!key) return TypedObject.keys(await this.all()) as ObjectPath<P>[];\n const data = await this.get(key) as Record<string, any>;\n return TypedObject.keys(data).filter((key) => data[key] !== undefined && data[key] !== null) as any\n }\n /**\n * Lấy số lượng key cấp cao nhất trong database.\n *\n * @returns Tổng số key ở root level.\n *\n * @example\n * const count = await db.size();\n */\n public async size(): Promise<number> {\n const keys = await this.keys();\n return keys.length;\n }\n /**\n * Lấy danh sách các giá trị từ database.\n *\n * Nếu không truyền `key` → trả về toàn bộ values ở root level.\n * Nếu truyền `key` → trả về values của object tại path đó.\n *\n * @typeParam P - Path của object trong database.\n *\n * @param key - Đường dẫn object cần lấy values.\n *\n * @returns Mảng các giá trị.\n *\n * @example\n * const allValues = await db.values();\n *\n * const userValues = await db.values(\"users\");\n */\n public async values<P extends AutocompletableString<ObjectPath<V>>>(key?: P): Promise<ObjectValue<V, P>[]> {\n if (!key) return TypedObject.values(await this.all());\n const data = await this.get(key) as Record<string, any>;\n return TypedObject.values(data) as ObjectValue<V, P>[];\n }\n /**\n * Lấy ngẫu nhiên một phần tử từ array tại path được chỉ định.\n *\n * @typeParam P - Path trỏ đến array trong database.\n *\n * @param key - Đường dẫn đến array.\n *\n * @returns Một phần tử ngẫu nhiên trong array hoặc `null` nếu array rỗng.\n *\n * @throws BlackCatError\n * - INVALID_TARGET nếu giá trị tại key không phải array\n *\n * @example\n * const randomUser = await db.random(\"users\");\n */\n public async random<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<Maybe<ObjectValue<V, P>>> {\n const array = await this.get(key);\n if (!Array.isArray(array)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(array));\n }\n return array[Math.floor(Math.random() * array.length)] ?? null;\n }\n /**\n * Tìm phần tử đầu tiên thỏa điều kiện.\n *\n * Hoạt động tương tự `Array.prototype.find`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Phần tử đầu tiên thỏa điều kiện hoặc `null` nếu không tìm thấy.\n *\n * @example\n * const user = await db.find(u => u.id === 1);\n */\n public async find(queryFunction: QueryFunction<V>): Promise<Maybe<V>> {\n const values = await this.values();\n return values.find(queryFunction as QueryFunction<ObjectValue<V, any>>) as Promise<Maybe<V>> ?? null;\n }\n /**\n * Biến đổi tất cả giá trị trong database thành một mảng mới.\n *\n * Hoạt động giống `Array.prototype.map`.\n *\n * @typeParam TReturnType - Kiểu dữ liệu của phần tử trả về.\n *\n * @param queryFunction - Hàm transform từng phần tử.\n *\n * @returns Mảng kết quả sau khi transform.\n *\n * @example\n * const names = await db.map(user => user.name);\n */\n public async map<TReturnType>(queryFunction: QueryFunction<V, TReturnType>): Promise<TReturnType[]> {\n const values = await this.values();\n return values.map(queryFunction as QueryFunction<ObjectValue<V, any>, TReturnType>);\n }\n /**\n * Tìm index của phần tử đầu tiên thỏa điều kiện.\n *\n * Hoạt động giống `Array.prototype.findIndex`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Index của phần tử hoặc `-1` nếu không tìm thấy.\n *\n * @example\n * const index = await db.findIndex(user => user.id === 1);\n */\n public async findIndex(queryFunction: QueryFunction<V>): Promise<number> {\n const values = await this.values();\n return values.findIndex(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n /**\n * Lọc các phần tử thỏa điều kiện.\n *\n * Hoạt động giống `Array.prototype.filter`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Mảng các phần tử thỏa điều kiện.\n *\n * @example\n * const admins = await db.filter(user => user.role === \"admin\");\n */\n public async filter(queryFunction: QueryFunction<V>): Promise<V[]> {\n const values = await this.values();\n return values.filter(queryFunction as QueryFunction<ObjectValue<V, any>>) as any;\n }\n /**\n * Kiểm tra có ít nhất một phần tử thỏa điều kiện hay không.\n *\n * Hoạt động giống `Array.prototype.some`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns `true` nếu tồn tại phần tử thỏa điều kiện.\n *\n * @example\n * const hasAdmin = await db.some(user => user.role === \"admin\");\n */\n public async some(queryFunction: QueryFunction<V>): Promise<boolean> {\n const values = await this.values();\n return values.some(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n /**\n * Kiểm tra tất cả phần tử có thỏa điều kiện hay không.\n *\n * Hoạt động giống `Array.prototype.every`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns `true` nếu tất cả phần tử đều thỏa điều kiện.\n *\n * @example\n * const allActive = await db.every(user => user.active === true);\n */\n public async every(queryFunction: QueryFunction<V>): Promise<boolean> {\n const values = await this.values();\n return values.every(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n}","import { promises as fs } from \"fs\";\nimport { DatabaseDriver } from \"../types\";\n\n/**\n * Cấu hình khởi tạo cho {@link JSONDriver}.\n */\ninterface JSONDriverOptions {\n /**\n * Đường dẫn tới file JSON dùng làm database.\n *\n * Ví dụ:\n * ```ts\n * \"./database.json\"\n * \"./data/users.json\"\n * ```\n */\n filePath: string;\n /**\n * Nếu bật, nội dung JSON sẽ được **minify**\n * (không format khoảng trắng) để giảm dung lượng file.\n *\n * Nếu tắt, JSON sẽ được format với indentation để dễ đọc.\n *\n * @default false\n */\n minifyJSON?: boolean;\n}\n\n/**\n * Driver lưu trữ dữ liệu dạng JSON.\n *\n * ⚠️ Đây **không phải database hoàn chỉnh**.\n * Class này chỉ đóng vai trò **driver lưu trữ (storage layer)**\n * cho class chính `Database`.\n *\n * Toàn bộ logic xử lý key path (`a.b.c`), validate dữ liệu,\n * và các thao tác database sẽ được thực hiện trong class `Database`.\n *\n * `JSONDriver` chỉ chịu trách nhiệm:\n *\n * - Đọc dữ liệu từ file JSON\n * - Ghi dữ liệu xuống file JSON\n * \n * @example \n * ```ts\n * const database = new Database({\n * driber: new JSONDriver({\\\n * filePath: \"./database.json\",\n * minifyJSON: false\n * })\n * });\n * ```\n */\nexport class JSONDriver implements DatabaseDriver {\n /**\n * Đường dẫn tới file database JSON.\n */\n private filePath: string;\n /**\n * Cho biết có minify JSON khi ghi file hay không.\n */\n public minifyJSON: boolean;\n /**\n * Khởi tạo một instance mới của {@link JSONDriver}.\n *\n * @param options - Cấu hình driver\n *\n * @param options.filePath\n * Đường dẫn tới file JSON dùng làm database.\n *\n * @param options.minifyJSON\n * Nếu `true`, nội dung JSON sẽ được minify khi ghi ra file để giảm dung lượng.\n *\n * @example\n * ```ts\n * const database = new Database({\n * driver: db = new JSONDriver({\n * filePath: \"./database.json\"\n * })\n * });\n * ```\n */\n constructor(options: JSONDriverOptions) {\n this.filePath = options.filePath || \"database.json\";\n this.minifyJSON = options.minifyJSON || false;\n\n }\n /**\n * Đảm bảo file database tồn tại.\n * Nếu file chưa tồn tại sẽ tự động tạo file `{}`.\n */\n private async ensureFile(): Promise<void> {\n try {\n await fs.access(this.filePath);\n } catch {\n await fs.writeFile(this.filePath, \"{}\");\n }\n }\n /**\n * Đọc toàn bộ dữ liệu từ file database JSON.\n *\n * Nếu file không tồn tại hoặc lỗi parse,\n * method sẽ trả về object rỗng.\n *\n * @template V Kiểu dữ liệu database.\n * @returns Promise chứa toàn bộ dữ liệu database.\n */\n public async all<V>(): Promise<V> {\n await this.ensureFile();\n return fs.readFile(this.filePath, \"utf-8\").then((content) => JSON.parse(content) as V).catch((error) => {\n console.error(`Không thể đọc file database: ${this.filePath}`, error);\n return {} as V;\n });\n }\n /**\n * Ghi toàn bộ dữ liệu database xuống file JSON.\n *\n * Method này **không xử lý key path**.\n * Logic cập nhật dữ liệu sẽ được xử lý ở class `Database`\n * trước khi truyền object hoàn chỉnh vào đây.\n *\n * @param data Toàn bộ dữ liệu database sau khi đã được cập nhật.\n *\n * @template R Kiểu dữ liệu database.\n * @returns Promise chứa dữ liệu đã ghi.\n */\n public async set<R = any>(data: R): Promise<R> {\n await this.ensureFile();\n await fs.writeFile(this.filePath, JSON.stringify(data, null, this.minifyJSON ? undefined : \"\\t\"));\n return data;\n }\n /**\n * Xóa toàn bộ database.\n *\n * Method này chỉ reset file JSON về `{}`.\n *\n * @returns `true` nếu reset thành công.\n */\n public async delete(): Promise<boolean> {\n await this.ensureFile();\n await fs.writeFile(this.filePath, \"{}\");\n return true;\n }\n}","import { DatabaseDriver } from \"../types\";\n\n/**\n * Driver lưu trữ dữ liệu trong RAM.\n *\n * ⚠️ Đây **không phải database chính**.\n * Class này chỉ là **storage driver phụ trợ** cho class `Database`.\n *\n * Toàn bộ logic xử lý:\n * - key path (`a.b.c`)\n * - validation\n * - update dữ liệu\n *\n * đều được thực hiện trong class `Database`.\n *\n * `MemoryDriver` chỉ chịu trách nhiệm:\n * - lưu trữ object database trong RAM\n * - trả về toàn bộ dữ liệu\n *\n * Dữ liệu sẽ **mất khi ứng dụng restart**.\n *\n * Phù hợp cho:\n * - testing\n * - cache runtime\n * - development\n * \n * @example\n * ```ts\n * const database = new Database({\n * driver: new MemoryDriver({\n * users: {},\n * guilds: {},\n * settings: {\n * prefix: \"!\"\n * }\n * })\n * });\n * ```\n * \n * hoặc \n * \n * ```ts\n * const database = new Database({\n * driver: new MemoryDriver()\n * });\n * ```\n */\nexport class MemoryDriver implements DatabaseDriver {\n /**\n * Object chứa toàn bộ dữ liệu database trong RAM.\n */\n private store: Record<string, any>;\n /**\n * Khởi tạo MemoryDriver.\n *\n * @param initialData Dữ liệu khởi tạo ban đầu.\n * * @example\n * ```ts\n * const database = new Database({\n * driver: new MemoryDriver({\n * users: {},\n * guilds: {},\n * settings: {\n * prefix: \"!\"\n * }\n * })\n * });\n * ```\n * \n * hoặc \n * \n * ```ts\n * const database = new Database({\n * driver: new MemoryDriver()\n * });\n * ```\n */\n constructor(initialData: Record<string, any> = {}) {\n this.store = initialData;\n }\n /**\n * Trả về toàn bộ dữ liệu database.\n *\n * @template T Kiểu dữ liệu database.\n */\n public async all<T = any>(): Promise<T> {\n return this.store as T;\n }\n /**\n * Ghi toàn bộ database vào memory.\n *\n * ⚠️ Method này **không xử lý key-path**.\n * Dữ liệu đã được xử lý trước bởi `Database`.\n *\n * @param data Toàn bộ database object\n */\n public async set<T = any>(data: T): Promise<T> {\n this.store = data as any;\n return data;\n }\n /**\n * Xóa toàn bộ dữ liệu database trong memory.\n */\n public async delete(): Promise<boolean> {\n this.store = {};\n return true;\n }\n}","import SQLite from \"better-sqlite3\";\nimport { DatabaseDriver } from \"../types\";\n\n/**\n * Các tùy chọn cấu hình cho SQLiteDriver.\n * @hidden\n *\n * Interface này định nghĩa các thiết lập được sử dụng khi\n * khởi tạo driver SQLite cho hệ thống database.\n */\ninterface SQLiteDriverOptions {\n /**\n * Đường dẫn đến file cơ sở dữ liệu SQLite.\n *\n * Nếu không được cung cấp, driver có thể tạo\n * một file database mặc định tùy theo cách triển khai.\n *\n * Ví dụ:\n * `\"./database.sqlite\"`\n */\n filePath?: string;\n /**\n * Tên bảng được sử dụng để lưu trữ dữ liệu key-value.\n *\n * Nếu không được chỉ định, driver có thể sử dụng\n * một tên bảng mặc định (ví dụ: `\"data\"`).\n *\n * Ví dụ:\n * `\"storage\"`\n */\n table?: string;\n}\n/**\n * Driver lưu trữ dữ liệu bằng SQLite.\n *\n * ⚠️ Đây **không phải database chính**.\n * Class này chỉ là **driver lưu trữ phụ trợ** cho `Database`.\n *\n * Logic xử lý dữ liệu như:\n * - parse key path\n * - update object\n * - validation\n *\n * sẽ được thực hiện bởi class `Database`.\n *\n * Driver này chỉ:\n * - serialize database thành JSON\n * - lưu JSON vào SQLite\n * - trả về JSON khi đọc\n *\n * Toàn bộ database được lưu trong **một row duy nhất**.\n * \n * @example\n * ```ts\n * const database = new Database({\n * driver: new SQLiteDriver({\n * filePath: \"database.sqlite\",\n * table: \"json_store\"\n * })\n * })\n * ```\n */\nexport class SQLiteDriver implements DatabaseDriver {\n /**\n * SQLite database instance.\n */\n private db: SQLite.Database;\n /**\n * Tên table lưu trữ dữ liệu JSON.\n */\n private table: string;\n /**\n * Khởi tạo SQLiteDriver.\n *\n * @param filePath Đường dẫn file SQLite\n * @param table Tên table lưu JSON database\n * @example\n * ```ts\n * const database = new Database({\n * driver: new SQLiteDriver({\n * filePath: \"database.sqlite\",\n * table: \"json_store\"\n * })\n * })\n * ```\n */\n constructor(options: SQLiteDriverOptions = {}) {\n this.db = new SQLite(options.filePath ?? \"database.sqlite\");\n this.table = options.table ?? \"json_store\";\n this.db.prepare(`CREATE TABLE IF NOT EXISTS ${this.table} (id INTEGER PRIMARY KEY, data TEXT)`).run();\n const row = this.db.prepare(`SELECT * FROM ${this.table} WHERE id = 1`).get();\n if (!row) {\n this.db.prepare(`INSERT INTO ${this.table} (id, data) VALUES (1, '{}')`).run();\n }\n }\n /**\n * Lấy toàn bộ dữ liệu database từ SQLite.\n *\n * @template T Kiểu dữ liệu database.\n */\n public async all<T = any>(): Promise<T> {\n const row = this.db.prepare(`SELECT data FROM ${this.table} WHERE id = 1`).get() as { data: string };\n return JSON.parse(row.data) as T;\n }\n /**\n * Ghi toàn bộ database vào SQLite.\n *\n * ⚠️ Method này **không xử lý key-path**.\n * `Database` đã cập nhật object trước khi truyền vào đây.\n *\n * @param data Toàn bộ database object\n */\n public async set<T = any>(data: T): Promise<T> {\n this.db.prepare(`UPDATE ${this.table} SET data = ? WHERE id = 1`).run(JSON.stringify(data));\n return data;\n }\n /**\n * Reset toàn bộ database.\n */\n public async delete(): Promise<boolean> {\n this.db.prepare(`UPDATE ${this.table} SET data = '{}' WHERE id = 1`).run();\n return true;\n }\n}","import { MongoClient, Db, Collection } from \"mongodb\";\nimport type { DatabaseDriver } from \"../types\";\n\n/**\n * Cấu hình cho MongoDriver.\n */\ninterface MongoDriverOptions {\n /**\n * Chuỗi kết nối MongoDB.\n *\n * @default \"mongodb://localhost:27017\"\n */\n mongourl?: string;\n /**\n * Tên database MongoDB.\n *\n * @default \"database\"\n */\n databaseName?: string;\n /**\n * Tên collection lưu dữ liệu JSON.\n *\n * @default \"json_store\"\n */\n collectionName?: string;\n}\n/**\n * Schema document dùng để lưu trữ database trong MongoDB.\n */\ninterface DatabaseDocument<V = any> {\n _id: string;\n data: V;\n}\n/**\n * Driver lưu trữ dữ liệu bằng MongoDB.\n *\n * ⚠️ Đây **không phải database chính**.\n * Class này chỉ là **driver lưu trữ phụ trợ** cho class `Database`.\n *\n * Logic xử lý:\n * - parse key path\n * - validate dữ liệu\n * - cập nhật object\n *\n * sẽ được xử lý bởi class `Database`.\n *\n * `MongoDriver` chỉ chịu trách nhiệm:\n * - lưu toàn bộ database object\n * - trả về database object\n *\n * Toàn bộ database được lưu trong **một document duy nhất**.\n * \n * @example \n * ```ts\n * const database = new Database({ \n * driver: new MongoDriver({\n * mongourl: \"mongodb://localhost:27017\", \n * databaseName: \"mydb\", \n * collectionName: \"store\" \n * })\n * });\n * ```\n */\nexport class MongoDriver implements DatabaseDriver {\n /**\n * MongoDB client instance.\n */\n private client: MongoClient;\n /**\n * MongoDB database instance.\n */\n private db!: Db;\n /**\n * Collection lưu dữ liệu JSON.\n */\n private collection!: Collection<DatabaseDocument>;\n /**\n * Tên database MongoDB.\n */\n private databaseName: string;\n /**\n * Tên collection MongoDB.\n */\n private collectionName: string;\n /**\n * Khởi tạo MongoDriver.\n *\n * @param options Cấu hình MongoDB driver.\n * \n * @example \n * ```ts\n * const database = new Database({ \n * driver: new MongoDriver({\n * mongourl: \"mongodb://localhost:27017\", \n * databaseName: \"mydb\", \n * collectionName: \"store\" \n * })\n * });\n */\n constructor(options: MongoDriverOptions = {}) {\n const {\n mongourl = \"mongodb://localhost:27017\",\n databaseName = \"database\",\n collectionName = \"json_store\"\n } = options;\n this.client = new MongoClient(mongourl);\n this.databaseName = databaseName;\n this.collectionName = collectionName;\n }\n /**\n * Thiết lập kết nối MongoDB nếu chưa kết nối.\n */\n private async connect(): Promise<void> {\n if (!this.db) {\n await this.client.connect();\n this.db = this.client.db(this.databaseName);\n this.collection = this.db.collection(this.collectionName);\n const doc = await this.collection.findOne({ _id: \"database\" });\n if (!doc) {\n await this.collection.insertOne({\n _id: \"database\",\n data: {}\n });\n }\n }\n }\n /**\n * Lấy toàn bộ dữ liệu database từ MongoDB.\n */\n public async all<T = any>(): Promise<T> {\n await this.connect();\n const doc = await this.collection.findOne({ _id: \"database\" });\n return (doc?.data ?? {}) as T;\n }\n /**\n * Ghi toàn bộ database vào MongoDB.\n *\n * ⚠️ Method này **không xử lý key-path**.\n * Object database đã được xử lý bởi class `Database`.\n * \n * @param data Toàn bộ object database\n */\n public async set<T = any>(data: T): Promise<T> {\n await this.connect();\n await this.collection.updateOne(\n { _id: \"database\" },\n { $set: { data } }\n );\n return data;\n }\n /**\n * Reset toàn bộ database về object rỗng.\n */\n public async delete(): Promise<boolean> {\n await this.connect();\n await this.collection.updateOne(\n { _id: \"database\" },\n { $set: { data: {} } }\n );\n return true;\n }\n}"],"mappings":"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","names":["key","fs","SQLite"]}
|
package/dist/index.mjs
CHANGED
|
@@ -428,41 +428,86 @@ var _Database = class _Database {
|
|
|
428
428
|
return originalLength - filtered.length;
|
|
429
429
|
}
|
|
430
430
|
/**
|
|
431
|
-
* Cập nhật
|
|
431
|
+
* Cập nhật dữ liệu trong database theo đường dẫn key.
|
|
432
432
|
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
433
|
+
* Hàm này sẽ tìm đến vị trí của `key` trong database và gán `value` vào đó.
|
|
434
|
+
* Nếu `value` và giá trị hiện tại tại key đều là object thì sẽ thực hiện
|
|
435
|
+
* **shallow merge** thay vì ghi đè toàn bộ object.
|
|
435
436
|
*
|
|
436
|
-
*
|
|
437
|
-
* thì chúng sẽ được tự động tạo.
|
|
437
|
+
* Điều này giúp tránh việc làm mất các thuộc tính đã tồn tại.
|
|
438
438
|
*
|
|
439
|
-
* @template P
|
|
439
|
+
* @template P - Đường dẫn key hợp lệ trong object database.
|
|
440
|
+
*
|
|
441
|
+
* @param key - Đường dẫn tới giá trị cần cập nhật.
|
|
442
|
+
* Hỗ trợ nested path dạng `"a.b.c"`.
|
|
440
443
|
*
|
|
441
|
-
* @param
|
|
442
|
-
* @param value Giá trị mới.
|
|
444
|
+
* @param value - Giá trị mới sẽ được cập nhật tại key.
|
|
443
445
|
*
|
|
444
|
-
* @returns
|
|
446
|
+
* @returns
|
|
447
|
+
* Trả về giá trị cuối cùng sau khi cập nhật.
|
|
445
448
|
*
|
|
446
449
|
* @example
|
|
450
|
+
* Database ban đầu:
|
|
451
|
+
* ```json
|
|
452
|
+
* {
|
|
453
|
+
* "123": {
|
|
454
|
+
* "guildID": "123",
|
|
455
|
+
* "guildName": "BlackCat",
|
|
456
|
+
* "history": []
|
|
457
|
+
* }
|
|
458
|
+
* }
|
|
459
|
+
* ```
|
|
460
|
+
*
|
|
461
|
+
* Cập nhật:
|
|
447
462
|
* ```ts
|
|
448
|
-
* await db.update("
|
|
463
|
+
* await db.update("123", {
|
|
464
|
+
* history: [1,2,3]
|
|
465
|
+
* });
|
|
449
466
|
* ```
|
|
467
|
+
*
|
|
468
|
+
* Kết quả:
|
|
469
|
+
* ```json
|
|
470
|
+
* {
|
|
471
|
+
* "123": {
|
|
472
|
+
* "guildID": "123",
|
|
473
|
+
* "guildName": "BlackCat",
|
|
474
|
+
* "history": [1,2,3]
|
|
475
|
+
* }
|
|
476
|
+
* }
|
|
477
|
+
* ```
|
|
478
|
+
*
|
|
479
|
+
* @throws {BlackCatError}
|
|
480
|
+
* - `REQUIRED_PARAMETER_MISSING` nếu key không được cung cấp
|
|
481
|
+
* - `INVALID_TYPE` nếu key không phải string
|
|
450
482
|
*/
|
|
451
483
|
async update(key, value) {
|
|
484
|
+
if (!key) {
|
|
485
|
+
throw new BlackCatError("REQUIRED_PARAMETER_MISSING", "key");
|
|
486
|
+
}
|
|
487
|
+
if (typeof key !== "string") {
|
|
488
|
+
throw new BlackCatError("INVALID_TYPE", "key", "string", typeOf(key));
|
|
489
|
+
}
|
|
452
490
|
const allDatabase = await this.all();
|
|
453
491
|
const keys = key.split(".");
|
|
454
492
|
let current = allDatabase;
|
|
455
493
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
456
494
|
const part = keys[i];
|
|
457
|
-
if (!(part
|
|
495
|
+
if (!isObject(current[part])) {
|
|
458
496
|
current[part] = {};
|
|
459
497
|
}
|
|
460
498
|
current = current[part];
|
|
461
499
|
}
|
|
462
500
|
const lastKey = keys[keys.length - 1];
|
|
463
|
-
current[lastKey]
|
|
501
|
+
if (isObject(value) && isObject(current[lastKey])) {
|
|
502
|
+
current[lastKey] = {
|
|
503
|
+
...current[lastKey],
|
|
504
|
+
...value
|
|
505
|
+
};
|
|
506
|
+
} else {
|
|
507
|
+
current[lastKey] = value;
|
|
508
|
+
}
|
|
464
509
|
await this.driver.set(allDatabase);
|
|
465
|
-
return current;
|
|
510
|
+
return current[lastKey];
|
|
466
511
|
}
|
|
467
512
|
/**
|
|
468
513
|
* Cộng thêm giá trị vào một key dạng number.
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/isObject.function.ts","../src/utils/typeOf.function.ts","../src/utils/isNumber.function.ts","../src/utils/BlackCatError.ts","../src/utils/TypedObject.ts","../src/utils/Emitter.ts","../src/Database.ts","../src/drivers/JSONDriver.ts","../src/drivers/MemoryDriver.ts","../src/drivers/SQLiteDriver.ts","../src/drivers/MongoDriver.ts"],"sourcesContent":["/**\n * Checks for is the item object and returns it.\n * @param {any} item The item to check.\n * @returns {boolean} Is the item object or not.\n */\nexport const isObject = (item: any): boolean => !Array.isArray(item) && item !== null && typeof item == \"object\";","/**\n * Returns the exact type of a given input.\n * @param input - The value to check.\n * @returns A string representing the exact type of the input.\n */\nexport const typeOf = (input: any): string => {\n // ✅ Handle special cases: null, undefined, and NaN\n if (input == null || (typeof input === \"number\" && Number.isNaN(input))) return String(input);\n // ✅ If it's a class constructor (has a prototype)\n if (typeof input === \"function\" && input.prototype) return `${input.name} class instance`;\n // ✅ If it's an object or function, return the constructor name if available\n return input?.constructor?.name ?? typeof input;\n};","import { typeOf } from \"./typeOf.function\";\n\n/**\n * Determines if the specified value is a number.\n *\n * A small hack to actually determine if the input is a number since\n * empty strings and arrays are considered as numbers too.\n * @param {any} input The input to check.\n * @returns {boolean} Whether the specified input is a number.\n */\nexport const isNumber = (input: any): boolean => !isNaN(input as number) && input !== \"\" && input !== null && typeOf(input) !== \"Array\";","import { typeOf } from \"./typeOf.function\";\n\nexport type TargetParamType = \"string\" | \"number\" | \"object\" | \"array\" | `${string} class instance`;\n\nexport const errors = {\n DEVICE_IS_OFFLINE: 'Your device appears to be offline so it\\'s impossible to proceed with ' + 'connection to your online MongoDB cluster. Please connect your device to the internet or switch to the ' + 'local MongoDB database and try again.',\n CONNECTION_NOT_ESTABLISHED: 'Failed to connect to MongoDB. Please double-check the specified ' + 'connection URI and make sure that you\\'re performing the ' + 'database connection using the `QuickMongoClient.connect()` method.',\n CONNECTION_URI_NOT_SPECIFIED: 'The MongoDB connection URI must be specified.',\n INVALID_CONNECTION_URI: 'The specified MongoDB connection URI is invalid.',\n UNKNOWN_ERROR: 'Unknown error.',\n REQUIRED_PARAMETER_MISSING: '\\'{1}\\' parameter is required but is missing.',\n REQUIRED_CONSTRUCTOR_PARAMETER_MISSING: '\\'{1}\\' parameter in constructor \\'{2}\\' is required but is missing.',\n INVALID_CONSTRUCTOR_PARAMETER_TYPE: '\\'{1}\\' parameter in constructor \\'{2}\\' must be ' + 'a type of {3}. Received type: {4}.',\n INVALID_TYPE: '\\'{1}\\' must be a type of {2}. Received type: {3}.',\n ONE_OR_MORE_ARRAY_TYPES_INVALID: 'All specified elements from array in \\'{1}\\' parameter ' + 'must be a type of {2}. Received array of types: {3}.',\n INVALID_TARGET: 'The target in database must be a type of {1}. Received target type: {2}.',\n INVALID_KEY: \"{1}\",\n INVALID_PARAMETER: \"{1} {2}\",\n DATABASE_CONNECTION_FAILED: \"{1}\"\n}\n\nexport interface ErrorParams extends Record<keyof typeof errors, string[]> {\n CONNECTION_NOT_ESTABLISHED: [];\n UNKNOWN_ERROR: [];\n CONNECTION_URI_NOT_SPECIFIED: [];\n INVALID_CONNECTION_URI: [];\n REQUIRED_PARAMETER_MISSING: [missingParam: string];\n REQUIRED_CONSTRUCTOR_PARAMETER_MISSING: [missingParam: string, className: string];\n INVALID_TYPE: [paramName: string, targetType: TargetParamType, receivedType: string];\n INVALID_CONSTRUCTOR_PARAMETER_TYPE: [paramName: string, className: string, targetType: TargetParamType, receivedType: string];\n ONE_OR_MORE_ARRAY_TYPES_INVALID: [paramName: string, targetType: TargetParamType, receivedTypesArray: string];\n INVALID_TARGET: [targetType: TargetParamType, receivedType: string];\n INVALID_KEY: [paramName: string];\n INVALID_PARAMETER: [paramName: string, receivedType: string];\n DATABASE_CONNECTION_FAILED: [paramName: string]\n}\nexport const createTypesArray = <T>(...elements: any): string => `[${elements.map((element: any) => typeOf(element))}]`;\n/**\n * BlackCatError class.\n */\nexport class BlackCatError<TErrorCode extends keyof typeof errors> extends Error {\n /** \n * Creates a BlackCatError instance.\n * @param {string} errorCode Quick Mongo error code.\n * @param {any[]} params Additional parameters to replace the placeholders in the error message.\n */\n public constructor(errorCode: TErrorCode, ...params: ErrorParams[TErrorCode]) {\n const code = errors[errorCode] ? errorCode : \"UNKNOWN_ERROR\" as TErrorCode;\n let message = errors[code];\n for (let i = 0; i < params.length; i++) {\n message = message.replaceAll(`{${i + 1}}`, params[i]);\n };\n super(message);\n /**\n * The name of the error.\n */\n this.name = `BlackCatError [${code}]`;\n }\n}","import { ExtractObjectKeys, ExtractObjectValues, ExtractObjectEntries } from \"../types\";\n\n/**\n * Utility class for working with objects.\n *\n * Provides **static** methods for retrieving keys and values of an object with addition of types.\n *\n * This class enhances type safety by providing better typings for object keys and values.\n */\nexport class TypedObject {\n /**\n * Returns the names of the enumerable string properties and methods of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object keys types from.\n *\n * @param {TObject} obj Object to get the keys from.\n *\n * @returns {Array<ExtractObjectKeys<TObject>>}\n * Array of names of the enumerable string properties and methods of the specified object.\n */\n public static keys<TObject extends Record<string, any>>(obj: TObject): ExtractObjectKeys<TObject>[] {\n return Object.keys(obj || {});\n }\n /**\n * Returns an array of values of the enumerable properties of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object values types from.\n *\n * @param {TObject} obj Object to get the values from.\n *\n * @returns {Array<ExtractObjectValues<TObject>>}\n * Array of values of the enumerable properties of the specified object.\n */\n public static values<TObject extends Record<string, any>>(obj: TObject): ExtractObjectValues<TObject>[] {\n return Object.values(obj || {});\n }\n /**\n * Returns an array of entries (key-value pairs) of the enumerable properties of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object entries types (key-value pairs types) from.\n *\n * @param {TObject} obj Object to get the entries from.\n *\n * @returns {ExtractObjectEntries<TObject>[]}\n * Array of entries (key-value pairs) of the enumerable properties of the specified object.\n */\n public static entries<TObject extends Record<string, any>>(obj: TObject): ExtractObjectEntries<TObject>[] {\n return Object.entries(obj || {})\n }\n}","import { EventEmitter } from \"node:events\";\n\nexport class Emitter<E extends Record<string, any>> {\n private _emitter = new EventEmitter();\n /**\n * Listens to the event.\n * @param {string} event Event name.\n * @param {Function} listener Listener function.\n */\n public on<K extends Exclude<keyof E, number>>(event: K, listener: (...args: E[K]) => any): Emitter<E> {\n this._emitter.on(event, listener);\n return this;\n }\n /**\n * Listens to the event only for once.\n * @param {string} event Event name.\n * @param {Function} listener Listener function.\n */\n public once<K extends Exclude<keyof E, number>>(event: K, listener: (...args: E[K]) => any): Emitter<E> {\n this._emitter.once(event, listener);\n return this;\n }\n /**\n * Emits the event.\n * @param {string} event Event name.\n * @param {any[]} args Listener arguments.\n * @returns {boolean} `true` if the event had listeners, `false` otherwise.\n */\n public emit<K extends Exclude<keyof E, number>>(event: K, ...args: E[K]): boolean {\n return this._emitter.emit(event, ...args as any[]);\n }\n}","import { DatabaseConfiguration, AutocompletableString, FirstObjectKey, If, IsObject, ObjectPath, ObjectValue, Maybe, QueryFunction, RestOrArray, ExtractFromArray, DatabaseDriver, ArrayElement } from \"./types\";\nimport { BlackCatError, createTypesArray, isNumber, typeOf, TypedObject, isObject } from \"./utils\";\n\n/**\n * Class Database cung cấp API thao tác dữ liệu dạng key-path\n * trên nhiều loại storage khác nhau thông qua `DatabaseDriver`.\n *\n * Đây là **lớp database chính (logic layer)** của hệ thống.\n *\n * Class này chịu trách nhiệm:\n * - parse key path (`user.profile.name`)\n * - validate dữ liệu\n * - thao tác object\n * - query dữ liệu (find, filter, map...)\n *\n * Việc lưu trữ dữ liệu thực tế sẽ được thực hiện bởi các **driver phụ trợ**\n * như:\n *\n * - `JSONDriver`\n * - `MemoryDriver`\n * - `SQLiteDriver`\n * - `MongoDriver`\n *\n * Các driver này chỉ chịu trách nhiệm:\n * - đọc toàn bộ dữ liệu database\n * - ghi toàn bộ dữ liệu database\n *\n * @template V Kiểu dữ liệu tổng thể của database.\n */\nexport class Database<V = any> {\n /**\n * Storage driver được sử dụng để đọc và ghi dữ liệu database.\n *\n * Driver phải implement interface `DatabaseDriver`.\n *\n * Ví dụ:\n * ```ts\n * const db = new Database({\n * driver: new JSONDriver({ filePath: \"./database.json\" }),\n * })\n * ```\n */\n public driver: DatabaseDriver;\n /**\n * Khởi tạo Database instance.\n *\n * @param options Cấu hình database.\n * @param options.driver Driver lưu trữ dữ liệu.\n *\n * @example\n * ```ts\n * const db = new Database({\n * driver: new JSONDriver({ filePath: \"./database.json\" }),\n * })\n * ```\n *\n * Ví dụ với MongoDB:\n *\n * ```ts\n * const db = new Database({\n * driver: new MongoDriver({\n * uri: \"mongodb://localhost:27017\",\n * databaseName: \"mydb\"\n * })\n * });\n * ```\n */\n constructor(options: DatabaseConfiguration) {\n this.driver = options.driver;\n }\n /**\n * Lấy toàn bộ dữ liệu từ database thông qua driver.\n *\n * @template T Kiểu dữ liệu object database trả về.\n *\n * @returns Promise chứa toàn bộ dữ liệu database.\n *\n * @example\n * ```ts\n * const data = await db.all();\n * console.log(data.users);\n * ```\n */\n public async all<T extends Record<string, any> = Record<string, any>>(): Promise<T> {\n return await this.driver.all<T>();\n }\n /**\n * Lấy giá trị từ database theo key-path.\n *\n * Key có thể là chuỗi dạng path:\n *\n * ```\n * user.profile.name\n * economy.users.123.balance\n * ```\n *\n * Nếu không truyền `key`, method sẽ trả về **toàn bộ database**.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần lấy.\n *\n * @returns Giá trị tại key hoặc `null` nếu không tồn tại.\n *\n * @example\n * ```ts\n * const name = await db.get(\"user.profile.name\");\n * ```\n *\n * @example\n * ```ts\n * const all = await db.get();\n * ```\n */\n public async get<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>): Promise<Maybe<ObjectValue<V, P>> | V> {\n const data = await this.all();\n if (key === undefined) return data as V;\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeOf(key));\n }\n const keys = key.split(\".\");\n let result: any = data;\n for (const k of keys) {\n if (!isObject(result) && !Array.isArray(result)) return null;\n result = result[k];\n if (result === undefined) return null;\n }\n return result;\n }\n /**\n * Tìm và trả về một bản ghi đầu tiên khớp với điều kiện trong database.\n *\n * Hàm này có hai cách sử dụng:\n *\n * 1. **Chỉ truyền `key`**\n * → Trả về toàn bộ dữ liệu của key (tương tự `get()`).\n *\n * 2. **Truyền `key` và `query`**\n * → Tìm phần tử đầu tiên trong mảng dữ liệu của key khớp với điều kiện.\n *\n * @template V - Kiểu dữ liệu của database.\n * @template P - Đường dẫn key trong object (`ObjectPath<V>`).\n *\n * @param key - Key hoặc đường dẫn đến dữ liệu cần truy vấn.\n * @param query - Đối tượng điều kiện để tìm bản ghi phù hợp.\n *\n * @returns\n * - Nếu chỉ có `key`: trả về toàn bộ dữ liệu của key.\n * - Nếu có `query`: trả về bản ghi đầu tiên khớp điều kiện.\n * - Nếu không tìm thấy: trả về `null`.\n *\n * @example\n * Chỉ lấy dữ liệu theo key\n * ```ts\n * const users = await db.findOne(\"user\");\n * ```\n *\n * @example\n * Tìm một bản ghi theo điều kiện\n * ```ts\n * const user = await db.findOne(\"user\", {\n * guild: 1234566\n * });\n * ```\n */\n public async findOne<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>, query?: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<Maybe<ObjectValue<V, P>> | V> {\n const data = await this.get(key as any);\n if (!query) return data;\n if (!Array.isArray(data)) return null as Maybe<ObjectValue<V, P>>;\n const result = data.find((item) => {\n return Object.entries(query as Record<string, any>).every(([k, v]) => item[k] == v);\n });\n return (result ?? null) as Maybe<ObjectValue<V, P>>;\n }\n /**\n * Kiểm tra một key-path có tồn tại trong database hay không.\n *\n * Method này sử dụng `get()` để xác định giá trị có tồn tại.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần kiểm tra.\n *\n * @returns `true` nếu key tồn tại, ngược lại `false`.\n *\n * @example\n * ```ts\n * const exists = await db.has(\"users.123\");\n * ```\n */\n public async has<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const value = await this.get(key);\n return value !== null && value !== undefined;\n }\n /**\n * Gán giá trị cho một key-path trong database.\n *\n * Nếu key-path chưa tồn tại, các object trung gian\n * sẽ được tự động tạo.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần gán giá trị.\n * @param {ObjectValue<V, P>} value Giá trị mới.\n *\n * @returns {Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>>} Giá trị vừa được set hoặc object root nếu value là object.\n *\n * @example\n * ```ts\n * await db.set(\"users.123.name\", \"Alice\");\n * ```\n *\n * @example\n * ```ts\n * await db.set(\"config.prefix\", \"!\");\n * ```\n */\n public async set<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, value: ObjectValue<V, P>): Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>> {\n const allDatabase = await this.all();\n if (!key) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"key\");\n }\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeOf(key));\n }\n const keys = key.split(\".\");\n let currentObj = allDatabase;\n\n for (let i = 0; i < keys.length; i++) {\n if (keys.length - 1 === i) {\n currentObj[keys[i]] = value\n } else {\n if (!isObject(currentObj[keys[i]])) {\n currentObj[keys[i]] = {};\n }\n currentObj = currentObj[keys[i]];\n };\n };\n await this.driver.set(allDatabase);\n return typeof value == \"object\" && value !== null ? await this.get(keys[0]) as any : value as any;\n }\n /**\n * Xóa một key khỏi database.\n *\n * Hỗ trợ nested path bằng dot notation.\n *\n * @typeParam P - Path của object.\n *\n * @param key - Đường dẫn key cần xóa.\n *\n * @returns\n * - `true` nếu xóa thành công\n * - `false` nếu key không tồn tại\n *\n * @throws BlackCatError\n * - INVALID_TYPE nếu key không phải string\n *\n * @example\n * await db.delete(\"user.name\");\n */\n public async delete<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>): Promise<boolean> {\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeof key);\n }\n const allDatabase = await this.all();\n const keys = key.split(\".\");\n const lastKey = keys.pop() as string;\n let currentObj: any = allDatabase;\n for (const k of keys) {\n if (!isObject(currentObj[k])) {\n return false;\n }\n currentObj = currentObj[k];\n }\n if (!(lastKey in currentObj)) return false;\n delete currentObj[lastKey];\n await this.driver.set(allDatabase);\n return true;\n }\n /**\n * Xóa toàn bộ dữ liệu trong database.\n *\n * Method này gọi trực tiếp `driver.delete()` để reset storage.\n *\n * @returns `true` sau khi dữ liệu đã được xóa.\n *\n * @example\n * await db.deleteAll();\n */\n public async deleteAll(): Promise<boolean> {\n await this.driver.delete();\n return true;\n }\n /**\n * Xóa nhiều bản ghi trong một mảng dữ liệu dựa trên điều kiện truy vấn.\n *\n * ⚠️ Method này **chỉ hoạt động với dữ liệu dạng mảng (array)**.\n * Nếu dữ liệu tại `key` không phải là mảng, method sẽ **không thực hiện xóa**\n * và trả về `0`.\n *\n * Method sẽ duyệt qua toàn bộ phần tử trong mảng và xóa những phần tử\n * khớp với điều kiện `query`.\n *\n * @template V - Kiểu dữ liệu của database.\n * @template P - Đường dẫn key trong object (`ObjectPath<V>`).\n *\n * @param key - Đường dẫn đến mảng dữ liệu cần thao tác.\n * @param query - Điều kiện để xác định các phần tử cần xóa.\n * Có thể truyền:\n * - Một object điều kiện\n *\n * @returns Số lượng phần tử đã bị xóa khỏi mảng.\n *\n * @example\n * Database mẫu:\n * ```json\n * {\n * \"member\": {\n * \"user\": {\n * \"database\": [\n * { \"guild\": \"123\", \"username\": \"vinh\" },\n * { \"guild\": \"456\", \"username\": \"test\" }\n * ]\n * }\n * }\n * }\n * ```\n *\n * @example\n * Xóa tất cả user có guild = \"123\"\n * ```ts\n * await db.deleteMany(\"member.user.database\", {\n * guild: \"123\"\n * });\n * ```\n */\n public async deleteMany<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, query: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<number> {\n const data = await this.get(key as any);\n if (!Array.isArray(data)) return 0;\n const originalLength = data.length;\n const filtered = data.filter((item: any) => {\n return !Object.entries(query as Record<string, any>).every(([k, v]) => item[k] == v);\n });\n await this.set(key, filtered as any);\n\n return originalLength - filtered.length;\n }\n /**\n * Cập nhật giá trị của một key-path trong database.\n *\n * Khác với `set()`, method này chỉ ghi đè giá trị của key cuối cùng\n * trong path mà không thay đổi cấu trúc object phía trên.\n *\n * Nếu các object trung gian trong path chưa tồn tại\n * thì chúng sẽ được tự động tạo.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn dữ liệu cần cập nhật.\n * @param value Giá trị mới.\n *\n * @returns Object cha của key vừa cập nhật.\n *\n * @example\n * ```ts\n * await db.update(\"users.123.name\", \"Alice\");\n * ```\n */\n public async update<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, value: ObjectValue<V, P>): Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>> {\n const allDatabase = await this.all();\n const keys = key.split(\".\");\n let current: any = allDatabase;\n\n for (let i = 0; i < keys.length - 1; i++) {\n const part = keys[i];\n if (!(part in current)) {\n current[part] = {};\n }\n current = current[part];\n }\n\n const lastKey = keys[keys.length - 1];\n current[lastKey] = value;\n\n await this.driver.set(allDatabase);\n return current;\n }\n /**\n * Cộng thêm giá trị vào một key dạng number.\n *\n * Nếu key chưa tồn tại, giá trị mặc định sẽ là `0`.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn dữ liệu dạng number.\n * @param numberToAdd Số cần cộng thêm.\n *\n * @returns Giá trị mới sau khi cộng.\n *\n * @example\n * ```ts\n * await db.add(\"economy.users.123.balance\", 50);\n * ```\n */\n public async add<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, numberToAdd: number): Promise<number> {\n const targetNumber = await this.get(key) as any ?? 0;\n\n if (!isNumber(targetNumber)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"number\", typeOf(targetNumber));\n }\n if (numberToAdd === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"numberToAdd\");\n }\n if (!isNumber(numberToAdd)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"numberToAdd\", \"number\", typeOf(numberToAdd));\n }\n return await this.set(key, targetNumber + numberToAdd) as Promise<number>;\n }\n /**\n * Trừ giá trị khỏi một key dạng number.\n *\n * Nếu key chưa tồn tại, giá trị mặc định sẽ là `0`.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn dữ liệu dạng number.\n * @param numberToSubtract Số cần trừ.\n *\n * @returns Giá trị mới sau khi trừ.\n *\n * @example\n * ```ts\n * await db.subtract(\"economy.users.123.balance\", 20);\n * ```\n */\n public async subtract<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, numberToSubtract: number): Promise<number> {\n const targetNumber = await this.get(key) as any ?? 0;\n\n if (!isNumber(targetNumber)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"number\", typeOf(targetNumber));\n }\n if (numberToSubtract === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"numberToSubtract\");\n }\n if (!isNumber(numberToSubtract)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"numberToSubtract\", \"number\", typeOf(numberToSubtract));\n }\n return await this.set(key, targetNumber - numberToSubtract as any) as Promise<number>;\n }\n /**\n * Thêm một hoặc nhiều phần tử vào cuối array tại key-path.\n *\n * Method này sẽ:\n * - kiểm tra target có phải array không\n * - chỉ thêm các giá trị **chưa tồn tại** trong array\n *\n * ⚠️ Nếu key không tồn tại hoặc target không phải array\n * thì sẽ ném lỗi.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn tới array cần thêm phần tử.\n * @param values Một hoặc nhiều giá trị cần thêm.\n *\n * @returns Array sau khi thêm phần tử.\n *\n * @example\n * ```ts\n * await db.push(\"users.123.roles\", \"admin\");\n * ```\n *\n * @example\n * ```ts\n * await db.push(\"queue.songs\", song1, song2);\n * ```\n */\n public async push<P extends ObjectPath<V>>(key: AutocompletableString<P>, ...values: RestOrArray<ExtractFromArray<ObjectValue<V, P>>>): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n if (!values.length) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"values\");\n }\n const root = await this.all();\n const pathParts = key.split(\".\");\n let target = root;\n for (let i = 0; i < pathParts.length; i++) {\n const part = pathParts[i];\n if (!(part in target)) {\n throw new BlackCatError(\"INVALID_KEY\", key);\n }\n if (i === pathParts.length - 1) {\n if (!Array.isArray(target[part])) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(target[part]));\n }\n const uniqueValues = (values as any[]).filter(v => !target[part].includes(v));\n target[part].push(...uniqueValues);\n } else {\n target = target[part];\n }\n };\n const topKey = pathParts[0];\n await this.set(topKey, root[topKey]);\n return target[pathParts[pathParts.length - 1]];\n }\n /**\n * Thay thế phần tử trong array theo index.\n *\n * @typeParam P - Path trỏ đến array.\n *\n * @param key - Đường dẫn array.\n * @param targetArrayElementIndex - Index cần thay.\n * @param value - Giá trị mới.\n *\n * @returns Array sau khi thay thế.\n *\n * @throws BlackCatError\n * - INVALID_TYPE nếu index không phải number\n * - REQUIRED_PARAMETER_MISSING nếu thiếu value\n * - INVALID_KEY nếu path không tồn tại\n * - INVALID_TARGET nếu target không phải array\n *\n * @example\n * await db.pull(\"users\", 0, { id: 2 });\n */\n public async pull<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, targetArrayElementIndex: number, value: ExtractFromArray<ObjectValue<V, P>>,): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n if (!isNumber(targetArrayElementIndex)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"targetArrayElementIndex\", \"number\", typeOf(targetArrayElementIndex));\n };\n if (value === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"value\");\n };\n const root = await this.all();\n const pathParts = key.split(\".\");\n let target: any = root;\n for (let i = 0; i < pathParts.length; i++) {\n const part = pathParts[i];\n if (!(part in target)) {\n throw new BlackCatError(\"INVALID_KEY\", `Path \"${key}\" does not exist`);\n }\n if (i === pathParts.length - 1) {\n if (!Array.isArray(target[part])) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(target[part]));\n };\n const arr = target[part];\n const index = targetArrayElementIndex >= 0 ? targetArrayElementIndex : arr.length + targetArrayElementIndex;\n if (index < 0 || index >= arr.length) {\n console.error(`Index ${targetArrayElementIndex} is out of bounds`);\n };\n arr[index] = value;\n } else {\n target = target[part];\n };\n };\n await this.set(pathParts[0], root[pathParts[0]]);\n return target[pathParts[pathParts.length - 1]];\n }\n /**\n * Xóa phần tử khỏi array theo index.\n *\n * Có thể truyền nhiều index hoặc một array index.\n *\n * @typeParam P - Path trỏ đến array.\n *\n * @param key - Đường dẫn array.\n * @param targetArrayElementIndexes - Các index cần xóa.\n *\n * @returns Danh sách phần tử đã bị xóa.\n *\n * @throws BlackCatError\n * - INVALID_TARGET nếu target không phải array\n * - REQUIRED_PARAMETER_MISSING nếu thiếu index\n * - ONE_OR_MORE_ARRAY_TYPES_INVALID nếu index không phải number\n *\n * @example\n * await db.pop(\"users\", 0);\n * await db.pop(\"numbers\", [1, 2, 3]);\n */\n public async pop<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, ...targetArrayElementIndexes: RestOrArray<ExtractFromArray<number>>): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n const targetArray = await this.get(key) ?? [];\n\n if (!Array.isArray(targetArray)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(targetArray));\n };\n\n if (!targetArrayElementIndexes.length) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"targetArrayElementIndex\");\n };\n const indexes = Array.isArray(targetArrayElementIndexes[0]) ? (targetArrayElementIndexes[0] as number[]) : (targetArrayElementIndexes as number[]);\n if (indexes.some(index => !isNumber(index))) {\n throw new BlackCatError(\"ONE_OR_MORE_ARRAY_TYPES_INVALID\", \"targetArrayElementIndexes\", \"number\", createTypesArray(indexes));\n };\n\n const sortedIndexes = [...indexes].sort((a, b) => b - a);\n const removedElements: any[] = [];\n\n for (const index of sortedIndexes) {\n const removed = targetArray.splice(index, 1);\n removedElements.push(...removed);\n };\n\n const parentPath = key.split(\".\").slice(0, -1).join(\".\") as AutocompletableString<any>;\n const fieldName = key.split(\".\").slice(-1)[0];\n\n if (parentPath) {\n const parentObject = await this.get(parentPath) as Record<string, any> ?? {};\n parentObject[fieldName] = targetArray;\n await this.set(parentPath, parentObject as NonNullable<Exclude<ObjectValue<V, P>, undefined>>);\n } else {\n await this.set(key, targetArray as NonNullable<Exclude<ObjectValue<V, P>, undefined>>);\n };\n return removedElements;\n }\n /**\n * Kiểm tra xem giá trị tại key có phải là Array hay không.\n *\n * @typeParam P - Path của object trong database.\n * @param key - Đường dẫn key cần kiểm tra.\n *\n * @returns `true` nếu giá trị là Array, ngược lại `false`.\n *\n * @example\n * const result = await db.isTargetArray(\"users\");\n * console.log(result);\n */\n public async isTargetArray<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const target = await this.get(key);\n return Array.isArray(target);\n }\n /**\n * Kiểm tra xem giá trị tại key có phải là Number hay không.\n *\n * @typeParam P - Path của object trong database.\n *\n * @param key - Đường dẫn key cần kiểm tra.\n *\n * @returns `true` nếu giá trị là Number, ngược lại `false`.\n *\n * @example\n * const result = await db.isTargetNumber(\"stats.score\");\n * console.log(result);\n */\n public async isTargetNumber<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const target = await this.get(key);\n return isNumber(target);\n }\n /**\n * Lấy danh sách các key của object trong database.\n *\n * Nếu không truyền `key` → trả về các key cấp cao nhất của database.\n *\n * @typeParam P - Path của object.\n *\n * @param key - Path của object cần lấy danh sách key.\n *\n * @returns Mảng các key tồn tại (không bao gồm `null` hoặc `undefined`).\n *\n * @example\n * const rootKeys = await db.keys();\n * const userKeys = await db.keys(\"user\");\n */\n public async keys<P extends AutocompletableString<ObjectPath<V>>>(key?: P): Promise<ObjectPath<P>[]> {\n if (!key) return TypedObject.keys(await this.all()) as ObjectPath<P>[];\n const data = await this.get(key) as Record<string, any>;\n return TypedObject.keys(data).filter((key) => data[key] !== undefined && data[key] !== null) as any\n }\n /**\n * Lấy số lượng key cấp cao nhất trong database.\n *\n * @returns Tổng số key ở root level.\n *\n * @example\n * const count = await db.size();\n */\n public async size(): Promise<number> {\n const keys = await this.keys();\n return keys.length;\n }\n /**\n * Lấy danh sách các giá trị từ database.\n *\n * Nếu không truyền `key` → trả về toàn bộ values ở root level.\n * Nếu truyền `key` → trả về values của object tại path đó.\n *\n * @typeParam P - Path của object trong database.\n *\n * @param key - Đường dẫn object cần lấy values.\n *\n * @returns Mảng các giá trị.\n *\n * @example\n * const allValues = await db.values();\n *\n * const userValues = await db.values(\"users\");\n */\n public async values<P extends AutocompletableString<ObjectPath<V>>>(key?: P): Promise<ObjectValue<V, P>[]> {\n if (!key) return TypedObject.values(await this.all());\n const data = await this.get(key) as Record<string, any>;\n return TypedObject.values(data) as ObjectValue<V, P>[];\n }\n /**\n * Lấy ngẫu nhiên một phần tử từ array tại path được chỉ định.\n *\n * @typeParam P - Path trỏ đến array trong database.\n *\n * @param key - Đường dẫn đến array.\n *\n * @returns Một phần tử ngẫu nhiên trong array hoặc `null` nếu array rỗng.\n *\n * @throws BlackCatError\n * - INVALID_TARGET nếu giá trị tại key không phải array\n *\n * @example\n * const randomUser = await db.random(\"users\");\n */\n public async random<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<Maybe<ObjectValue<V, P>>> {\n const array = await this.get(key);\n if (!Array.isArray(array)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(array));\n }\n return array[Math.floor(Math.random() * array.length)] ?? null;\n }\n /**\n * Tìm phần tử đầu tiên thỏa điều kiện.\n *\n * Hoạt động tương tự `Array.prototype.find`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Phần tử đầu tiên thỏa điều kiện hoặc `null` nếu không tìm thấy.\n *\n * @example\n * const user = await db.find(u => u.id === 1);\n */\n public async find(queryFunction: QueryFunction<V>): Promise<Maybe<V>> {\n const values = await this.values();\n return values.find(queryFunction as QueryFunction<ObjectValue<V, any>>) as Promise<Maybe<V>> ?? null;\n }\n /**\n * Biến đổi tất cả giá trị trong database thành một mảng mới.\n *\n * Hoạt động giống `Array.prototype.map`.\n *\n * @typeParam TReturnType - Kiểu dữ liệu của phần tử trả về.\n *\n * @param queryFunction - Hàm transform từng phần tử.\n *\n * @returns Mảng kết quả sau khi transform.\n *\n * @example\n * const names = await db.map(user => user.name);\n */\n public async map<TReturnType>(queryFunction: QueryFunction<V, TReturnType>): Promise<TReturnType[]> {\n const values = await this.values();\n return values.map(queryFunction as QueryFunction<ObjectValue<V, any>, TReturnType>);\n }\n /**\n * Tìm index của phần tử đầu tiên thỏa điều kiện.\n *\n * Hoạt động giống `Array.prototype.findIndex`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Index của phần tử hoặc `-1` nếu không tìm thấy.\n *\n * @example\n * const index = await db.findIndex(user => user.id === 1);\n */\n public async findIndex(queryFunction: QueryFunction<V>): Promise<number> {\n const values = await this.values();\n return values.findIndex(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n /**\n * Lọc các phần tử thỏa điều kiện.\n *\n * Hoạt động giống `Array.prototype.filter`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Mảng các phần tử thỏa điều kiện.\n *\n * @example\n * const admins = await db.filter(user => user.role === \"admin\");\n */\n public async filter(queryFunction: QueryFunction<V>): Promise<V[]> {\n const values = await this.values();\n return values.filter(queryFunction as QueryFunction<ObjectValue<V, any>>) as any;\n }\n /**\n * Kiểm tra có ít nhất một phần tử thỏa điều kiện hay không.\n *\n * Hoạt động giống `Array.prototype.some`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns `true` nếu tồn tại phần tử thỏa điều kiện.\n *\n * @example\n * const hasAdmin = await db.some(user => user.role === \"admin\");\n */\n public async some(queryFunction: QueryFunction<V>): Promise<boolean> {\n const values = await this.values();\n return values.some(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n /**\n * Kiểm tra tất cả phần tử có thỏa điều kiện hay không.\n *\n * Hoạt động giống `Array.prototype.every`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns `true` nếu tất cả phần tử đều thỏa điều kiện.\n *\n * @example\n * const allActive = await db.every(user => user.active === true);\n */\n public async every(queryFunction: QueryFunction<V>): Promise<boolean> {\n const values = await this.values();\n return values.every(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n}","import { promises as fs } from \"fs\";\nimport { DatabaseDriver } from \"../types\";\n\n/**\n * Cấu hình khởi tạo cho {@link JSONDriver}.\n */\ninterface JSONDriverOptions {\n /**\n * Đường dẫn tới file JSON dùng làm database.\n *\n * Ví dụ:\n * ```ts\n * \"./database.json\"\n * \"./data/users.json\"\n * ```\n */\n filePath: string;\n /**\n * Nếu bật, nội dung JSON sẽ được **minify**\n * (không format khoảng trắng) để giảm dung lượng file.\n *\n * Nếu tắt, JSON sẽ được format với indentation để dễ đọc.\n *\n * @default false\n */\n minifyJSON?: boolean;\n}\n\n/**\n * Driver lưu trữ dữ liệu dạng JSON.\n *\n * ⚠️ Đây **không phải database hoàn chỉnh**.\n * Class này chỉ đóng vai trò **driver lưu trữ (storage layer)**\n * cho class chính `Database`.\n *\n * Toàn bộ logic xử lý key path (`a.b.c`), validate dữ liệu,\n * và các thao tác database sẽ được thực hiện trong class `Database`.\n *\n * `JSONDriver` chỉ chịu trách nhiệm:\n *\n * - Đọc dữ liệu từ file JSON\n * - Ghi dữ liệu xuống file JSON\n * \n * @example \n * ```ts\n * const database = new Database({\n * driber: new JSONDriver({\\\n * filePath: \"./database.json\",\n * minifyJSON: false\n * })\n * });\n * ```\n */\nexport class JSONDriver implements DatabaseDriver {\n /**\n * Đường dẫn tới file database JSON.\n */\n private filePath: string;\n /**\n * Cho biết có minify JSON khi ghi file hay không.\n */\n public minifyJSON: boolean;\n /**\n * Khởi tạo một instance mới của {@link JSONDriver}.\n *\n * @param options - Cấu hình driver\n *\n * @param options.filePath\n * Đường dẫn tới file JSON dùng làm database.\n *\n * @param options.minifyJSON\n * Nếu `true`, nội dung JSON sẽ được minify khi ghi ra file để giảm dung lượng.\n *\n * @example\n * ```ts\n * const database = new Database({\n * driver: db = new JSONDriver({\n * filePath: \"./database.json\"\n * })\n * });\n * ```\n */\n constructor(options: JSONDriverOptions) {\n this.filePath = options.filePath || \"database.json\";\n this.minifyJSON = options.minifyJSON || false;\n\n }\n /**\n * Đảm bảo file database tồn tại.\n * Nếu file chưa tồn tại sẽ tự động tạo file `{}`.\n */\n private async ensureFile(): Promise<void> {\n try {\n await fs.access(this.filePath);\n } catch {\n await fs.writeFile(this.filePath, \"{}\");\n }\n }\n /**\n * Đọc toàn bộ dữ liệu từ file database JSON.\n *\n * Nếu file không tồn tại hoặc lỗi parse,\n * method sẽ trả về object rỗng.\n *\n * @template V Kiểu dữ liệu database.\n * @returns Promise chứa toàn bộ dữ liệu database.\n */\n public async all<V>(): Promise<V> {\n await this.ensureFile();\n return fs.readFile(this.filePath, \"utf-8\").then((content) => JSON.parse(content) as V).catch((error) => {\n console.error(`Không thể đọc file database: ${this.filePath}`, error);\n return {} as V;\n });\n }\n /**\n * Ghi toàn bộ dữ liệu database xuống file JSON.\n *\n * Method này **không xử lý key path**.\n * Logic cập nhật dữ liệu sẽ được xử lý ở class `Database`\n * trước khi truyền object hoàn chỉnh vào đây.\n *\n * @param data Toàn bộ dữ liệu database sau khi đã được cập nhật.\n *\n * @template R Kiểu dữ liệu database.\n * @returns Promise chứa dữ liệu đã ghi.\n */\n public async set<R = any>(data: R): Promise<R> {\n await this.ensureFile();\n await fs.writeFile(this.filePath, JSON.stringify(data, null, this.minifyJSON ? undefined : \"\\t\"));\n return data;\n }\n /**\n * Xóa toàn bộ database.\n *\n * Method này chỉ reset file JSON về `{}`.\n *\n * @returns `true` nếu reset thành công.\n */\n public async delete(): Promise<boolean> {\n await this.ensureFile();\n await fs.writeFile(this.filePath, \"{}\");\n return true;\n }\n}","import { DatabaseDriver } from \"../types\";\r\n\r\n/**\r\n * Driver lưu trữ dữ liệu trong RAM.\r\n *\r\n * ⚠️ Đây **không phải database chính**.\r\n * Class này chỉ là **storage driver phụ trợ** cho class `Database`.\r\n *\r\n * Toàn bộ logic xử lý:\r\n * - key path (`a.b.c`)\r\n * - validation\r\n * - update dữ liệu\r\n *\r\n * đều được thực hiện trong class `Database`.\r\n *\r\n * `MemoryDriver` chỉ chịu trách nhiệm:\r\n * - lưu trữ object database trong RAM\r\n * - trả về toàn bộ dữ liệu\r\n *\r\n * Dữ liệu sẽ **mất khi ứng dụng restart**.\r\n *\r\n * Phù hợp cho:\r\n * - testing\r\n * - cache runtime\r\n * - development\r\n * \r\n * @example\r\n * ```ts\r\n * const database = new Database({\r\n * driver: new MemoryDriver({\r\n * users: {},\r\n * guilds: {},\r\n * settings: {\r\n * prefix: \"!\"\r\n * }\r\n * })\r\n * });\r\n * ```\r\n * \r\n * hoặc \r\n * \r\n * ```ts\r\n * const database = new Database({\r\n * driver: new MemoryDriver()\r\n * });\r\n * ```\r\n */\r\nexport class MemoryDriver implements DatabaseDriver {\r\n /**\r\n * Object chứa toàn bộ dữ liệu database trong RAM.\r\n */\r\n private store: Record<string, any>;\r\n /**\r\n * Khởi tạo MemoryDriver.\r\n *\r\n * @param initialData Dữ liệu khởi tạo ban đầu.\r\n * * @example\r\n * ```ts\r\n * const database = new Database({\r\n * driver: new MemoryDriver({\r\n * users: {},\r\n * guilds: {},\r\n * settings: {\r\n * prefix: \"!\"\r\n * }\r\n * })\r\n * });\r\n * ```\r\n * \r\n * hoặc \r\n * \r\n * ```ts\r\n * const database = new Database({\r\n * driver: new MemoryDriver()\r\n * });\r\n * ```\r\n */\r\n constructor(initialData: Record<string, any> = {}) {\r\n this.store = initialData;\r\n }\r\n /**\r\n * Trả về toàn bộ dữ liệu database.\r\n *\r\n * @template T Kiểu dữ liệu database.\r\n */\r\n public async all<T = any>(): Promise<T> {\r\n return this.store as T;\r\n }\r\n /**\r\n * Ghi toàn bộ database vào memory.\r\n *\r\n * ⚠️ Method này **không xử lý key-path**.\r\n * Dữ liệu đã được xử lý trước bởi `Database`.\r\n *\r\n * @param data Toàn bộ database object\r\n */\r\n public async set<T = any>(data: T): Promise<T> {\r\n this.store = data as any;\r\n return data;\r\n }\r\n /**\r\n * Xóa toàn bộ dữ liệu database trong memory.\r\n */\r\n public async delete(): Promise<boolean> {\r\n this.store = {};\r\n return true;\r\n }\r\n}","import SQLite from \"better-sqlite3\";\r\nimport { DatabaseDriver } from \"../types\";\r\n\r\n/**\r\n * Các tùy chọn cấu hình cho SQLiteDriver.\r\n * @hidden\r\n *\r\n * Interface này định nghĩa các thiết lập được sử dụng khi\r\n * khởi tạo driver SQLite cho hệ thống database.\r\n */\r\ninterface SQLiteDriverOptions {\r\n /**\r\n * Đường dẫn đến file cơ sở dữ liệu SQLite.\r\n *\r\n * Nếu không được cung cấp, driver có thể tạo\r\n * một file database mặc định tùy theo cách triển khai.\r\n *\r\n * Ví dụ:\r\n * `\"./database.sqlite\"`\r\n */\r\n filePath?: string;\r\n /**\r\n * Tên bảng được sử dụng để lưu trữ dữ liệu key-value.\r\n *\r\n * Nếu không được chỉ định, driver có thể sử dụng\r\n * một tên bảng mặc định (ví dụ: `\"data\"`).\r\n *\r\n * Ví dụ:\r\n * `\"storage\"`\r\n */\r\n table?: string;\r\n}\r\n/**\r\n * Driver lưu trữ dữ liệu bằng SQLite.\r\n *\r\n * ⚠️ Đây **không phải database chính**.\r\n * Class này chỉ là **driver lưu trữ phụ trợ** cho `Database`.\r\n *\r\n * Logic xử lý dữ liệu như:\r\n * - parse key path\r\n * - update object\r\n * - validation\r\n *\r\n * sẽ được thực hiện bởi class `Database`.\r\n *\r\n * Driver này chỉ:\r\n * - serialize database thành JSON\r\n * - lưu JSON vào SQLite\r\n * - trả về JSON khi đọc\r\n *\r\n * Toàn bộ database được lưu trong **một row duy nhất**.\r\n * \r\n * @example\r\n * ```ts\r\n * const database = new Database({\r\n * driver: new SQLiteDriver({\r\n * filePath: \"database.sqlite\",\r\n * table: \"json_store\"\r\n * })\r\n * })\r\n * ```\r\n */\r\nexport class SQLiteDriver implements DatabaseDriver {\r\n /**\r\n * SQLite database instance.\r\n */\r\n private db: SQLite.Database;\r\n /**\r\n * Tên table lưu trữ dữ liệu JSON.\r\n */\r\n private table: string;\r\n /**\r\n * Khởi tạo SQLiteDriver.\r\n *\r\n * @param filePath Đường dẫn file SQLite\r\n * @param table Tên table lưu JSON database\r\n * @example\r\n * ```ts\r\n * const database = new Database({\r\n * driver: new SQLiteDriver({\r\n * filePath: \"database.sqlite\",\r\n * table: \"json_store\"\r\n * })\r\n * })\r\n * ```\r\n */\r\n constructor(options: SQLiteDriverOptions = {}) {\r\n this.db = new SQLite(options.filePath ?? \"database.sqlite\");\r\n this.table = options.table ?? \"json_store\";\r\n this.db.prepare(`CREATE TABLE IF NOT EXISTS ${this.table} (id INTEGER PRIMARY KEY, data TEXT)`).run();\r\n const row = this.db.prepare(`SELECT * FROM ${this.table} WHERE id = 1`).get();\r\n if (!row) {\r\n this.db.prepare(`INSERT INTO ${this.table} (id, data) VALUES (1, '{}')`).run();\r\n }\r\n }\r\n /**\r\n * Lấy toàn bộ dữ liệu database từ SQLite.\r\n *\r\n * @template T Kiểu dữ liệu database.\r\n */\r\n public async all<T = any>(): Promise<T> {\r\n const row = this.db.prepare(`SELECT data FROM ${this.table} WHERE id = 1`).get() as { data: string };\r\n return JSON.parse(row.data) as T;\r\n }\r\n /**\r\n * Ghi toàn bộ database vào SQLite.\r\n *\r\n * ⚠️ Method này **không xử lý key-path**.\r\n * `Database` đã cập nhật object trước khi truyền vào đây.\r\n *\r\n * @param data Toàn bộ database object\r\n */\r\n public async set<T = any>(data: T): Promise<T> {\r\n this.db.prepare(`UPDATE ${this.table} SET data = ? WHERE id = 1`).run(JSON.stringify(data));\r\n return data;\r\n }\r\n /**\r\n * Reset toàn bộ database.\r\n */\r\n public async delete(): Promise<boolean> {\r\n this.db.prepare(`UPDATE ${this.table} SET data = '{}' WHERE id = 1`).run();\r\n return true;\r\n }\r\n}","import { MongoClient, Db, Collection } from \"mongodb\";\r\nimport type { DatabaseDriver } from \"../types\";\r\n\r\n/**\r\n * Cấu hình cho MongoDriver.\r\n */\r\ninterface MongoDriverOptions {\r\n /**\r\n * Chuỗi kết nối MongoDB.\r\n *\r\n * @default \"mongodb://localhost:27017\"\r\n */\r\n mongourl?: string;\r\n /**\r\n * Tên database MongoDB.\r\n *\r\n * @default \"database\"\r\n */\r\n databaseName?: string;\r\n /**\r\n * Tên collection lưu dữ liệu JSON.\r\n *\r\n * @default \"json_store\"\r\n */\r\n collectionName?: string;\r\n}\r\n/**\r\n * Schema document dùng để lưu trữ database trong MongoDB.\r\n */\r\ninterface DatabaseDocument<V = any> {\r\n _id: string;\r\n data: V;\r\n}\r\n/**\r\n * Driver lưu trữ dữ liệu bằng MongoDB.\r\n *\r\n * ⚠️ Đây **không phải database chính**.\r\n * Class này chỉ là **driver lưu trữ phụ trợ** cho class `Database`.\r\n *\r\n * Logic xử lý:\r\n * - parse key path\r\n * - validate dữ liệu\r\n * - cập nhật object\r\n *\r\n * sẽ được xử lý bởi class `Database`.\r\n *\r\n * `MongoDriver` chỉ chịu trách nhiệm:\r\n * - lưu toàn bộ database object\r\n * - trả về database object\r\n *\r\n * Toàn bộ database được lưu trong **một document duy nhất**.\r\n * \r\n * @example \r\n * ```ts\r\n * const database = new Database({ \r\n * driver: new MongoDriver({\r\n * mongourl: \"mongodb://localhost:27017\", \r\n * databaseName: \"mydb\", \r\n * collectionName: \"store\" \r\n * })\r\n * });\r\n * ```\r\n */\r\nexport class MongoDriver implements DatabaseDriver {\r\n /**\r\n * MongoDB client instance.\r\n */\r\n private client: MongoClient;\r\n /**\r\n * MongoDB database instance.\r\n */\r\n private db!: Db;\r\n /**\r\n * Collection lưu dữ liệu JSON.\r\n */\r\n private collection!: Collection<DatabaseDocument>;\r\n /**\r\n * Tên database MongoDB.\r\n */\r\n private databaseName: string;\r\n /**\r\n * Tên collection MongoDB.\r\n */\r\n private collectionName: string;\r\n /**\r\n * Khởi tạo MongoDriver.\r\n *\r\n * @param options Cấu hình MongoDB driver.\r\n * \r\n * @example \r\n * ```ts\r\n * const database = new Database({ \r\n * driver: new MongoDriver({\r\n * mongourl: \"mongodb://localhost:27017\", \r\n * databaseName: \"mydb\", \r\n * collectionName: \"store\" \r\n * })\r\n * });\r\n */\r\n constructor(options: MongoDriverOptions = {}) {\r\n const {\r\n mongourl = \"mongodb://localhost:27017\",\r\n databaseName = \"database\",\r\n collectionName = \"json_store\"\r\n } = options;\r\n this.client = new MongoClient(mongourl);\r\n this.databaseName = databaseName;\r\n this.collectionName = collectionName;\r\n }\r\n /**\r\n * Thiết lập kết nối MongoDB nếu chưa kết nối.\r\n */\r\n private async connect(): Promise<void> {\r\n if (!this.db) {\r\n await this.client.connect();\r\n this.db = this.client.db(this.databaseName);\r\n this.collection = this.db.collection(this.collectionName);\r\n const doc = await this.collection.findOne({ _id: \"database\" });\r\n if (!doc) {\r\n await this.collection.insertOne({\r\n _id: \"database\",\r\n data: {}\r\n });\r\n }\r\n }\r\n }\r\n /**\r\n * Lấy toàn bộ dữ liệu database từ MongoDB.\r\n */\r\n public async all<T = any>(): Promise<T> {\r\n await this.connect();\r\n const doc = await this.collection.findOne({ _id: \"database\" });\r\n return (doc?.data ?? {}) as T;\r\n }\r\n /**\r\n * Ghi toàn bộ database vào MongoDB.\r\n *\r\n * ⚠️ Method này **không xử lý key-path**.\r\n * Object database đã được xử lý bởi class `Database`.\r\n * \r\n * @param data Toàn bộ object database\r\n */\r\n public async set<T = any>(data: T): Promise<T> {\r\n await this.connect();\r\n await this.collection.updateOne(\r\n { _id: \"database\" },\r\n { $set: { data } }\r\n );\r\n return data;\r\n }\r\n /**\r\n * Reset toàn bộ database về object rỗng.\r\n */\r\n public async delete(): Promise<boolean> {\r\n await this.connect();\r\n await this.collection.updateOne(\r\n { _id: \"database\" },\r\n { $set: { data: {} } }\r\n );\r\n return true;\r\n }\r\n}"],"mappings":"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","names":["key"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/isObject.function.ts","../src/utils/typeOf.function.ts","../src/utils/isNumber.function.ts","../src/utils/BlackCatError.ts","../src/utils/TypedObject.ts","../src/utils/Emitter.ts","../src/Database.ts","../src/drivers/JSONDriver.ts","../src/drivers/MemoryDriver.ts","../src/drivers/SQLiteDriver.ts","../src/drivers/MongoDriver.ts"],"sourcesContent":["/**\n * Checks for is the item object and returns it.\n * @param {any} item The item to check.\n * @returns {boolean} Is the item object or not.\n */\nexport const isObject = (item: any): boolean => !Array.isArray(item) && item !== null && typeof item == \"object\";","/**\n * Returns the exact type of a given input.\n * @param input - The value to check.\n * @returns A string representing the exact type of the input.\n */\nexport const typeOf = (input: any): string => {\n // ✅ Handle special cases: null, undefined, and NaN\n if (input == null || (typeof input === \"number\" && Number.isNaN(input))) return String(input);\n // ✅ If it's a class constructor (has a prototype)\n if (typeof input === \"function\" && input.prototype) return `${input.name} class instance`;\n // ✅ If it's an object or function, return the constructor name if available\n return input?.constructor?.name ?? typeof input;\n};","import { typeOf } from \"./typeOf.function\";\n\n/**\n * Determines if the specified value is a number.\n *\n * A small hack to actually determine if the input is a number since\n * empty strings and arrays are considered as numbers too.\n * @param {any} input The input to check.\n * @returns {boolean} Whether the specified input is a number.\n */\nexport const isNumber = (input: any): boolean => !isNaN(input as number) && input !== \"\" && input !== null && typeOf(input) !== \"Array\";","import { typeOf } from \"./typeOf.function\";\n\nexport type TargetParamType = \"string\" | \"number\" | \"object\" | \"array\" | `${string} class instance`;\n\nexport const errors = {\n DEVICE_IS_OFFLINE: 'Your device appears to be offline so it\\'s impossible to proceed with ' + 'connection to your online MongoDB cluster. Please connect your device to the internet or switch to the ' + 'local MongoDB database and try again.',\n CONNECTION_NOT_ESTABLISHED: 'Failed to connect to MongoDB. Please double-check the specified ' + 'connection URI and make sure that you\\'re performing the ' + 'database connection using the `QuickMongoClient.connect()` method.',\n CONNECTION_URI_NOT_SPECIFIED: 'The MongoDB connection URI must be specified.',\n INVALID_CONNECTION_URI: 'The specified MongoDB connection URI is invalid.',\n UNKNOWN_ERROR: 'Unknown error.',\n REQUIRED_PARAMETER_MISSING: '\\'{1}\\' parameter is required but is missing.',\n REQUIRED_CONSTRUCTOR_PARAMETER_MISSING: '\\'{1}\\' parameter in constructor \\'{2}\\' is required but is missing.',\n INVALID_CONSTRUCTOR_PARAMETER_TYPE: '\\'{1}\\' parameter in constructor \\'{2}\\' must be ' + 'a type of {3}. Received type: {4}.',\n INVALID_TYPE: '\\'{1}\\' must be a type of {2}. Received type: {3}.',\n ONE_OR_MORE_ARRAY_TYPES_INVALID: 'All specified elements from array in \\'{1}\\' parameter ' + 'must be a type of {2}. Received array of types: {3}.',\n INVALID_TARGET: 'The target in database must be a type of {1}. Received target type: {2}.',\n INVALID_KEY: \"{1}\",\n INVALID_PARAMETER: \"{1} {2}\",\n DATABASE_CONNECTION_FAILED: \"{1}\"\n}\n\nexport interface ErrorParams extends Record<keyof typeof errors, string[]> {\n CONNECTION_NOT_ESTABLISHED: [];\n UNKNOWN_ERROR: [];\n CONNECTION_URI_NOT_SPECIFIED: [];\n INVALID_CONNECTION_URI: [];\n REQUIRED_PARAMETER_MISSING: [missingParam: string];\n REQUIRED_CONSTRUCTOR_PARAMETER_MISSING: [missingParam: string, className: string];\n INVALID_TYPE: [paramName: string, targetType: TargetParamType, receivedType: string];\n INVALID_CONSTRUCTOR_PARAMETER_TYPE: [paramName: string, className: string, targetType: TargetParamType, receivedType: string];\n ONE_OR_MORE_ARRAY_TYPES_INVALID: [paramName: string, targetType: TargetParamType, receivedTypesArray: string];\n INVALID_TARGET: [targetType: TargetParamType, receivedType: string];\n INVALID_KEY: [paramName: string];\n INVALID_PARAMETER: [paramName: string, receivedType: string];\n DATABASE_CONNECTION_FAILED: [paramName: string]\n}\nexport const createTypesArray = <T>(...elements: any): string => `[${elements.map((element: any) => typeOf(element))}]`;\n/**\n * BlackCatError class.\n */\nexport class BlackCatError<TErrorCode extends keyof typeof errors> extends Error {\n /** \n * Creates a BlackCatError instance.\n * @param {string} errorCode Quick Mongo error code.\n * @param {any[]} params Additional parameters to replace the placeholders in the error message.\n */\n public constructor(errorCode: TErrorCode, ...params: ErrorParams[TErrorCode]) {\n const code = errors[errorCode] ? errorCode : \"UNKNOWN_ERROR\" as TErrorCode;\n let message = errors[code];\n for (let i = 0; i < params.length; i++) {\n message = message.replaceAll(`{${i + 1}}`, params[i]);\n };\n super(message);\n /**\n * The name of the error.\n */\n this.name = `BlackCatError [${code}]`;\n }\n}","import { ExtractObjectKeys, ExtractObjectValues, ExtractObjectEntries } from \"../types\";\n\n/**\n * Utility class for working with objects.\n *\n * Provides **static** methods for retrieving keys and values of an object with addition of types.\n *\n * This class enhances type safety by providing better typings for object keys and values.\n */\nexport class TypedObject {\n /**\n * Returns the names of the enumerable string properties and methods of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object keys types from.\n *\n * @param {TObject} obj Object to get the keys from.\n *\n * @returns {Array<ExtractObjectKeys<TObject>>}\n * Array of names of the enumerable string properties and methods of the specified object.\n */\n public static keys<TObject extends Record<string, any>>(obj: TObject): ExtractObjectKeys<TObject>[] {\n return Object.keys(obj || {});\n }\n /**\n * Returns an array of values of the enumerable properties of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object values types from.\n *\n * @param {TObject} obj Object to get the values from.\n *\n * @returns {Array<ExtractObjectValues<TObject>>}\n * Array of values of the enumerable properties of the specified object.\n */\n public static values<TObject extends Record<string, any>>(obj: TObject): ExtractObjectValues<TObject>[] {\n return Object.values(obj || {});\n }\n /**\n * Returns an array of entries (key-value pairs) of the enumerable properties of an object.\n *\n * Type parameters:\n *\n * - `TObject` (`Record<string, any>`) - The object to get the object entries types (key-value pairs types) from.\n *\n * @param {TObject} obj Object to get the entries from.\n *\n * @returns {ExtractObjectEntries<TObject>[]}\n * Array of entries (key-value pairs) of the enumerable properties of the specified object.\n */\n public static entries<TObject extends Record<string, any>>(obj: TObject): ExtractObjectEntries<TObject>[] {\n return Object.entries(obj || {})\n }\n}","import { EventEmitter } from \"node:events\";\n\nexport class Emitter<E extends Record<string, any>> {\n private _emitter = new EventEmitter();\n /**\n * Listens to the event.\n * @param {string} event Event name.\n * @param {Function} listener Listener function.\n */\n public on<K extends Exclude<keyof E, number>>(event: K, listener: (...args: E[K]) => any): Emitter<E> {\n this._emitter.on(event, listener);\n return this;\n }\n /**\n * Listens to the event only for once.\n * @param {string} event Event name.\n * @param {Function} listener Listener function.\n */\n public once<K extends Exclude<keyof E, number>>(event: K, listener: (...args: E[K]) => any): Emitter<E> {\n this._emitter.once(event, listener);\n return this;\n }\n /**\n * Emits the event.\n * @param {string} event Event name.\n * @param {any[]} args Listener arguments.\n * @returns {boolean} `true` if the event had listeners, `false` otherwise.\n */\n public emit<K extends Exclude<keyof E, number>>(event: K, ...args: E[K]): boolean {\n return this._emitter.emit(event, ...args as any[]);\n }\n}","import { DatabaseConfiguration, AutocompletableString, FirstObjectKey, If, IsObject, ObjectPath, ObjectValue, Maybe, QueryFunction, RestOrArray, ExtractFromArray, DatabaseDriver, ArrayElement } from \"./types\";\nimport { BlackCatError, createTypesArray, isNumber, typeOf, TypedObject, isObject } from \"./utils\";\n\n/**\n * Class Database cung cấp API thao tác dữ liệu dạng key-path\n * trên nhiều loại storage khác nhau thông qua `DatabaseDriver`.\n *\n * Đây là **lớp database chính (logic layer)** của hệ thống.\n *\n * Class này chịu trách nhiệm:\n * - parse key path (`user.profile.name`)\n * - validate dữ liệu\n * - thao tác object\n * - query dữ liệu (find, filter, map...)\n *\n * Việc lưu trữ dữ liệu thực tế sẽ được thực hiện bởi các **driver phụ trợ**\n * như:\n *\n * - `JSONDriver`\n * - `MemoryDriver`\n * - `SQLiteDriver`\n * - `MongoDriver`\n *\n * Các driver này chỉ chịu trách nhiệm:\n * - đọc toàn bộ dữ liệu database\n * - ghi toàn bộ dữ liệu database\n *\n * @template V Kiểu dữ liệu tổng thể của database.\n */\nexport class Database<V = any> {\n /**\n * Storage driver được sử dụng để đọc và ghi dữ liệu database.\n *\n * Driver phải implement interface `DatabaseDriver`.\n *\n * Ví dụ:\n * ```ts\n * const db = new Database({\n * driver: new JSONDriver({ filePath: \"./database.json\" }),\n * })\n * ```\n */\n public driver: DatabaseDriver;\n /**\n * Khởi tạo Database instance.\n *\n * @param options Cấu hình database.\n * @param options.driver Driver lưu trữ dữ liệu.\n *\n * @example\n * ```ts\n * const db = new Database({\n * driver: new JSONDriver({ filePath: \"./database.json\" }),\n * })\n * ```\n *\n * Ví dụ với MongoDB:\n *\n * ```ts\n * const db = new Database({\n * driver: new MongoDriver({\n * uri: \"mongodb://localhost:27017\",\n * databaseName: \"mydb\"\n * })\n * });\n * ```\n */\n constructor(options: DatabaseConfiguration) {\n this.driver = options.driver;\n }\n /**\n * Lấy toàn bộ dữ liệu từ database thông qua driver.\n *\n * @template T Kiểu dữ liệu object database trả về.\n *\n * @returns Promise chứa toàn bộ dữ liệu database.\n *\n * @example\n * ```ts\n * const data = await db.all();\n * console.log(data.users);\n * ```\n */\n public async all<T extends Record<string, any> = Record<string, any>>(): Promise<T> {\n return await this.driver.all<T>();\n }\n /**\n * Lấy giá trị từ database theo key-path.\n *\n * Key có thể là chuỗi dạng path:\n *\n * ```\n * user.profile.name\n * economy.users.123.balance\n * ```\n *\n * Nếu không truyền `key`, method sẽ trả về **toàn bộ database**.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần lấy.\n *\n * @returns Giá trị tại key hoặc `null` nếu không tồn tại.\n *\n * @example\n * ```ts\n * const name = await db.get(\"user.profile.name\");\n * ```\n *\n * @example\n * ```ts\n * const all = await db.get();\n * ```\n */\n public async get<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>): Promise<Maybe<ObjectValue<V, P>> | V> {\n const data = await this.all();\n if (key === undefined) return data as V;\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeOf(key));\n }\n const keys = key.split(\".\");\n let result: any = data;\n for (const k of keys) {\n if (!isObject(result) && !Array.isArray(result)) return null;\n result = result[k];\n if (result === undefined) return null;\n }\n return result;\n }\n /**\n * Tìm và trả về một bản ghi đầu tiên khớp với điều kiện trong database.\n *\n * Hàm này có hai cách sử dụng:\n *\n * 1. **Chỉ truyền `key`**\n * → Trả về toàn bộ dữ liệu của key (tương tự `get()`).\n *\n * 2. **Truyền `key` và `query`**\n * → Tìm phần tử đầu tiên trong mảng dữ liệu của key khớp với điều kiện.\n *\n * @template V - Kiểu dữ liệu của database.\n * @template P - Đường dẫn key trong object (`ObjectPath<V>`).\n *\n * @param key - Key hoặc đường dẫn đến dữ liệu cần truy vấn.\n * @param query - Đối tượng điều kiện để tìm bản ghi phù hợp.\n *\n * @returns\n * - Nếu chỉ có `key`: trả về toàn bộ dữ liệu của key.\n * - Nếu có `query`: trả về bản ghi đầu tiên khớp điều kiện.\n * - Nếu không tìm thấy: trả về `null`.\n *\n * @example\n * Chỉ lấy dữ liệu theo key\n * ```ts\n * const users = await db.findOne(\"user\");\n * ```\n *\n * @example\n * Tìm một bản ghi theo điều kiện\n * ```ts\n * const user = await db.findOne(\"user\", {\n * guild: 1234566\n * });\n * ```\n */\n public async findOne<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>, query?: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<Maybe<ObjectValue<V, P>> | V> {\n const data = await this.get(key as any);\n if (!query) return data;\n if (!Array.isArray(data)) return null as Maybe<ObjectValue<V, P>>;\n const result = data.find((item) => {\n return Object.entries(query as Record<string, any>).every(([k, v]) => item[k] == v);\n });\n return (result ?? null) as Maybe<ObjectValue<V, P>>;\n }\n /**\n * Kiểm tra một key-path có tồn tại trong database hay không.\n *\n * Method này sử dụng `get()` để xác định giá trị có tồn tại.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần kiểm tra.\n *\n * @returns `true` nếu key tồn tại, ngược lại `false`.\n *\n * @example\n * ```ts\n * const exists = await db.has(\"users.123\");\n * ```\n */\n public async has<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const value = await this.get(key);\n return value !== null && value !== undefined;\n }\n /**\n * Gán giá trị cho một key-path trong database.\n *\n * Nếu key-path chưa tồn tại, các object trung gian\n * sẽ được tự động tạo.\n *\n * @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.\n *\n * @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần gán giá trị.\n * @param {ObjectValue<V, P>} value Giá trị mới.\n *\n * @returns {Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>>} Giá trị vừa được set hoặc object root nếu value là object.\n *\n * @example\n * ```ts\n * await db.set(\"users.123.name\", \"Alice\");\n * ```\n *\n * @example\n * ```ts\n * await db.set(\"config.prefix\", \"!\");\n * ```\n */\n public async set<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, value: ObjectValue<V, P>): Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>> {\n const allDatabase = await this.all();\n if (!key) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"key\");\n }\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeOf(key));\n }\n const keys = key.split(\".\");\n let currentObj = allDatabase;\n\n for (let i = 0; i < keys.length; i++) {\n if (keys.length - 1 === i) {\n currentObj[keys[i]] = value\n } else {\n if (!isObject(currentObj[keys[i]])) {\n currentObj[keys[i]] = {};\n }\n currentObj = currentObj[keys[i]];\n };\n };\n await this.driver.set(allDatabase);\n return typeof value == \"object\" && value !== null ? await this.get(keys[0]) as any : value as any;\n }\n /**\n * Xóa một key khỏi database.\n *\n * Hỗ trợ nested path bằng dot notation.\n *\n * @typeParam P - Path của object.\n *\n * @param key - Đường dẫn key cần xóa.\n *\n * @returns\n * - `true` nếu xóa thành công\n * - `false` nếu key không tồn tại\n *\n * @throws BlackCatError\n * - INVALID_TYPE nếu key không phải string\n *\n * @example\n * await db.delete(\"user.name\");\n */\n public async delete<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>): Promise<boolean> {\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeof key);\n }\n const allDatabase = await this.all();\n const keys = key.split(\".\");\n const lastKey = keys.pop() as string;\n let currentObj: any = allDatabase;\n for (const k of keys) {\n if (!isObject(currentObj[k])) {\n return false;\n }\n currentObj = currentObj[k];\n }\n if (!(lastKey in currentObj)) return false;\n delete currentObj[lastKey];\n await this.driver.set(allDatabase);\n return true;\n }\n /**\n * Xóa toàn bộ dữ liệu trong database.\n *\n * Method này gọi trực tiếp `driver.delete()` để reset storage.\n *\n * @returns `true` sau khi dữ liệu đã được xóa.\n *\n * @example\n * await db.deleteAll();\n */\n public async deleteAll(): Promise<boolean> {\n await this.driver.delete();\n return true;\n }\n /**\n * Xóa nhiều bản ghi trong một mảng dữ liệu dựa trên điều kiện truy vấn.\n *\n * ⚠️ Method này **chỉ hoạt động với dữ liệu dạng mảng (array)**.\n * Nếu dữ liệu tại `key` không phải là mảng, method sẽ **không thực hiện xóa**\n * và trả về `0`.\n *\n * Method sẽ duyệt qua toàn bộ phần tử trong mảng và xóa những phần tử\n * khớp với điều kiện `query`.\n *\n * @template V - Kiểu dữ liệu của database.\n * @template P - Đường dẫn key trong object (`ObjectPath<V>`).\n *\n * @param key - Đường dẫn đến mảng dữ liệu cần thao tác.\n * @param query - Điều kiện để xác định các phần tử cần xóa.\n * Có thể truyền:\n * - Một object điều kiện\n *\n * @returns Số lượng phần tử đã bị xóa khỏi mảng.\n *\n * @example\n * Database mẫu:\n * ```json\n * {\n * \"member\": {\n * \"user\": {\n * \"database\": [\n * { \"guild\": \"123\", \"username\": \"vinh\" },\n * { \"guild\": \"456\", \"username\": \"test\" }\n * ]\n * }\n * }\n * }\n * ```\n *\n * @example\n * Xóa tất cả user có guild = \"123\"\n * ```ts\n * await db.deleteMany(\"member.user.database\", {\n * guild: \"123\"\n * });\n * ```\n */\n public async deleteMany<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, query: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<number> {\n const data = await this.get(key as any);\n if (!Array.isArray(data)) return 0;\n const originalLength = data.length;\n const filtered = data.filter((item: any) => {\n return !Object.entries(query as Record<string, any>).every(([k, v]) => item[k] == v);\n });\n await this.set(key, filtered as any);\n\n return originalLength - filtered.length;\n }\n /**\n * Cập nhật dữ liệu trong database theo đường dẫn key.\n *\n * Hàm này sẽ tìm đến vị trí của `key` trong database và gán `value` vào đó.\n * Nếu `value` và giá trị hiện tại tại key đều là object thì sẽ thực hiện\n * **shallow merge** thay vì ghi đè toàn bộ object.\n *\n * Điều này giúp tránh việc làm mất các thuộc tính đã tồn tại.\n *\n * @template P - Đường dẫn key hợp lệ trong object database.\n *\n * @param key - Đường dẫn tới giá trị cần cập nhật.\n * Hỗ trợ nested path dạng `\"a.b.c\"`.\n *\n * @param value - Giá trị mới sẽ được cập nhật tại key.\n *\n * @returns\n * Trả về giá trị cuối cùng sau khi cập nhật.\n *\n * @example\n * Database ban đầu:\n * ```json\n * {\n * \"123\": {\n * \"guildID\": \"123\",\n * \"guildName\": \"BlackCat\",\n * \"history\": []\n * }\n * }\n * ```\n *\n * Cập nhật:\n * ```ts\n * await db.update(\"123\", {\n * history: [1,2,3]\n * });\n * ```\n *\n * Kết quả:\n * ```json\n * {\n * \"123\": {\n * \"guildID\": \"123\",\n * \"guildName\": \"BlackCat\",\n * \"history\": [1,2,3]\n * }\n * }\n * ```\n *\n * @throws {BlackCatError}\n * - `REQUIRED_PARAMETER_MISSING` nếu key không được cung cấp\n * - `INVALID_TYPE` nếu key không phải string\n */\n public async update<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, value: ObjectValue<V, P>): Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>> {\n if (!key) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"key\");\n }\n if (typeof key !== \"string\") {\n throw new BlackCatError(\"INVALID_TYPE\", \"key\", \"string\", typeOf(key));\n }\n const allDatabase = await this.all();\n const keys = key.split(\".\");\n let current: any = allDatabase;\n for (let i = 0; i < keys.length - 1; i++) {\n const part = keys[i];\n if (!isObject(current[part])) {\n current[part] = {};\n }\n current = current[part];\n }\n\n const lastKey = keys[keys.length - 1];\n if (isObject(value) && isObject(current[lastKey])) {\n current[lastKey] = {\n ...current[lastKey],\n ...value\n };\n } else {\n current[lastKey] = value;\n }\n await this.driver.set(allDatabase);\n return current[lastKey];\n }\n /**\n * Cộng thêm giá trị vào một key dạng number.\n *\n * Nếu key chưa tồn tại, giá trị mặc định sẽ là `0`.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn dữ liệu dạng number.\n * @param numberToAdd Số cần cộng thêm.\n *\n * @returns Giá trị mới sau khi cộng.\n *\n * @example\n * ```ts\n * await db.add(\"economy.users.123.balance\", 50);\n * ```\n */\n public async add<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, numberToAdd: number): Promise<number> {\n const targetNumber = await this.get(key) as any ?? 0;\n\n if (!isNumber(targetNumber)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"number\", typeOf(targetNumber));\n }\n if (numberToAdd === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"numberToAdd\");\n }\n if (!isNumber(numberToAdd)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"numberToAdd\", \"number\", typeOf(numberToAdd));\n }\n return await this.set(key, targetNumber + numberToAdd) as Promise<number>;\n }\n /**\n * Trừ giá trị khỏi một key dạng number.\n *\n * Nếu key chưa tồn tại, giá trị mặc định sẽ là `0`.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn dữ liệu dạng number.\n * @param numberToSubtract Số cần trừ.\n *\n * @returns Giá trị mới sau khi trừ.\n *\n * @example\n * ```ts\n * await db.subtract(\"economy.users.123.balance\", 20);\n * ```\n */\n public async subtract<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, numberToSubtract: number): Promise<number> {\n const targetNumber = await this.get(key) as any ?? 0;\n\n if (!isNumber(targetNumber)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"number\", typeOf(targetNumber));\n }\n if (numberToSubtract === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"numberToSubtract\");\n }\n if (!isNumber(numberToSubtract)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"numberToSubtract\", \"number\", typeOf(numberToSubtract));\n }\n return await this.set(key, targetNumber - numberToSubtract as any) as Promise<number>;\n }\n /**\n * Thêm một hoặc nhiều phần tử vào cuối array tại key-path.\n *\n * Method này sẽ:\n * - kiểm tra target có phải array không\n * - chỉ thêm các giá trị **chưa tồn tại** trong array\n *\n * ⚠️ Nếu key không tồn tại hoặc target không phải array\n * thì sẽ ném lỗi.\n *\n * @template P Key path trong database.\n *\n * @param key Đường dẫn tới array cần thêm phần tử.\n * @param values Một hoặc nhiều giá trị cần thêm.\n *\n * @returns Array sau khi thêm phần tử.\n *\n * @example\n * ```ts\n * await db.push(\"users.123.roles\", \"admin\");\n * ```\n *\n * @example\n * ```ts\n * await db.push(\"queue.songs\", song1, song2);\n * ```\n */\n public async push<P extends ObjectPath<V>>(key: AutocompletableString<P>, ...values: RestOrArray<ExtractFromArray<ObjectValue<V, P>>>): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n if (!values.length) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"values\");\n }\n const root = await this.all();\n const pathParts = key.split(\".\");\n let target = root;\n for (let i = 0; i < pathParts.length; i++) {\n const part = pathParts[i];\n if (!(part in target)) {\n throw new BlackCatError(\"INVALID_KEY\", key);\n }\n if (i === pathParts.length - 1) {\n if (!Array.isArray(target[part])) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(target[part]));\n }\n const uniqueValues = (values as any[]).filter(v => !target[part].includes(v));\n target[part].push(...uniqueValues);\n } else {\n target = target[part];\n }\n };\n const topKey = pathParts[0];\n await this.set(topKey, root[topKey]);\n return target[pathParts[pathParts.length - 1]];\n }\n /**\n * Thay thế phần tử trong array theo index.\n *\n * @typeParam P - Path trỏ đến array.\n *\n * @param key - Đường dẫn array.\n * @param targetArrayElementIndex - Index cần thay.\n * @param value - Giá trị mới.\n *\n * @returns Array sau khi thay thế.\n *\n * @throws BlackCatError\n * - INVALID_TYPE nếu index không phải number\n * - REQUIRED_PARAMETER_MISSING nếu thiếu value\n * - INVALID_KEY nếu path không tồn tại\n * - INVALID_TARGET nếu target không phải array\n *\n * @example\n * await db.pull(\"users\", 0, { id: 2 });\n */\n public async pull<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, targetArrayElementIndex: number, value: ExtractFromArray<ObjectValue<V, P>>,): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n if (!isNumber(targetArrayElementIndex)) {\n throw new BlackCatError(\"INVALID_TYPE\", \"targetArrayElementIndex\", \"number\", typeOf(targetArrayElementIndex));\n };\n if (value === undefined) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"value\");\n };\n const root = await this.all();\n const pathParts = key.split(\".\");\n let target: any = root;\n for (let i = 0; i < pathParts.length; i++) {\n const part = pathParts[i];\n if (!(part in target)) {\n throw new BlackCatError(\"INVALID_KEY\", `Path \"${key}\" does not exist`);\n }\n if (i === pathParts.length - 1) {\n if (!Array.isArray(target[part])) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(target[part]));\n };\n const arr = target[part];\n const index = targetArrayElementIndex >= 0 ? targetArrayElementIndex : arr.length + targetArrayElementIndex;\n if (index < 0 || index >= arr.length) {\n console.error(`Index ${targetArrayElementIndex} is out of bounds`);\n };\n arr[index] = value;\n } else {\n target = target[part];\n };\n };\n await this.set(pathParts[0], root[pathParts[0]]);\n return target[pathParts[pathParts.length - 1]];\n }\n /**\n * Xóa phần tử khỏi array theo index.\n *\n * Có thể truyền nhiều index hoặc một array index.\n *\n * @typeParam P - Path trỏ đến array.\n *\n * @param key - Đường dẫn array.\n * @param targetArrayElementIndexes - Các index cần xóa.\n *\n * @returns Danh sách phần tử đã bị xóa.\n *\n * @throws BlackCatError\n * - INVALID_TARGET nếu target không phải array\n * - REQUIRED_PARAMETER_MISSING nếu thiếu index\n * - ONE_OR_MORE_ARRAY_TYPES_INVALID nếu index không phải number\n *\n * @example\n * await db.pop(\"users\", 0);\n * await db.pop(\"numbers\", [1, 2, 3]);\n */\n public async pop<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, ...targetArrayElementIndexes: RestOrArray<ExtractFromArray<number>>): Promise<ExtractFromArray<ObjectValue<V, P>>[]> {\n const targetArray = await this.get(key) ?? [];\n\n if (!Array.isArray(targetArray)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(targetArray));\n };\n\n if (!targetArrayElementIndexes.length) {\n throw new BlackCatError(\"REQUIRED_PARAMETER_MISSING\", \"targetArrayElementIndex\");\n };\n const indexes = Array.isArray(targetArrayElementIndexes[0]) ? (targetArrayElementIndexes[0] as number[]) : (targetArrayElementIndexes as number[]);\n if (indexes.some(index => !isNumber(index))) {\n throw new BlackCatError(\"ONE_OR_MORE_ARRAY_TYPES_INVALID\", \"targetArrayElementIndexes\", \"number\", createTypesArray(indexes));\n };\n\n const sortedIndexes = [...indexes].sort((a, b) => b - a);\n const removedElements: any[] = [];\n\n for (const index of sortedIndexes) {\n const removed = targetArray.splice(index, 1);\n removedElements.push(...removed);\n };\n\n const parentPath = key.split(\".\").slice(0, -1).join(\".\") as AutocompletableString<any>;\n const fieldName = key.split(\".\").slice(-1)[0];\n\n if (parentPath) {\n const parentObject = await this.get(parentPath) as Record<string, any> ?? {};\n parentObject[fieldName] = targetArray;\n await this.set(parentPath, parentObject as NonNullable<Exclude<ObjectValue<V, P>, undefined>>);\n } else {\n await this.set(key, targetArray as NonNullable<Exclude<ObjectValue<V, P>, undefined>>);\n };\n return removedElements;\n }\n /**\n * Kiểm tra xem giá trị tại key có phải là Array hay không.\n *\n * @typeParam P - Path của object trong database.\n * @param key - Đường dẫn key cần kiểm tra.\n *\n * @returns `true` nếu giá trị là Array, ngược lại `false`.\n *\n * @example\n * const result = await db.isTargetArray(\"users\");\n * console.log(result);\n */\n public async isTargetArray<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const target = await this.get(key);\n return Array.isArray(target);\n }\n /**\n * Kiểm tra xem giá trị tại key có phải là Number hay không.\n *\n * @typeParam P - Path của object trong database.\n *\n * @param key - Đường dẫn key cần kiểm tra.\n *\n * @returns `true` nếu giá trị là Number, ngược lại `false`.\n *\n * @example\n * const result = await db.isTargetNumber(\"stats.score\");\n * console.log(result);\n */\n public async isTargetNumber<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<boolean> {\n const target = await this.get(key);\n return isNumber(target);\n }\n /**\n * Lấy danh sách các key của object trong database.\n *\n * Nếu không truyền `key` → trả về các key cấp cao nhất của database.\n *\n * @typeParam P - Path của object.\n *\n * @param key - Path của object cần lấy danh sách key.\n *\n * @returns Mảng các key tồn tại (không bao gồm `null` hoặc `undefined`).\n *\n * @example\n * const rootKeys = await db.keys();\n * const userKeys = await db.keys(\"user\");\n */\n public async keys<P extends AutocompletableString<ObjectPath<V>>>(key?: P): Promise<ObjectPath<P>[]> {\n if (!key) return TypedObject.keys(await this.all()) as ObjectPath<P>[];\n const data = await this.get(key) as Record<string, any>;\n return TypedObject.keys(data).filter((key) => data[key] !== undefined && data[key] !== null) as any\n }\n /**\n * Lấy số lượng key cấp cao nhất trong database.\n *\n * @returns Tổng số key ở root level.\n *\n * @example\n * const count = await db.size();\n */\n public async size(): Promise<number> {\n const keys = await this.keys();\n return keys.length;\n }\n /**\n * Lấy danh sách các giá trị từ database.\n *\n * Nếu không truyền `key` → trả về toàn bộ values ở root level.\n * Nếu truyền `key` → trả về values của object tại path đó.\n *\n * @typeParam P - Path của object trong database.\n *\n * @param key - Đường dẫn object cần lấy values.\n *\n * @returns Mảng các giá trị.\n *\n * @example\n * const allValues = await db.values();\n *\n * const userValues = await db.values(\"users\");\n */\n public async values<P extends AutocompletableString<ObjectPath<V>>>(key?: P): Promise<ObjectValue<V, P>[]> {\n if (!key) return TypedObject.values(await this.all());\n const data = await this.get(key) as Record<string, any>;\n return TypedObject.values(data) as ObjectValue<V, P>[];\n }\n /**\n * Lấy ngẫu nhiên một phần tử từ array tại path được chỉ định.\n *\n * @typeParam P - Path trỏ đến array trong database.\n *\n * @param key - Đường dẫn đến array.\n *\n * @returns Một phần tử ngẫu nhiên trong array hoặc `null` nếu array rỗng.\n *\n * @throws BlackCatError\n * - INVALID_TARGET nếu giá trị tại key không phải array\n *\n * @example\n * const randomUser = await db.random(\"users\");\n */\n public async random<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>): Promise<Maybe<ObjectValue<V, P>>> {\n const array = await this.get(key);\n if (!Array.isArray(array)) {\n throw new BlackCatError(\"INVALID_TARGET\", \"array\", typeOf(array));\n }\n return array[Math.floor(Math.random() * array.length)] ?? null;\n }\n /**\n * Tìm phần tử đầu tiên thỏa điều kiện.\n *\n * Hoạt động tương tự `Array.prototype.find`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Phần tử đầu tiên thỏa điều kiện hoặc `null` nếu không tìm thấy.\n *\n * @example\n * const user = await db.find(u => u.id === 1);\n */\n public async find(queryFunction: QueryFunction<V>): Promise<Maybe<V>> {\n const values = await this.values();\n return values.find(queryFunction as QueryFunction<ObjectValue<V, any>>) as Promise<Maybe<V>> ?? null;\n }\n /**\n * Biến đổi tất cả giá trị trong database thành một mảng mới.\n *\n * Hoạt động giống `Array.prototype.map`.\n *\n * @typeParam TReturnType - Kiểu dữ liệu của phần tử trả về.\n *\n * @param queryFunction - Hàm transform từng phần tử.\n *\n * @returns Mảng kết quả sau khi transform.\n *\n * @example\n * const names = await db.map(user => user.name);\n */\n public async map<TReturnType>(queryFunction: QueryFunction<V, TReturnType>): Promise<TReturnType[]> {\n const values = await this.values();\n return values.map(queryFunction as QueryFunction<ObjectValue<V, any>, TReturnType>);\n }\n /**\n * Tìm index của phần tử đầu tiên thỏa điều kiện.\n *\n * Hoạt động giống `Array.prototype.findIndex`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Index của phần tử hoặc `-1` nếu không tìm thấy.\n *\n * @example\n * const index = await db.findIndex(user => user.id === 1);\n */\n public async findIndex(queryFunction: QueryFunction<V>): Promise<number> {\n const values = await this.values();\n return values.findIndex(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n /**\n * Lọc các phần tử thỏa điều kiện.\n *\n * Hoạt động giống `Array.prototype.filter`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns Mảng các phần tử thỏa điều kiện.\n *\n * @example\n * const admins = await db.filter(user => user.role === \"admin\");\n */\n public async filter(queryFunction: QueryFunction<V>): Promise<V[]> {\n const values = await this.values();\n return values.filter(queryFunction as QueryFunction<ObjectValue<V, any>>) as any;\n }\n /**\n * Kiểm tra có ít nhất một phần tử thỏa điều kiện hay không.\n *\n * Hoạt động giống `Array.prototype.some`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns `true` nếu tồn tại phần tử thỏa điều kiện.\n *\n * @example\n * const hasAdmin = await db.some(user => user.role === \"admin\");\n */\n public async some(queryFunction: QueryFunction<V>): Promise<boolean> {\n const values = await this.values();\n return values.some(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n /**\n * Kiểm tra tất cả phần tử có thỏa điều kiện hay không.\n *\n * Hoạt động giống `Array.prototype.every`.\n *\n * @param queryFunction - Hàm kiểm tra điều kiện.\n *\n * @returns `true` nếu tất cả phần tử đều thỏa điều kiện.\n *\n * @example\n * const allActive = await db.every(user => user.active === true);\n */\n public async every(queryFunction: QueryFunction<V>): Promise<boolean> {\n const values = await this.values();\n return values.every(queryFunction as QueryFunction<ObjectValue<V, any>>);\n }\n}","import { promises as fs } from \"fs\";\nimport { DatabaseDriver } from \"../types\";\n\n/**\n * Cấu hình khởi tạo cho {@link JSONDriver}.\n */\ninterface JSONDriverOptions {\n /**\n * Đường dẫn tới file JSON dùng làm database.\n *\n * Ví dụ:\n * ```ts\n * \"./database.json\"\n * \"./data/users.json\"\n * ```\n */\n filePath: string;\n /**\n * Nếu bật, nội dung JSON sẽ được **minify**\n * (không format khoảng trắng) để giảm dung lượng file.\n *\n * Nếu tắt, JSON sẽ được format với indentation để dễ đọc.\n *\n * @default false\n */\n minifyJSON?: boolean;\n}\n\n/**\n * Driver lưu trữ dữ liệu dạng JSON.\n *\n * ⚠️ Đây **không phải database hoàn chỉnh**.\n * Class này chỉ đóng vai trò **driver lưu trữ (storage layer)**\n * cho class chính `Database`.\n *\n * Toàn bộ logic xử lý key path (`a.b.c`), validate dữ liệu,\n * và các thao tác database sẽ được thực hiện trong class `Database`.\n *\n * `JSONDriver` chỉ chịu trách nhiệm:\n *\n * - Đọc dữ liệu từ file JSON\n * - Ghi dữ liệu xuống file JSON\n * \n * @example \n * ```ts\n * const database = new Database({\n * driber: new JSONDriver({\\\n * filePath: \"./database.json\",\n * minifyJSON: false\n * })\n * });\n * ```\n */\nexport class JSONDriver implements DatabaseDriver {\n /**\n * Đường dẫn tới file database JSON.\n */\n private filePath: string;\n /**\n * Cho biết có minify JSON khi ghi file hay không.\n */\n public minifyJSON: boolean;\n /**\n * Khởi tạo một instance mới của {@link JSONDriver}.\n *\n * @param options - Cấu hình driver\n *\n * @param options.filePath\n * Đường dẫn tới file JSON dùng làm database.\n *\n * @param options.minifyJSON\n * Nếu `true`, nội dung JSON sẽ được minify khi ghi ra file để giảm dung lượng.\n *\n * @example\n * ```ts\n * const database = new Database({\n * driver: db = new JSONDriver({\n * filePath: \"./database.json\"\n * })\n * });\n * ```\n */\n constructor(options: JSONDriverOptions) {\n this.filePath = options.filePath || \"database.json\";\n this.minifyJSON = options.minifyJSON || false;\n\n }\n /**\n * Đảm bảo file database tồn tại.\n * Nếu file chưa tồn tại sẽ tự động tạo file `{}`.\n */\n private async ensureFile(): Promise<void> {\n try {\n await fs.access(this.filePath);\n } catch {\n await fs.writeFile(this.filePath, \"{}\");\n }\n }\n /**\n * Đọc toàn bộ dữ liệu từ file database JSON.\n *\n * Nếu file không tồn tại hoặc lỗi parse,\n * method sẽ trả về object rỗng.\n *\n * @template V Kiểu dữ liệu database.\n * @returns Promise chứa toàn bộ dữ liệu database.\n */\n public async all<V>(): Promise<V> {\n await this.ensureFile();\n return fs.readFile(this.filePath, \"utf-8\").then((content) => JSON.parse(content) as V).catch((error) => {\n console.error(`Không thể đọc file database: ${this.filePath}`, error);\n return {} as V;\n });\n }\n /**\n * Ghi toàn bộ dữ liệu database xuống file JSON.\n *\n * Method này **không xử lý key path**.\n * Logic cập nhật dữ liệu sẽ được xử lý ở class `Database`\n * trước khi truyền object hoàn chỉnh vào đây.\n *\n * @param data Toàn bộ dữ liệu database sau khi đã được cập nhật.\n *\n * @template R Kiểu dữ liệu database.\n * @returns Promise chứa dữ liệu đã ghi.\n */\n public async set<R = any>(data: R): Promise<R> {\n await this.ensureFile();\n await fs.writeFile(this.filePath, JSON.stringify(data, null, this.minifyJSON ? undefined : \"\\t\"));\n return data;\n }\n /**\n * Xóa toàn bộ database.\n *\n * Method này chỉ reset file JSON về `{}`.\n *\n * @returns `true` nếu reset thành công.\n */\n public async delete(): Promise<boolean> {\n await this.ensureFile();\n await fs.writeFile(this.filePath, \"{}\");\n return true;\n }\n}","import { DatabaseDriver } from \"../types\";\n\n/**\n * Driver lưu trữ dữ liệu trong RAM.\n *\n * ⚠️ Đây **không phải database chính**.\n * Class này chỉ là **storage driver phụ trợ** cho class `Database`.\n *\n * Toàn bộ logic xử lý:\n * - key path (`a.b.c`)\n * - validation\n * - update dữ liệu\n *\n * đều được thực hiện trong class `Database`.\n *\n * `MemoryDriver` chỉ chịu trách nhiệm:\n * - lưu trữ object database trong RAM\n * - trả về toàn bộ dữ liệu\n *\n * Dữ liệu sẽ **mất khi ứng dụng restart**.\n *\n * Phù hợp cho:\n * - testing\n * - cache runtime\n * - development\n * \n * @example\n * ```ts\n * const database = new Database({\n * driver: new MemoryDriver({\n * users: {},\n * guilds: {},\n * settings: {\n * prefix: \"!\"\n * }\n * })\n * });\n * ```\n * \n * hoặc \n * \n * ```ts\n * const database = new Database({\n * driver: new MemoryDriver()\n * });\n * ```\n */\nexport class MemoryDriver implements DatabaseDriver {\n /**\n * Object chứa toàn bộ dữ liệu database trong RAM.\n */\n private store: Record<string, any>;\n /**\n * Khởi tạo MemoryDriver.\n *\n * @param initialData Dữ liệu khởi tạo ban đầu.\n * * @example\n * ```ts\n * const database = new Database({\n * driver: new MemoryDriver({\n * users: {},\n * guilds: {},\n * settings: {\n * prefix: \"!\"\n * }\n * })\n * });\n * ```\n * \n * hoặc \n * \n * ```ts\n * const database = new Database({\n * driver: new MemoryDriver()\n * });\n * ```\n */\n constructor(initialData: Record<string, any> = {}) {\n this.store = initialData;\n }\n /**\n * Trả về toàn bộ dữ liệu database.\n *\n * @template T Kiểu dữ liệu database.\n */\n public async all<T = any>(): Promise<T> {\n return this.store as T;\n }\n /**\n * Ghi toàn bộ database vào memory.\n *\n * ⚠️ Method này **không xử lý key-path**.\n * Dữ liệu đã được xử lý trước bởi `Database`.\n *\n * @param data Toàn bộ database object\n */\n public async set<T = any>(data: T): Promise<T> {\n this.store = data as any;\n return data;\n }\n /**\n * Xóa toàn bộ dữ liệu database trong memory.\n */\n public async delete(): Promise<boolean> {\n this.store = {};\n return true;\n }\n}","import SQLite from \"better-sqlite3\";\nimport { DatabaseDriver } from \"../types\";\n\n/**\n * Các tùy chọn cấu hình cho SQLiteDriver.\n * @hidden\n *\n * Interface này định nghĩa các thiết lập được sử dụng khi\n * khởi tạo driver SQLite cho hệ thống database.\n */\ninterface SQLiteDriverOptions {\n /**\n * Đường dẫn đến file cơ sở dữ liệu SQLite.\n *\n * Nếu không được cung cấp, driver có thể tạo\n * một file database mặc định tùy theo cách triển khai.\n *\n * Ví dụ:\n * `\"./database.sqlite\"`\n */\n filePath?: string;\n /**\n * Tên bảng được sử dụng để lưu trữ dữ liệu key-value.\n *\n * Nếu không được chỉ định, driver có thể sử dụng\n * một tên bảng mặc định (ví dụ: `\"data\"`).\n *\n * Ví dụ:\n * `\"storage\"`\n */\n table?: string;\n}\n/**\n * Driver lưu trữ dữ liệu bằng SQLite.\n *\n * ⚠️ Đây **không phải database chính**.\n * Class này chỉ là **driver lưu trữ phụ trợ** cho `Database`.\n *\n * Logic xử lý dữ liệu như:\n * - parse key path\n * - update object\n * - validation\n *\n * sẽ được thực hiện bởi class `Database`.\n *\n * Driver này chỉ:\n * - serialize database thành JSON\n * - lưu JSON vào SQLite\n * - trả về JSON khi đọc\n *\n * Toàn bộ database được lưu trong **một row duy nhất**.\n * \n * @example\n * ```ts\n * const database = new Database({\n * driver: new SQLiteDriver({\n * filePath: \"database.sqlite\",\n * table: \"json_store\"\n * })\n * })\n * ```\n */\nexport class SQLiteDriver implements DatabaseDriver {\n /**\n * SQLite database instance.\n */\n private db: SQLite.Database;\n /**\n * Tên table lưu trữ dữ liệu JSON.\n */\n private table: string;\n /**\n * Khởi tạo SQLiteDriver.\n *\n * @param filePath Đường dẫn file SQLite\n * @param table Tên table lưu JSON database\n * @example\n * ```ts\n * const database = new Database({\n * driver: new SQLiteDriver({\n * filePath: \"database.sqlite\",\n * table: \"json_store\"\n * })\n * })\n * ```\n */\n constructor(options: SQLiteDriverOptions = {}) {\n this.db = new SQLite(options.filePath ?? \"database.sqlite\");\n this.table = options.table ?? \"json_store\";\n this.db.prepare(`CREATE TABLE IF NOT EXISTS ${this.table} (id INTEGER PRIMARY KEY, data TEXT)`).run();\n const row = this.db.prepare(`SELECT * FROM ${this.table} WHERE id = 1`).get();\n if (!row) {\n this.db.prepare(`INSERT INTO ${this.table} (id, data) VALUES (1, '{}')`).run();\n }\n }\n /**\n * Lấy toàn bộ dữ liệu database từ SQLite.\n *\n * @template T Kiểu dữ liệu database.\n */\n public async all<T = any>(): Promise<T> {\n const row = this.db.prepare(`SELECT data FROM ${this.table} WHERE id = 1`).get() as { data: string };\n return JSON.parse(row.data) as T;\n }\n /**\n * Ghi toàn bộ database vào SQLite.\n *\n * ⚠️ Method này **không xử lý key-path**.\n * `Database` đã cập nhật object trước khi truyền vào đây.\n *\n * @param data Toàn bộ database object\n */\n public async set<T = any>(data: T): Promise<T> {\n this.db.prepare(`UPDATE ${this.table} SET data = ? WHERE id = 1`).run(JSON.stringify(data));\n return data;\n }\n /**\n * Reset toàn bộ database.\n */\n public async delete(): Promise<boolean> {\n this.db.prepare(`UPDATE ${this.table} SET data = '{}' WHERE id = 1`).run();\n return true;\n }\n}","import { MongoClient, Db, Collection } from \"mongodb\";\nimport type { DatabaseDriver } from \"../types\";\n\n/**\n * Cấu hình cho MongoDriver.\n */\ninterface MongoDriverOptions {\n /**\n * Chuỗi kết nối MongoDB.\n *\n * @default \"mongodb://localhost:27017\"\n */\n mongourl?: string;\n /**\n * Tên database MongoDB.\n *\n * @default \"database\"\n */\n databaseName?: string;\n /**\n * Tên collection lưu dữ liệu JSON.\n *\n * @default \"json_store\"\n */\n collectionName?: string;\n}\n/**\n * Schema document dùng để lưu trữ database trong MongoDB.\n */\ninterface DatabaseDocument<V = any> {\n _id: string;\n data: V;\n}\n/**\n * Driver lưu trữ dữ liệu bằng MongoDB.\n *\n * ⚠️ Đây **không phải database chính**.\n * Class này chỉ là **driver lưu trữ phụ trợ** cho class `Database`.\n *\n * Logic xử lý:\n * - parse key path\n * - validate dữ liệu\n * - cập nhật object\n *\n * sẽ được xử lý bởi class `Database`.\n *\n * `MongoDriver` chỉ chịu trách nhiệm:\n * - lưu toàn bộ database object\n * - trả về database object\n *\n * Toàn bộ database được lưu trong **một document duy nhất**.\n * \n * @example \n * ```ts\n * const database = new Database({ \n * driver: new MongoDriver({\n * mongourl: \"mongodb://localhost:27017\", \n * databaseName: \"mydb\", \n * collectionName: \"store\" \n * })\n * });\n * ```\n */\nexport class MongoDriver implements DatabaseDriver {\n /**\n * MongoDB client instance.\n */\n private client: MongoClient;\n /**\n * MongoDB database instance.\n */\n private db!: Db;\n /**\n * Collection lưu dữ liệu JSON.\n */\n private collection!: Collection<DatabaseDocument>;\n /**\n * Tên database MongoDB.\n */\n private databaseName: string;\n /**\n * Tên collection MongoDB.\n */\n private collectionName: string;\n /**\n * Khởi tạo MongoDriver.\n *\n * @param options Cấu hình MongoDB driver.\n * \n * @example \n * ```ts\n * const database = new Database({ \n * driver: new MongoDriver({\n * mongourl: \"mongodb://localhost:27017\", \n * databaseName: \"mydb\", \n * collectionName: \"store\" \n * })\n * });\n */\n constructor(options: MongoDriverOptions = {}) {\n const {\n mongourl = \"mongodb://localhost:27017\",\n databaseName = \"database\",\n collectionName = \"json_store\"\n } = options;\n this.client = new MongoClient(mongourl);\n this.databaseName = databaseName;\n this.collectionName = collectionName;\n }\n /**\n * Thiết lập kết nối MongoDB nếu chưa kết nối.\n */\n private async connect(): Promise<void> {\n if (!this.db) {\n await this.client.connect();\n this.db = this.client.db(this.databaseName);\n this.collection = this.db.collection(this.collectionName);\n const doc = await this.collection.findOne({ _id: \"database\" });\n if (!doc) {\n await this.collection.insertOne({\n _id: \"database\",\n data: {}\n });\n }\n }\n }\n /**\n * Lấy toàn bộ dữ liệu database từ MongoDB.\n */\n public async all<T = any>(): Promise<T> {\n await this.connect();\n const doc = await this.collection.findOne({ _id: \"database\" });\n return (doc?.data ?? {}) as T;\n }\n /**\n * Ghi toàn bộ database vào MongoDB.\n *\n * ⚠️ Method này **không xử lý key-path**.\n * Object database đã được xử lý bởi class `Database`.\n * \n * @param data Toàn bộ object database\n */\n public async set<T = any>(data: T): Promise<T> {\n await this.connect();\n await this.collection.updateOne(\n { _id: \"database\" },\n { $set: { data } }\n );\n return data;\n }\n /**\n * Reset toàn bộ database về object rỗng.\n */\n public async delete(): Promise<boolean> {\n await this.connect();\n await this.collection.updateOne(\n { _id: \"database\" },\n { $set: { data: {} } }\n );\n return true;\n }\n}"],"mappings":"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","names":["key"]}
|