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.js CHANGED
@@ -42,12 +42,16 @@ __export(index_exports, {
42
42
  module.exports = __toCommonJS(index_exports);
43
43
 
44
44
  // src/utils/isObject.function.ts
45
- var isObject = /* @__PURE__ */ __name((item) => !Array.isArray(item) && item !== null && typeof item == "object", "isObject");
45
+ var isObject = /* @__PURE__ */ __name((item) => !Array.isArray(item) && item !== null && typeof item === "object", "isObject");
46
46
 
47
47
  // src/utils/typeOf.function.ts
48
48
  var typeOf = /* @__PURE__ */ __name((input) => {
49
- if (input == null || typeof input === "number" && Number.isNaN(input)) return String(input);
50
- if (typeof input === "function" && input.prototype) return `${input.name} class instance`;
49
+ if (input == null || typeof input === "number" && Number.isNaN(input)) {
50
+ return String(input);
51
+ }
52
+ if (typeof input === "function" && input.prototype) {
53
+ return `${input.name} class instance`;
54
+ }
51
55
  return input?.constructor?.name ?? typeof input;
52
56
  }, "typeOf");
53
57
 
@@ -56,20 +60,12 @@ var isNumber = /* @__PURE__ */ __name((input) => !isNaN(input) && input !== "" &
56
60
 
57
61
  // src/utils/BlackCatError.ts
58
62
  var errors = {
59
- 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.",
60
- 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.",
61
- CONNECTION_URI_NOT_SPECIFIED: "The MongoDB connection URI must be specified.",
62
- INVALID_CONNECTION_URI: "The specified MongoDB connection URI is invalid.",
63
- UNKNOWN_ERROR: "Unknown error.",
64
- REQUIRED_PARAMETER_MISSING: "'{1}' parameter is required but is missing.",
65
- REQUIRED_CONSTRUCTOR_PARAMETER_MISSING: "'{1}' parameter in constructor '{2}' is required but is missing.",
66
- INVALID_CONSTRUCTOR_PARAMETER_TYPE: "'{1}' parameter in constructor '{2}' must be a type of {3}. Received type: {4}.",
67
- INVALID_TYPE: "'{1}' must be a type of {2}. Received type: {3}.",
68
- 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}.",
69
- INVALID_TARGET: "The target in database must be a type of {1}. Received target type: {2}.",
70
- INVALID_KEY: "{1}",
71
- INVALID_PARAMETER: "{1} {2}",
72
- DATABASE_CONNECTION_FAILED: "{1}"
63
+ UNKNOWN_ERROR: "L\u1ED7i kh\xF4ng x\xE1c \u0111\u1ECBnh.",
64
+ REQUIRED_PARAMETER_MISSING: "Tham s\u1ED1 '{1}' l\xE0 b\u1EAFt bu\u1ED9c nh\u01B0ng ch\u01B0a \u0111\u01B0\u1EE3c cung c\u1EA5p.",
65
+ INVALID_TYPE: "'{1}' ph\u1EA3i c\xF3 ki\u1EC3u {2}. Ki\u1EC3u nh\u1EADn \u0111\u01B0\u1EE3c: {3}.",
66
+ 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}.",
67
+ 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}.",
68
+ INVALID_KEY: "{1}"
73
69
  };
74
70
  var createTypesArray = /* @__PURE__ */ __name((...elements) => `[${elements.map((element) => typeOf(element))}]`, "createTypesArray");
75
71
  var _BlackCatError = class _BlackCatError extends Error {
@@ -95,46 +91,107 @@ var BlackCatError = _BlackCatError;
95
91
  // src/utils/TypedObject.ts
96
92
  var _TypedObject = class _TypedObject {
97
93
  /**
98
- * Returns the names of the enumerable string properties and methods of an object.
94
+ * Lấy danh sách key của object với type chính xác.
95
+ *
96
+ * @typeParam TObject - Kiểu object đầu vào
97
+ *
98
+ * @param obj - Object cần lấy key
99
+ * @returns Mảng các key của object (`ExtractObjectKeys<TObject>[]`)
100
+ *
101
+ * @remarks
102
+ * Khác với `Object.keys`:
103
+ * - `Object.keys(obj)` → `string[]`
104
+ * - `TypedObject.keys(obj)` → union key chính xác
99
105
  *
100
- * Type parameters:
106
+ * ---
101
107
  *
102
- * - `TObject` (`Record<string, any>`) - The object to get the object keys types from.
108
+ * ### Lưu ý:
109
+ * - Nếu `obj` là `null` hoặc `undefined`, sẽ fallback thành `{}` → trả về `[]`
103
110
  *
104
- * @param {TObject} obj Object to get the keys from.
111
+ * ---
105
112
  *
106
- * @returns {Array<ExtractObjectKeys<TObject>>}
107
- * Array of names of the enumerable string properties and methods of the specified object.
113
+ * @example
114
+ * ```ts
115
+ * const obj = { a: 1, b: 2 };
116
+ *
117
+ * const keys = TypedObject.keys(obj);
118
+ * // ("a" | "b")[]
119
+ * ```
120
+ *
121
+ * @see Object.keys
108
122
  */
109
123
  static keys(obj) {
110
124
  return Object.keys(obj || {});
111
125
  }
112
126
  /**
113
- * Returns an array of values of the enumerable properties of an object.
127
+ * Lấy danh sách value của object với type chính xác.
128
+ *
129
+ * @typeParam TObject - Kiểu object đầu vào
130
+ *
131
+ * @param obj - Object cần lấy value
132
+ * @returns Mảng các value của object (`ExtractObjectValues<TObject>[]`)
133
+ *
134
+ * @remarks
135
+ * Khác với `Object.values`:
136
+ * - `Object.values(obj)` → `any[]`
137
+ * - `TypedObject.values(obj)` → union value chính xác
114
138
  *
115
- * Type parameters:
139
+ * ---
116
140
  *
117
- * - `TObject` (`Record<string, any>`) - The object to get the object values types from.
141
+ * ### Lưu ý:
142
+ * - Nếu `obj` là `null` hoặc `undefined`, sẽ fallback thành `{}` → trả về `[]`
143
+ *
144
+ * ---
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * const obj = { a: 1, b: 2 };
118
149
  *
119
- * @param {TObject} obj Object to get the values from.
150
+ * const values = TypedObject.values(obj);
151
+ * // number[]
152
+ * ```
120
153
  *
121
- * @returns {Array<ExtractObjectValues<TObject>>}
122
- * Array of values of the enumerable properties of the specified object.
154
+ * @see Object.values
123
155
  */
124
156
  static values(obj) {
125
157
  return Object.values(obj || {});
126
158
  }
127
159
  /**
128
- * Returns an array of entries (key-value pairs) of the enumerable properties of an object.
160
+ * Lấy danh sách entry (key-value) của object với type chính xác.
161
+ *
162
+ * @typeParam TObject - Kiểu object đầu vào
163
+ *
164
+ * @param obj - Object cần lấy entries
165
+ * @returns Mảng các cặp `[key, value]` (`ExtractObjectEntries<TObject>[]`)
166
+ *
167
+ * @remarks
168
+ * Khác với `Object.entries`:
169
+ * - `Object.entries(obj)` → `[string, any][]`
170
+ * - `TypedObject.entries(obj)` → typed tuple chính xác
171
+ *
172
+ * ---
129
173
  *
130
- * Type parameters:
174
+ * ### Lưu ý:
175
+ * - Nếu `obj` là `null` hoặc `undefined`, sẽ fallback thành `{}` → trả về `[]`
131
176
  *
132
- * - `TObject` (`Record<string, any>`) - The object to get the object entries types (key-value pairs types) from.
177
+ * ---
133
178
  *
134
- * @param {TObject} obj Object to get the entries from.
179
+ * @example
180
+ * ```ts
181
+ * const obj = { a: 1, b: 2 };
182
+ *
183
+ * const entries = TypedObject.entries(obj);
184
+ * // ["a" | "b", number][]
185
+ * ```
135
186
  *
136
- * @returns {ExtractObjectEntries<TObject>[]}
137
- * Array of entries (key-value pairs) of the enumerable properties of the specified object.
187
+ * @example
188
+ * ```ts
189
+ * for (const [key, value] of TypedObject.entries(obj)) {
190
+ * // key & value được infer đúng type
191
+ * }
192
+ * ```
193
+ *
194
+ * @see Object.entries
138
195
  */
139
196
  static entries(obj) {
140
197
  return Object.entries(obj || {});
@@ -143,9 +200,6 @@ var _TypedObject = class _TypedObject {
143
200
  __name(_TypedObject, "TypedObject");
144
201
  var TypedObject = _TypedObject;
145
202
 
146
- // src/utils/Emitter.ts
147
- var import_node_events = require("events");
148
-
149
203
  // src/Database.ts
150
204
  var _Database = class _Database {
151
205
  /**
@@ -466,41 +520,86 @@ var _Database = class _Database {
466
520
  return originalLength - filtered.length;
467
521
  }
468
522
  /**
469
- * Cập nhật giá trị của một key-path trong database.
523
+ * Cập nhật dữ liệu trong database theo đường dẫn key.
470
524
  *
471
- * Khác với `set()`, method này chỉ ghi đè giá trị của key cuối cùng
472
- * trong path không thay đổi cấu trúc object phía trên.
525
+ * Hàm này sẽ tìm đến vị trí của `key` trong database và gán `value` vào đó.
526
+ * Nếu `value` giá trị hiện tại tại key đều là object thì sẽ thực hiện
527
+ * **shallow merge** thay vì ghi đè toàn bộ object.
473
528
  *
474
- * Nếu các object trung gian trong path chưa tồn tại
475
- * thì chúng sẽ được tự động tạo.
529
+ * Đ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
530
  *
477
- * @template P Key path trong database.
531
+ * @template P - Đường dẫn key hợp lệ trong object database.
478
532
  *
479
- * @param key Đường dẫn dữ liệu cần cập nhật.
480
- * @param value Giá trị mới.
533
+ * @param key - Đường dẫn tới giá trị cần cập nhật.
534
+ * Hỗ trợ nested path dạng `"a.b.c"`.
481
535
  *
482
- * @returns Object cha của key vừa cập nhật.
536
+ * @param value - Giá trị mới sẽ được cập nhật tại key.
537
+ *
538
+ * @returns
539
+ * Trả về giá trị cuối cùng sau khi cập nhật.
483
540
  *
484
541
  * @example
542
+ * Database ban đầu:
543
+ * ```json
544
+ * {
545
+ * "123": {
546
+ * "guildID": "123",
547
+ * "guildName": "BlackCat",
548
+ * "history": []
549
+ * }
550
+ * }
551
+ * ```
552
+ *
553
+ * Cập nhật:
485
554
  * ```ts
486
- * await db.update("users.123.name", "Alice");
555
+ * await db.update("123", {
556
+ * history: [1,2,3]
557
+ * });
487
558
  * ```
559
+ *
560
+ * Kết quả:
561
+ * ```json
562
+ * {
563
+ * "123": {
564
+ * "guildID": "123",
565
+ * "guildName": "BlackCat",
566
+ * "history": [1,2,3]
567
+ * }
568
+ * }
569
+ * ```
570
+ *
571
+ * @throws {BlackCatError}
572
+ * - `REQUIRED_PARAMETER_MISSING` nếu key không được cung cấp
573
+ * - `INVALID_TYPE` nếu key không phải string
488
574
  */
489
575
  async update(key, value) {
576
+ if (!key) {
577
+ throw new BlackCatError("REQUIRED_PARAMETER_MISSING", "key");
578
+ }
579
+ if (typeof key !== "string") {
580
+ throw new BlackCatError("INVALID_TYPE", "key", "string", typeOf(key));
581
+ }
490
582
  const allDatabase = await this.all();
491
583
  const keys = key.split(".");
492
584
  let current = allDatabase;
493
585
  for (let i = 0; i < keys.length - 1; i++) {
494
586
  const part = keys[i];
495
- if (!(part in current)) {
587
+ if (!isObject(current[part])) {
496
588
  current[part] = {};
497
589
  }
498
590
  current = current[part];
499
591
  }
500
592
  const lastKey = keys[keys.length - 1];
501
- current[lastKey] = value;
593
+ if (isObject(value) && isObject(current[lastKey])) {
594
+ current[lastKey] = {
595
+ ...current[lastKey],
596
+ ...value
597
+ };
598
+ } else {
599
+ current[lastKey] = value;
600
+ }
502
601
  await this.driver.set(allDatabase);
503
- return current;
602
+ return current[lastKey];
504
603
  }
505
604
  /**
506
605
  * Cộng thêm giá trị vào một key dạng number.
@@ -1177,11 +1276,21 @@ var _MongoDriver = class _MongoDriver {
1177
1276
  *
1178
1277
  * @example
1179
1278
  * ```ts
1279
+ * import { Database, MongoDriver } from "blackcat.js-database";
1280
+ *
1180
1281
  * const database = new Database({
1181
1282
  * driver: new MongoDriver({
1182
1283
  * mongourl: "mongodb://localhost:27017",
1183
1284
  * databaseName: "mydb",
1184
- * collectionName: "store"
1285
+ * collectionName: "store",
1286
+ * onLoad: ({ db, collection, databaseName }) => {
1287
+ * console.log(`✅ Đã kết nối với cơ sở dữ liệu: ${databaseName}`);
1288
+ * console.log(`📦 Bộ sưu tập: ${collection.collectionName}`);
1289
+ * },
1290
+ * onError: ({ error, databaseName }) => {
1291
+ * console.error(`❌ Không thể kết nối với cơ sở dữ liệu: ${databaseName}`);
1292
+ * console.error(error);
1293
+ * }
1185
1294
  * })
1186
1295
  * });
1187
1296
  */
@@ -1206,6 +1315,18 @@ var _MongoDriver = class _MongoDriver {
1206
1315
  * Tên collection MongoDB.
1207
1316
  */
1208
1317
  __publicField(this, "collectionName");
1318
+ /**
1319
+ * Callback khi kết nối thành công.
1320
+ */
1321
+ __publicField(this, "onLoad");
1322
+ /**
1323
+ * Callback khi xảy ra lỗi.
1324
+ */
1325
+ __publicField(this, "onError");
1326
+ /**
1327
+ * Trạng thái đã gọi onLoad chưa (tránh spam)
1328
+ */
1329
+ __publicField(this, "isLoaded", false);
1209
1330
  const {
1210
1331
  mongourl = "mongodb://localhost:27017",
1211
1332
  databaseName = "database",
@@ -1214,21 +1335,42 @@ var _MongoDriver = class _MongoDriver {
1214
1335
  this.client = new import_mongodb.MongoClient(mongourl);
1215
1336
  this.databaseName = databaseName;
1216
1337
  this.collectionName = collectionName;
1338
+ this.onLoad = options.onLoad;
1339
+ this.onError = options.onError;
1217
1340
  }
1218
1341
  /**
1219
1342
  * Thiết lập kết nối MongoDB nếu chưa kết nối.
1220
1343
  */
1221
1344
  async connect() {
1222
1345
  if (!this.db) {
1223
- await this.client.connect();
1224
- this.db = this.client.db(this.databaseName);
1225
- this.collection = this.db.collection(this.collectionName);
1226
- const doc = await this.collection.findOne({ _id: "database" });
1227
- if (!doc) {
1228
- await this.collection.insertOne({
1229
- _id: "database",
1230
- data: {}
1346
+ try {
1347
+ await this.client.connect();
1348
+ this.db = this.client.db(this.databaseName);
1349
+ this.collection = this.db.collection(this.collectionName);
1350
+ const doc = await this.collection.findOne({ _id: "database" });
1351
+ if (!doc) {
1352
+ await this.collection.insertOne({
1353
+ _id: "database",
1354
+ data: {}
1355
+ });
1356
+ }
1357
+ if (!this.isLoaded) {
1358
+ this.isLoaded = true;
1359
+ this.onLoad?.({
1360
+ client: this.client,
1361
+ db: this.db,
1362
+ collection: this.collection,
1363
+ databaseName: this.databaseName,
1364
+ collectionName: this.collectionName
1365
+ });
1366
+ }
1367
+ } catch (error) {
1368
+ this.onError?.({
1369
+ error,
1370
+ databaseName: this.databaseName,
1371
+ collectionName: this.collectionName
1231
1372
  });
1373
+ throw error;
1232
1374
  }
1233
1375
  }
1234
1376
  }