blackcat.js-database 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -4,12 +4,16 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
 
6
6
  // src/utils/isObject.function.ts
7
- var isObject = /* @__PURE__ */ __name((item) => !Array.isArray(item) && item !== null && typeof item == "object", "isObject");
7
+ var isObject = /* @__PURE__ */ __name((item) => !Array.isArray(item) && item !== null && typeof item === "object", "isObject");
8
8
 
9
9
  // src/utils/typeOf.function.ts
10
10
  var typeOf = /* @__PURE__ */ __name((input) => {
11
- if (input == null || typeof input === "number" && Number.isNaN(input)) return String(input);
12
- if (typeof input === "function" && input.prototype) return `${input.name} class instance`;
11
+ if (input == null || typeof input === "number" && Number.isNaN(input)) {
12
+ return String(input);
13
+ }
14
+ if (typeof input === "function" && input.prototype) {
15
+ return `${input.name} class instance`;
16
+ }
13
17
  return input?.constructor?.name ?? typeof input;
14
18
  }, "typeOf");
15
19
 
@@ -18,20 +22,12 @@ var isNumber = /* @__PURE__ */ __name((input) => !isNaN(input) && input !== "" &
18
22
 
19
23
  // src/utils/BlackCatError.ts
20
24
  var errors = {
21
- 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.",
22
- 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.",
23
- CONNECTION_URI_NOT_SPECIFIED: "The MongoDB connection URI must be specified.",
24
- INVALID_CONNECTION_URI: "The specified MongoDB connection URI is invalid.",
25
- UNKNOWN_ERROR: "Unknown error.",
26
- REQUIRED_PARAMETER_MISSING: "'{1}' parameter is required but is missing.",
27
- REQUIRED_CONSTRUCTOR_PARAMETER_MISSING: "'{1}' parameter in constructor '{2}' is required but is missing.",
28
- INVALID_CONSTRUCTOR_PARAMETER_TYPE: "'{1}' parameter in constructor '{2}' must be a type of {3}. Received type: {4}.",
29
- INVALID_TYPE: "'{1}' must be a type of {2}. Received type: {3}.",
30
- 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}.",
31
- INVALID_TARGET: "The target in database must be a type of {1}. Received target type: {2}.",
32
- INVALID_KEY: "{1}",
33
- INVALID_PARAMETER: "{1} {2}",
34
- DATABASE_CONNECTION_FAILED: "{1}"
25
+ UNKNOWN_ERROR: "L\u1ED7i kh\xF4ng x\xE1c \u0111\u1ECBnh.",
26
+ REQUIRED_PARAMETER_MISSING: "Tham s\u1ED1 '{1}' l\xE0 b\u1EAFt bu\u1ED9c nh\u01B0ng ch\u01B0a \u0111\u01B0\u1EE3c cung c\u1EA5p.",
27
+ INVALID_TYPE: "'{1}' ph\u1EA3i c\xF3 ki\u1EC3u {2}. Ki\u1EC3u nh\u1EADn \u0111\u01B0\u1EE3c: {3}.",
28
+ ONE_OR_MORE_ARRAY_TYPES_INVALID: "T\u1EA5t c\u1EA3 ph\u1EA7n t\u1EED trong m\u1EA3ng c\u1EE7a tham s\u1ED1 '{1}' ph\u1EA3i c\xF3 ki\u1EC3u {2}. C\xE1c ki\u1EC3u nh\u1EADn \u0111\u01B0\u1EE3c trong m\u1EA3ng: {3}.",
29
+ INVALID_TARGET: "\u0110\u1ED1i t\u01B0\u1EE3ng target trong database ph\u1EA3i c\xF3 ki\u1EC3u {1}. Ki\u1EC3u nh\u1EADn \u0111\u01B0\u1EE3c: {2}.",
30
+ INVALID_KEY: "{1}"
35
31
  };
36
32
  var createTypesArray = /* @__PURE__ */ __name((...elements) => `[${elements.map((element) => typeOf(element))}]`, "createTypesArray");
37
33
  var _BlackCatError = class _BlackCatError extends Error {
@@ -57,46 +53,107 @@ var BlackCatError = _BlackCatError;
57
53
  // src/utils/TypedObject.ts
58
54
  var _TypedObject = class _TypedObject {
59
55
  /**
60
- * Returns the names of the enumerable string properties and methods of an object.
56
+ * Lấy danh sách key của object với type chính xác.
57
+ *
58
+ * @typeParam TObject - Kiểu object đầu vào
59
+ *
60
+ * @param obj - Object cần lấy key
61
+ * @returns Mảng các key của object (`ExtractObjectKeys<TObject>[]`)
62
+ *
63
+ * @remarks
64
+ * Khác với `Object.keys`:
65
+ * - `Object.keys(obj)` → `string[]`
66
+ * - `TypedObject.keys(obj)` → union key chính xác
61
67
  *
62
- * Type parameters:
68
+ * ---
63
69
  *
64
- * - `TObject` (`Record<string, any>`) - The object to get the object keys types from.
70
+ * ### Lưu ý:
71
+ * - Nếu `obj` là `null` hoặc `undefined`, sẽ fallback thành `{}` → trả về `[]`
65
72
  *
66
- * @param {TObject} obj Object to get the keys from.
73
+ * ---
67
74
  *
68
- * @returns {Array<ExtractObjectKeys<TObject>>}
69
- * Array of names of the enumerable string properties and methods of the specified object.
75
+ * @example
76
+ * ```ts
77
+ * const obj = { a: 1, b: 2 };
78
+ *
79
+ * const keys = TypedObject.keys(obj);
80
+ * // ("a" | "b")[]
81
+ * ```
82
+ *
83
+ * @see Object.keys
70
84
  */
71
85
  static keys(obj) {
72
86
  return Object.keys(obj || {});
73
87
  }
74
88
  /**
75
- * Returns an array of values of the enumerable properties of an object.
89
+ * Lấy danh sách value của object với type chính xác.
90
+ *
91
+ * @typeParam TObject - Kiểu object đầu vào
92
+ *
93
+ * @param obj - Object cần lấy value
94
+ * @returns Mảng các value của object (`ExtractObjectValues<TObject>[]`)
95
+ *
96
+ * @remarks
97
+ * Khác với `Object.values`:
98
+ * - `Object.values(obj)` → `any[]`
99
+ * - `TypedObject.values(obj)` → union value chính xác
76
100
  *
77
- * Type parameters:
101
+ * ---
78
102
  *
79
- * - `TObject` (`Record<string, any>`) - The object to get the object values types from.
103
+ * ### Lưu ý:
104
+ * - Nếu `obj` là `null` hoặc `undefined`, sẽ fallback thành `{}` → trả về `[]`
105
+ *
106
+ * ---
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * const obj = { a: 1, b: 2 };
80
111
  *
81
- * @param {TObject} obj Object to get the values from.
112
+ * const values = TypedObject.values(obj);
113
+ * // number[]
114
+ * ```
82
115
  *
83
- * @returns {Array<ExtractObjectValues<TObject>>}
84
- * Array of values of the enumerable properties of the specified object.
116
+ * @see Object.values
85
117
  */
86
118
  static values(obj) {
87
119
  return Object.values(obj || {});
88
120
  }
89
121
  /**
90
- * Returns an array of entries (key-value pairs) of the enumerable properties of an object.
122
+ * Lấy danh sách entry (key-value) của object với type chính xác.
123
+ *
124
+ * @typeParam TObject - Kiểu object đầu vào
125
+ *
126
+ * @param obj - Object cần lấy entries
127
+ * @returns Mảng các cặp `[key, value]` (`ExtractObjectEntries<TObject>[]`)
128
+ *
129
+ * @remarks
130
+ * Khác với `Object.entries`:
131
+ * - `Object.entries(obj)` → `[string, any][]`
132
+ * - `TypedObject.entries(obj)` → typed tuple chính xác
133
+ *
134
+ * ---
91
135
  *
92
- * Type parameters:
136
+ * ### Lưu ý:
137
+ * - Nếu `obj` là `null` hoặc `undefined`, sẽ fallback thành `{}` → trả về `[]`
93
138
  *
94
- * - `TObject` (`Record<string, any>`) - The object to get the object entries types (key-value pairs types) from.
139
+ * ---
95
140
  *
96
- * @param {TObject} obj Object to get the entries from.
141
+ * @example
142
+ * ```ts
143
+ * const obj = { a: 1, b: 2 };
144
+ *
145
+ * const entries = TypedObject.entries(obj);
146
+ * // ["a" | "b", number][]
147
+ * ```
97
148
  *
98
- * @returns {ExtractObjectEntries<TObject>[]}
99
- * Array of entries (key-value pairs) of the enumerable properties of the specified object.
149
+ * @example
150
+ * ```ts
151
+ * for (const [key, value] of TypedObject.entries(obj)) {
152
+ * // key & value được infer đúng type
153
+ * }
154
+ * ```
155
+ *
156
+ * @see Object.entries
100
157
  */
101
158
  static entries(obj) {
102
159
  return Object.entries(obj || {});
@@ -105,9 +162,6 @@ var _TypedObject = class _TypedObject {
105
162
  __name(_TypedObject, "TypedObject");
106
163
  var TypedObject = _TypedObject;
107
164
 
108
- // src/utils/Emitter.ts
109
- import { EventEmitter } from "events";
110
-
111
165
  // src/Database.ts
112
166
  var _Database = class _Database {
113
167
  /**
@@ -428,41 +482,86 @@ var _Database = class _Database {
428
482
  return originalLength - filtered.length;
429
483
  }
430
484
  /**
431
- * Cập nhật giá trị của một key-path trong database.
485
+ * Cập nhật dữ liệu trong database theo đường dẫn key.
432
486
  *
433
- * Khác với `set()`, method này chỉ ghi đè giá trị của key cuối cùng
434
- * trong path không thay đổi cấu trúc object phía trên.
487
+ * Hàm này sẽ tìm đến vị trí của `key` trong database và gán `value` vào đó.
488
+ * Nếu `value` giá trị hiện tại tại key đều là object thì sẽ thực hiện
489
+ * **shallow merge** thay vì ghi đè toàn bộ object.
435
490
  *
436
- * Nếu các object trung gian trong path chưa tồn tại
437
- * thì chúng sẽ được tự động tạo.
491
+ * Đ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
492
  *
439
- * @template P Key path trong database.
493
+ * @template P - Đường dẫn key hợp lệ trong object database.
440
494
  *
441
- * @param key Đường dẫn dữ liệu cần cập nhật.
442
- * @param value Giá trị mới.
495
+ * @param key - Đường dẫn tới giá trị cần cập nhật.
496
+ * Hỗ trợ nested path dạng `"a.b.c"`.
443
497
  *
444
- * @returns Object cha của key vừa cập nhật.
498
+ * @param value - Giá trị mới sẽ được cập nhật tại key.
499
+ *
500
+ * @returns
501
+ * Trả về giá trị cuối cùng sau khi cập nhật.
445
502
  *
446
503
  * @example
504
+ * Database ban đầu:
505
+ * ```json
506
+ * {
507
+ * "123": {
508
+ * "guildID": "123",
509
+ * "guildName": "BlackCat",
510
+ * "history": []
511
+ * }
512
+ * }
513
+ * ```
514
+ *
515
+ * Cập nhật:
447
516
  * ```ts
448
- * await db.update("users.123.name", "Alice");
517
+ * await db.update("123", {
518
+ * history: [1,2,3]
519
+ * });
449
520
  * ```
521
+ *
522
+ * Kết quả:
523
+ * ```json
524
+ * {
525
+ * "123": {
526
+ * "guildID": "123",
527
+ * "guildName": "BlackCat",
528
+ * "history": [1,2,3]
529
+ * }
530
+ * }
531
+ * ```
532
+ *
533
+ * @throws {BlackCatError}
534
+ * - `REQUIRED_PARAMETER_MISSING` nếu key không được cung cấp
535
+ * - `INVALID_TYPE` nếu key không phải string
450
536
  */
451
537
  async update(key, value) {
538
+ if (!key) {
539
+ throw new BlackCatError("REQUIRED_PARAMETER_MISSING", "key");
540
+ }
541
+ if (typeof key !== "string") {
542
+ throw new BlackCatError("INVALID_TYPE", "key", "string", typeOf(key));
543
+ }
452
544
  const allDatabase = await this.all();
453
545
  const keys = key.split(".");
454
546
  let current = allDatabase;
455
547
  for (let i = 0; i < keys.length - 1; i++) {
456
548
  const part = keys[i];
457
- if (!(part in current)) {
549
+ if (!isObject(current[part])) {
458
550
  current[part] = {};
459
551
  }
460
552
  current = current[part];
461
553
  }
462
554
  const lastKey = keys[keys.length - 1];
463
- current[lastKey] = value;
555
+ if (isObject(value) && isObject(current[lastKey])) {
556
+ current[lastKey] = {
557
+ ...current[lastKey],
558
+ ...value
559
+ };
560
+ } else {
561
+ current[lastKey] = value;
562
+ }
464
563
  await this.driver.set(allDatabase);
465
- return current;
564
+ return current[lastKey];
466
565
  }
467
566
  /**
468
567
  * Cộng thêm giá trị vào một key dạng number.
@@ -1139,11 +1238,21 @@ var _MongoDriver = class _MongoDriver {
1139
1238
  *
1140
1239
  * @example
1141
1240
  * ```ts
1241
+ * import { Database, MongoDriver } from "blackcat.js-database";
1242
+ *
1142
1243
  * const database = new Database({
1143
1244
  * driver: new MongoDriver({
1144
1245
  * mongourl: "mongodb://localhost:27017",
1145
1246
  * databaseName: "mydb",
1146
- * collectionName: "store"
1247
+ * collectionName: "store",
1248
+ * onLoad: ({ db, collection, databaseName }) => {
1249
+ * console.log(`✅ Đã kết nối với cơ sở dữ liệu: ${databaseName}`);
1250
+ * console.log(`📦 Bộ sưu tập: ${collection.collectionName}`);
1251
+ * },
1252
+ * onError: ({ error, databaseName }) => {
1253
+ * console.error(`❌ Không thể kết nối với cơ sở dữ liệu: ${databaseName}`);
1254
+ * console.error(error);
1255
+ * }
1147
1256
  * })
1148
1257
  * });
1149
1258
  */
@@ -1168,6 +1277,18 @@ var _MongoDriver = class _MongoDriver {
1168
1277
  * Tên collection MongoDB.
1169
1278
  */
1170
1279
  __publicField(this, "collectionName");
1280
+ /**
1281
+ * Callback khi kết nối thành công.
1282
+ */
1283
+ __publicField(this, "onLoad");
1284
+ /**
1285
+ * Callback khi xảy ra lỗi.
1286
+ */
1287
+ __publicField(this, "onError");
1288
+ /**
1289
+ * Trạng thái đã gọi onLoad chưa (tránh spam)
1290
+ */
1291
+ __publicField(this, "isLoaded", false);
1171
1292
  const {
1172
1293
  mongourl = "mongodb://localhost:27017",
1173
1294
  databaseName = "database",
@@ -1176,21 +1297,42 @@ var _MongoDriver = class _MongoDriver {
1176
1297
  this.client = new MongoClient(mongourl);
1177
1298
  this.databaseName = databaseName;
1178
1299
  this.collectionName = collectionName;
1300
+ this.onLoad = options.onLoad;
1301
+ this.onError = options.onError;
1179
1302
  }
1180
1303
  /**
1181
1304
  * Thiết lập kết nối MongoDB nếu chưa kết nối.
1182
1305
  */
1183
1306
  async connect() {
1184
1307
  if (!this.db) {
1185
- await this.client.connect();
1186
- this.db = this.client.db(this.databaseName);
1187
- this.collection = this.db.collection(this.collectionName);
1188
- const doc = await this.collection.findOne({ _id: "database" });
1189
- if (!doc) {
1190
- await this.collection.insertOne({
1191
- _id: "database",
1192
- data: {}
1308
+ try {
1309
+ await this.client.connect();
1310
+ this.db = this.client.db(this.databaseName);
1311
+ this.collection = this.db.collection(this.collectionName);
1312
+ const doc = await this.collection.findOne({ _id: "database" });
1313
+ if (!doc) {
1314
+ await this.collection.insertOne({
1315
+ _id: "database",
1316
+ data: {}
1317
+ });
1318
+ }
1319
+ if (!this.isLoaded) {
1320
+ this.isLoaded = true;
1321
+ this.onLoad?.({
1322
+ client: this.client,
1323
+ db: this.db,
1324
+ collection: this.collection,
1325
+ databaseName: this.databaseName,
1326
+ collectionName: this.collectionName
1327
+ });
1328
+ }
1329
+ } catch (error) {
1330
+ this.onError?.({
1331
+ error,
1332
+ databaseName: this.databaseName,
1333
+ collectionName: this.collectionName
1193
1334
  });
1335
+ throw error;
1194
1336
  }
1195
1337
  }
1196
1338
  }