blackcat.js-database 1.0.5 → 1.0.7
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 +6 -1
- package/dist/{index.js → index.cjs} +465 -125
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +353 -50
- package/dist/index.d.ts +353 -50
- package/dist/index.mjs +464 -124
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -13
- package/dist/index.js.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
4
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
3
|
|
|
6
4
|
// src/utils/isObject.function.ts
|
|
7
5
|
var isObject = /* @__PURE__ */ __name((item) => !Array.isArray(item) && item !== null && typeof item === "object", "isObject");
|
|
@@ -30,7 +28,10 @@ var errors = {
|
|
|
30
28
|
INVALID_KEY: "{1}"
|
|
31
29
|
};
|
|
32
30
|
var createTypesArray = /* @__PURE__ */ __name((...elements) => `[${elements.map((element) => typeOf(element))}]`, "createTypesArray");
|
|
33
|
-
var
|
|
31
|
+
var BlackCatError = class extends Error {
|
|
32
|
+
static {
|
|
33
|
+
__name(this, "BlackCatError");
|
|
34
|
+
}
|
|
34
35
|
/**
|
|
35
36
|
* Creates a BlackCatError instance.
|
|
36
37
|
* @param {string} errorCode Quick Mongo error code.
|
|
@@ -47,11 +48,12 @@ var _BlackCatError = class _BlackCatError extends Error {
|
|
|
47
48
|
this.name = `BlackCatError [${code}]`;
|
|
48
49
|
}
|
|
49
50
|
};
|
|
50
|
-
__name(_BlackCatError, "BlackCatError");
|
|
51
|
-
var BlackCatError = _BlackCatError;
|
|
52
51
|
|
|
53
52
|
// src/utils/TypedObject.ts
|
|
54
|
-
var
|
|
53
|
+
var TypedObject = class {
|
|
54
|
+
static {
|
|
55
|
+
__name(this, "TypedObject");
|
|
56
|
+
}
|
|
55
57
|
/**
|
|
56
58
|
* Lấy danh sách key của object với type chính xác.
|
|
57
59
|
*
|
|
@@ -159,11 +161,25 @@ var _TypedObject = class _TypedObject {
|
|
|
159
161
|
return Object.entries(obj || {});
|
|
160
162
|
}
|
|
161
163
|
};
|
|
162
|
-
__name(_TypedObject, "TypedObject");
|
|
163
|
-
var TypedObject = _TypedObject;
|
|
164
164
|
|
|
165
165
|
// src/Database.ts
|
|
166
|
-
var
|
|
166
|
+
var Database = class {
|
|
167
|
+
static {
|
|
168
|
+
__name(this, "Database");
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Storage driver được sử dụng để đọc và ghi dữ liệu database.
|
|
172
|
+
*
|
|
173
|
+
* Driver phải implement interface `DatabaseDriver`.
|
|
174
|
+
*
|
|
175
|
+
* Ví dụ:
|
|
176
|
+
* ```ts
|
|
177
|
+
* const db = new Database({
|
|
178
|
+
* driver: new JSONDriver({ filePath: "./database.json" }),
|
|
179
|
+
* })
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
driver;
|
|
167
183
|
/**
|
|
168
184
|
* Khởi tạo Database instance.
|
|
169
185
|
*
|
|
@@ -189,19 +205,6 @@ var _Database = class _Database {
|
|
|
189
205
|
* ```
|
|
190
206
|
*/
|
|
191
207
|
constructor(options) {
|
|
192
|
-
/**
|
|
193
|
-
* Storage driver được sử dụng để đọc và ghi dữ liệu database.
|
|
194
|
-
*
|
|
195
|
-
* Driver phải implement interface `DatabaseDriver`.
|
|
196
|
-
*
|
|
197
|
-
* Ví dụ:
|
|
198
|
-
* ```ts
|
|
199
|
-
* const db = new Database({
|
|
200
|
-
* driver: new JSONDriver({ filePath: "./database.json" }),
|
|
201
|
-
* })
|
|
202
|
-
* ```
|
|
203
|
-
*/
|
|
204
|
-
__publicField(this, "driver");
|
|
205
208
|
this.driver = options.driver;
|
|
206
209
|
}
|
|
207
210
|
/**
|
|
@@ -250,7 +253,6 @@ var _Database = class _Database {
|
|
|
250
253
|
*/
|
|
251
254
|
async get(key) {
|
|
252
255
|
const data = await this.all();
|
|
253
|
-
if (key === void 0) return data;
|
|
254
256
|
if (typeof key !== "string") {
|
|
255
257
|
throw new BlackCatError("INVALID_TYPE", "key", "string", typeOf(key));
|
|
256
258
|
}
|
|
@@ -303,9 +305,7 @@ var _Database = class _Database {
|
|
|
303
305
|
const data = await this.get(key);
|
|
304
306
|
if (!query) return data;
|
|
305
307
|
if (!Array.isArray(data)) return null;
|
|
306
|
-
const result = data.find((item) =>
|
|
307
|
-
return Object.entries(query).every(([k, v]) => item[k] == v);
|
|
308
|
-
});
|
|
308
|
+
const result = data.find((item) => Object.entries(query).every(([k, v]) => item[k] == v));
|
|
309
309
|
return result ?? null;
|
|
310
310
|
}
|
|
311
311
|
/**
|
|
@@ -339,7 +339,7 @@ var _Database = class _Database {
|
|
|
339
339
|
* @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần gán giá trị.
|
|
340
340
|
* @param {ObjectValue<V, P>} value Giá trị mới.
|
|
341
341
|
*
|
|
342
|
-
* @returns {
|
|
342
|
+
* @returns {void} Giá trị vừa được set hoặc object root nếu value là object.
|
|
343
343
|
*
|
|
344
344
|
* @example
|
|
345
345
|
* ```ts
|
|
@@ -374,26 +374,71 @@ var _Database = class _Database {
|
|
|
374
374
|
}
|
|
375
375
|
;
|
|
376
376
|
await this.driver.set(allDatabase);
|
|
377
|
-
return typeof value == "object" && value !== null ? await this.get(keys[0]) : value;
|
|
378
377
|
}
|
|
379
378
|
/**
|
|
380
|
-
*
|
|
379
|
+
* Đảm bảo một key tồn tại với giá trị mặc định.
|
|
380
|
+
* Nếu key đã tồn tại → giữ nguyên và trả về giá trị hiện tại.
|
|
381
|
+
* Nếu chưa tồn tại → set giá trị default và trả về default đó.
|
|
381
382
|
*
|
|
382
|
-
*
|
|
383
|
+
* Khác với `set()` — không bao giờ ghi đè dữ liệu đã có.
|
|
384
|
+
*
|
|
385
|
+
* @template P Key path trong database.
|
|
386
|
+
*
|
|
387
|
+
* @param key Đường dẫn cần đảm bảo tồn tại.
|
|
388
|
+
* @param defaultValue Giá trị mặc định nếu key chưa có.
|
|
389
|
+
*
|
|
390
|
+
* @returns Giá trị tại key sau khi ensure (current hoặc default).
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* // "config.maxRetries" chưa tồn tại → set về 3, trả về 3
|
|
394
|
+
* const retries = await db.ensure("config.maxRetries", 3);
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* // "config.maxRetries" đã là 10 → không đổi, trả về 10
|
|
398
|
+
* const retries = await db.ensure("config.maxRetries", 3);
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
* // Dùng với object — đảm bảo cấu trúc user tồn tại
|
|
402
|
+
* const user = await db.ensure("users.123", {
|
|
403
|
+
* balance: 0,
|
|
404
|
+
* level: 1,
|
|
405
|
+
* joinedAt: Date.now(),
|
|
406
|
+
* });
|
|
407
|
+
*/
|
|
408
|
+
async ensure(key, defaultValue) {
|
|
409
|
+
const current = await this.get(key);
|
|
410
|
+
if (current !== null && current !== void 0) return current;
|
|
411
|
+
await this.set(key, defaultValue);
|
|
412
|
+
return defaultValue;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Xóa dữ liệu khỏi database.
|
|
416
|
+
* Hỗ trợ truy cập dữ liệu lồng nhau bằng dot notation.
|
|
417
|
+
* Nếu key không tồn tại hoặc đường dẫn không hợp lệ, hàm sẽ trả về `false`.
|
|
383
418
|
*
|
|
384
419
|
* @typeParam P - Path của object.
|
|
385
420
|
*
|
|
386
|
-
* @param key - Đường dẫn
|
|
421
|
+
* @param key - Đường dẫn dữ liệu cần xóa.
|
|
387
422
|
*
|
|
388
423
|
* @returns
|
|
389
|
-
* - `true` nếu xóa thành công
|
|
390
|
-
* - `false` nếu key không tồn tại
|
|
424
|
+
* - `true` nếu xóa thành công.
|
|
425
|
+
* - `false` nếu key không tồn tại hoặc đường dẫn không hợp lệ.
|
|
391
426
|
*
|
|
392
427
|
* @throws BlackCatError
|
|
393
|
-
* - INVALID_TYPE nếu key không phải
|
|
428
|
+
* - INVALID_TYPE nếu `key` không phải là chuỗi.
|
|
394
429
|
*
|
|
395
430
|
* @example
|
|
431
|
+
* // Xóa một thuộc tính
|
|
396
432
|
* await db.delete("user.name");
|
|
433
|
+
*
|
|
434
|
+
* @example
|
|
435
|
+
* // Xóa object lồng nhau
|
|
436
|
+
* await db.delete("users.0.profile");
|
|
437
|
+
*
|
|
438
|
+
* @example
|
|
439
|
+
* // Key không tồn tại
|
|
440
|
+
* const deleted = await db.delete("user.address");
|
|
441
|
+
* console.log(deleted); // false
|
|
397
442
|
*/
|
|
398
443
|
async delete(key) {
|
|
399
444
|
if (typeof key !== "string") {
|
|
@@ -425,8 +470,8 @@ var _Database = class _Database {
|
|
|
425
470
|
* await db.deleteAll();
|
|
426
471
|
*/
|
|
427
472
|
async deleteAll() {
|
|
428
|
-
await this.driver.delete();
|
|
429
|
-
return
|
|
473
|
+
const result = await this.driver.delete();
|
|
474
|
+
return result;
|
|
430
475
|
}
|
|
431
476
|
/**
|
|
432
477
|
* 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.
|
|
@@ -482,25 +527,57 @@ var _Database = class _Database {
|
|
|
482
527
|
return originalLength - filtered.length;
|
|
483
528
|
}
|
|
484
529
|
/**
|
|
485
|
-
* Cập nhật dữ liệu trong database theo đường dẫn key.
|
|
530
|
+
* Cập nhật dữ liệu trong database theo đường dẫn (`key`).
|
|
531
|
+
*
|
|
532
|
+
* ## Chức năng
|
|
533
|
+
* - Cập nhật giá trị tại một key hoặc nested key trong database.
|
|
534
|
+
* - Tự động tạo object trung gian nếu đường dẫn chưa tồn tại.
|
|
535
|
+
* - Hỗ trợ gộp dữ liệu (merge) đối với object và mảng nhằm hạn chế ghi đè dữ liệu đã có.
|
|
536
|
+
*
|
|
537
|
+
* ## Mô tả hoạt động
|
|
538
|
+
* Hàm sẽ đọc toàn bộ dữ liệu database, tìm đến vị trí tương ứng với `key`
|
|
539
|
+
* và cập nhật giá trị mới theo các quy tắc sau:
|
|
486
540
|
*
|
|
487
|
-
*
|
|
488
|
-
* Nếu
|
|
489
|
-
*
|
|
541
|
+
* - **Đối với Array**
|
|
542
|
+
* - Nếu cả giá trị hiện tại và giá trị mới đều là mảng thì sẽ **không ghi đè**.
|
|
543
|
+
* - Các phần tử mới sẽ được thêm vào cuối mảng.
|
|
544
|
+
* - Chỉ thêm những phần tử chưa tồn tại ví dụ dựa trên cặp thuộc tính:
|
|
545
|
+
* - `username`
|
|
546
|
+
* - `guild`
|
|
547
|
+
* - Điều này giúp tránh lưu trùng dữ liệu thành viên giữa nhiều lần cập nhật.
|
|
490
548
|
*
|
|
491
|
-
*
|
|
549
|
+
* - **Đối với Object**
|
|
550
|
+
* - Nếu cả hai đều là object sẽ thực hiện **shallow merge** (`...old, ...new`).
|
|
551
|
+
* - Các thuộc tính mới sẽ ghi đè thuộc tính cùng tên.
|
|
552
|
+
* - Những thuộc tính khác vẫn được giữ nguyên.
|
|
492
553
|
*
|
|
493
|
-
*
|
|
554
|
+
* - **Các kiểu dữ liệu khác**
|
|
555
|
+
* - Giá trị mới sẽ ghi đè hoàn toàn giá trị cũ.
|
|
494
556
|
*
|
|
495
|
-
*
|
|
496
|
-
* Hỗ trợ nested path dạng `"a.b.c"`.
|
|
557
|
+
* Sau khi cập nhật xong, toàn bộ database sẽ được ghi lại thông qua driver.
|
|
497
558
|
*
|
|
498
|
-
* @
|
|
559
|
+
* @template P
|
|
560
|
+
* Đường dẫn hợp lệ của object trong database.
|
|
561
|
+
*
|
|
562
|
+
* @param key
|
|
563
|
+
* Đường dẫn cần cập nhật.
|
|
564
|
+
*
|
|
565
|
+
* Hỗ trợ nested path:
|
|
566
|
+
* ```ts
|
|
567
|
+
* "guilds.123.settings.prefix"
|
|
568
|
+
* "users.456.profile.name"
|
|
569
|
+
* ```
|
|
570
|
+
*
|
|
571
|
+
* @param value
|
|
572
|
+
* Giá trị mới cần cập nhật.
|
|
499
573
|
*
|
|
500
574
|
* @returns
|
|
501
|
-
* Trả về giá trị cuối cùng sau khi
|
|
575
|
+
* Trả về giá trị cuối cùng sau khi được lưu vào database.
|
|
576
|
+
*
|
|
577
|
+
* ## Cách sử dụng
|
|
578
|
+
*
|
|
579
|
+
* ### Ví dụ 1 - Cập nhật object
|
|
502
580
|
*
|
|
503
|
-
* @example
|
|
504
581
|
* Database ban đầu:
|
|
505
582
|
* ```json
|
|
506
583
|
* {
|
|
@@ -512,10 +589,9 @@ var _Database = class _Database {
|
|
|
512
589
|
* }
|
|
513
590
|
* ```
|
|
514
591
|
*
|
|
515
|
-
* Cập nhật:
|
|
516
592
|
* ```ts
|
|
517
593
|
* await db.update("123", {
|
|
518
|
-
*
|
|
594
|
+
* history: [1, 2, 3]
|
|
519
595
|
* });
|
|
520
596
|
* ```
|
|
521
597
|
*
|
|
@@ -525,14 +601,120 @@ var _Database = class _Database {
|
|
|
525
601
|
* "123": {
|
|
526
602
|
* "guildID": "123",
|
|
527
603
|
* "guildName": "BlackCat",
|
|
528
|
-
* "history": [1,2,3]
|
|
604
|
+
* "history": [1, 2, 3]
|
|
605
|
+
* }
|
|
606
|
+
* }
|
|
607
|
+
* ```
|
|
608
|
+
*
|
|
609
|
+
* ---
|
|
610
|
+
*
|
|
611
|
+
* ### Ví dụ 2 - Cập nhật nested key
|
|
612
|
+
*
|
|
613
|
+
* ```ts
|
|
614
|
+
* await db.update("guilds.123.settings.prefix", "!");
|
|
615
|
+
* ```
|
|
616
|
+
*
|
|
617
|
+
* Nếu đường dẫn chưa tồn tại:
|
|
618
|
+
*
|
|
619
|
+
* ```json
|
|
620
|
+
* {}
|
|
621
|
+
* ```
|
|
622
|
+
*
|
|
623
|
+
* Sau khi cập nhật:
|
|
624
|
+
*
|
|
625
|
+
* ```json
|
|
626
|
+
* {
|
|
627
|
+
* "guilds": {
|
|
628
|
+
* "123": {
|
|
629
|
+
* "settings": {
|
|
630
|
+
* "prefix": "!"
|
|
631
|
+
* }
|
|
632
|
+
* }
|
|
529
633
|
* }
|
|
530
634
|
* }
|
|
531
635
|
* ```
|
|
532
636
|
*
|
|
637
|
+
* ---
|
|
638
|
+
*
|
|
639
|
+
* ### Ví dụ 3 - Merge object
|
|
640
|
+
*
|
|
641
|
+
* Giá trị hiện tại:
|
|
642
|
+
*
|
|
643
|
+
* ```json
|
|
644
|
+
* {
|
|
645
|
+
* "name": "BlackCat",
|
|
646
|
+
* "language": "vi",
|
|
647
|
+
* "prefix": "!"
|
|
648
|
+
* }
|
|
649
|
+
* ```
|
|
650
|
+
*
|
|
651
|
+
* ```ts
|
|
652
|
+
* await db.update("config", {
|
|
653
|
+
* prefix: "?",
|
|
654
|
+
* color: "#5865F2"
|
|
655
|
+
* });
|
|
656
|
+
* ```
|
|
657
|
+
*
|
|
658
|
+
* Kết quả:
|
|
659
|
+
*
|
|
660
|
+
* ```json
|
|
661
|
+
* {
|
|
662
|
+
* "name": "BlackCat",
|
|
663
|
+
* "language": "vi",
|
|
664
|
+
* "prefix": "?",
|
|
665
|
+
* "color": "#5865F2"
|
|
666
|
+
* }
|
|
667
|
+
* ```
|
|
668
|
+
*
|
|
669
|
+
* ---
|
|
670
|
+
*
|
|
671
|
+
* ### Ví dụ 4 - Merge mảng và loại bỏ phần tử trùng
|
|
672
|
+
*
|
|
673
|
+
* Giá trị hiện tại:
|
|
674
|
+
*
|
|
675
|
+
* ```json
|
|
676
|
+
* [
|
|
677
|
+
* {
|
|
678
|
+
* "username": "Alice",
|
|
679
|
+
* "guild": "123"
|
|
680
|
+
* }
|
|
681
|
+
* ]
|
|
682
|
+
* ```
|
|
683
|
+
*
|
|
684
|
+
* ```ts
|
|
685
|
+
* await db.update("history", [
|
|
686
|
+
* {
|
|
687
|
+
* username: "Alice",
|
|
688
|
+
* guild: "123"
|
|
689
|
+
* },
|
|
690
|
+
* {
|
|
691
|
+
* username: "Bob",
|
|
692
|
+
* guild: "123"
|
|
693
|
+
* }
|
|
694
|
+
* ]);
|
|
695
|
+
* ```
|
|
696
|
+
*
|
|
697
|
+
* Kết quả:
|
|
698
|
+
*
|
|
699
|
+
* ```json
|
|
700
|
+
* [
|
|
701
|
+
* {
|
|
702
|
+
* "username": "Alice",
|
|
703
|
+
* "guild": "123"
|
|
704
|
+
* },
|
|
705
|
+
* {
|
|
706
|
+
* "username": "Bob",
|
|
707
|
+
* "guild": "123"
|
|
708
|
+
* }
|
|
709
|
+
* ]
|
|
710
|
+
* ```
|
|
711
|
+
*
|
|
712
|
+
* Phần tử `"Alice"` sẽ không được thêm lần nữa vì đã tồn tại với cùng
|
|
713
|
+
* `username` và `guild`.
|
|
714
|
+
*
|
|
533
715
|
* @throws {BlackCatError}
|
|
534
|
-
* - `REQUIRED_PARAMETER_MISSING` nếu
|
|
535
|
-
* - `INVALID_TYPE` nếu key không phải string
|
|
716
|
+
* - `REQUIRED_PARAMETER_MISSING` nếu không truyền `key`.
|
|
717
|
+
* - `INVALID_TYPE` nếu `key` không phải kiểu `string`.
|
|
536
718
|
*/
|
|
537
719
|
async update(key, value) {
|
|
538
720
|
if (!key) {
|
|
@@ -552,9 +734,13 @@ var _Database = class _Database {
|
|
|
552
734
|
current = current[part];
|
|
553
735
|
}
|
|
554
736
|
const lastKey = keys[keys.length - 1];
|
|
555
|
-
|
|
737
|
+
const currentValue = current[lastKey];
|
|
738
|
+
if (Array.isArray(value) && Array.isArray(currentValue)) {
|
|
739
|
+
const unique = value.filter((item) => !currentValue.some((existing) => existing.username === item.username && existing.guild === item.guild));
|
|
740
|
+
current[lastKey] = [...currentValue, ...unique];
|
|
741
|
+
} else if (isObject(value) && isObject(currentValue)) {
|
|
556
742
|
current[lastKey] = {
|
|
557
|
-
...
|
|
743
|
+
...currentValue,
|
|
558
744
|
...value
|
|
559
745
|
};
|
|
560
746
|
} else {
|
|
@@ -563,6 +749,114 @@ var _Database = class _Database {
|
|
|
563
749
|
await this.driver.set(allDatabase);
|
|
564
750
|
return current[lastKey];
|
|
565
751
|
}
|
|
752
|
+
/**
|
|
753
|
+
* ## Đồng bộ dữ liệu với cơ sở dữ liệu
|
|
754
|
+
*
|
|
755
|
+
* ### Chức năng
|
|
756
|
+
* Đồng bộ dữ liệu tại một đường dẫn (`keys`) với giá trị mới (`value`).
|
|
757
|
+
*
|
|
758
|
+
* Hàm sẽ tự động:
|
|
759
|
+
* - Tạo mới dữ liệu nếu chưa tồn tại.
|
|
760
|
+
* - So sánh dữ liệu cũ và mới.
|
|
761
|
+
* - Chỉ cập nhật các trường thực sự thay đổi đối với Object.
|
|
762
|
+
* - Không thực hiện ghi nếu dữ liệu không thay đổi.
|
|
763
|
+
*
|
|
764
|
+
* Điều này giúp giảm số lần ghi xuống cơ sở dữ liệu và tối ưu hiệu năng.
|
|
765
|
+
*
|
|
766
|
+
* ---
|
|
767
|
+
*
|
|
768
|
+
* ### Cơ chế hoạt động
|
|
769
|
+
*
|
|
770
|
+
* 1. Lấy dữ liệu hiện tại bằng `get()`.
|
|
771
|
+
* 2. Nếu chưa tồn tại (`undefined` hoặc `null`)
|
|
772
|
+
* → gọi `set()` để tạo mới.
|
|
773
|
+
* 3. Nếu truyền hàm `compare` và hàm này trả về `true`
|
|
774
|
+
* → bỏ qua đồng bộ.
|
|
775
|
+
* 4. Nếu dữ liệu không phải Object (hoặc là Array)
|
|
776
|
+
* → so sánh bằng `Object.is()`, nếu khác thì gọi `update()`.
|
|
777
|
+
* 5. Nếu dữ liệu là Object
|
|
778
|
+
* → chỉ lấy các thuộc tính thay đổi và cập nhật đúng các trường đó.
|
|
779
|
+
* 6. Nếu không có trường nào thay đổi thì không ghi dữ liệu.
|
|
780
|
+
*
|
|
781
|
+
* ---
|
|
782
|
+
*
|
|
783
|
+
* ### Giá trị trả về
|
|
784
|
+
*
|
|
785
|
+
* - `undefined`
|
|
786
|
+
* - Khi tạo mới dữ liệu.
|
|
787
|
+
* - Khi không có thay đổi.
|
|
788
|
+
* - Khi dữ liệu nguyên thủy được cập nhật.
|
|
789
|
+
* - `Partial<ObjectValue<V, P>>`
|
|
790
|
+
* - Trả về object chỉ chứa các trường đã được cập nhật khi đồng bộ Object.
|
|
791
|
+
*
|
|
792
|
+
* ---
|
|
793
|
+
*
|
|
794
|
+
* ### Ví dụ
|
|
795
|
+
*
|
|
796
|
+
* ```ts
|
|
797
|
+
* // Tạo mới nếu chưa tồn tại
|
|
798
|
+
* await db.syncDatabase({
|
|
799
|
+
* keys: "users.1",
|
|
800
|
+
* value: {
|
|
801
|
+
* name: "BlackCat",
|
|
802
|
+
* age: 20
|
|
803
|
+
* }
|
|
804
|
+
* });
|
|
805
|
+
*
|
|
806
|
+
* // Chỉ cập nhật trường age
|
|
807
|
+
* await db.syncDatabase({
|
|
808
|
+
* keys: "users.1",
|
|
809
|
+
* value: {
|
|
810
|
+
* name: "BlackCat",
|
|
811
|
+
* age: 21
|
|
812
|
+
* }
|
|
813
|
+
* });
|
|
814
|
+
*
|
|
815
|
+
* // Sử dụng compare để bỏ qua đồng bộ
|
|
816
|
+
* await db.syncDatabase({
|
|
817
|
+
* keys: "users.1",
|
|
818
|
+
* value: newData,
|
|
819
|
+
* compare(oldData, newData) {
|
|
820
|
+
* return oldData.version >= newData.version;
|
|
821
|
+
* }
|
|
822
|
+
* });
|
|
823
|
+
* ```
|
|
824
|
+
*
|
|
825
|
+
* @template P Đường dẫn tới dữ liệu trong cơ sở dữ liệu.
|
|
826
|
+
*
|
|
827
|
+
* @param options Thông tin đồng bộ.
|
|
828
|
+
* @param options.keys Đường dẫn của dữ liệu cần đồng bộ.
|
|
829
|
+
* @param options.value Giá trị mới cần ghi.
|
|
830
|
+
* @param options.compare Hàm so sánh tùy chỉnh. Nếu trả về `true` thì sẽ không thực hiện đồng bộ.
|
|
831
|
+
*
|
|
832
|
+
* @returns
|
|
833
|
+
* - `undefined` nếu không có thay đổi hoặc dữ liệu được tạo mới.
|
|
834
|
+
* - `Partial<ObjectValue<V, P>>` chứa các trường đã thay đổi khi cập nhật Object.
|
|
835
|
+
*/
|
|
836
|
+
async syncDatabase({ keys, value, compare }) {
|
|
837
|
+
const oldValue = await this.get(keys);
|
|
838
|
+
if (oldValue === void 0 || oldValue === null) {
|
|
839
|
+
await this.set(keys, value);
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
if (compare?.(oldValue, value)) return;
|
|
843
|
+
if (!isObject(oldValue) || !isObject(value) || Array.isArray(oldValue) || Array.isArray(value)) {
|
|
844
|
+
if (!Object.is(oldValue, value)) {
|
|
845
|
+
await this.update(keys, value);
|
|
846
|
+
}
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
const changed = {};
|
|
850
|
+
for (const k in value) {
|
|
851
|
+
const field = k;
|
|
852
|
+
if (!Object.is(oldValue[field], value[field])) {
|
|
853
|
+
changed[field] = value[field];
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (Object.keys(changed).length === 0) return;
|
|
857
|
+
await this.update(keys, changed);
|
|
858
|
+
return changed;
|
|
859
|
+
}
|
|
566
860
|
/**
|
|
567
861
|
* Cộng thêm giá trị vào một key dạng number.
|
|
568
862
|
*
|
|
@@ -591,7 +885,8 @@ var _Database = class _Database {
|
|
|
591
885
|
if (!isNumber(numberToAdd)) {
|
|
592
886
|
throw new BlackCatError("INVALID_TYPE", "numberToAdd", "number", typeOf(numberToAdd));
|
|
593
887
|
}
|
|
594
|
-
|
|
888
|
+
await this.set(key, targetNumber + numberToAdd);
|
|
889
|
+
return targetNumber + numberToAdd;
|
|
595
890
|
}
|
|
596
891
|
/**
|
|
597
892
|
* Trừ giá trị khỏi một key dạng number.
|
|
@@ -621,7 +916,48 @@ var _Database = class _Database {
|
|
|
621
916
|
if (!isNumber(numberToSubtract)) {
|
|
622
917
|
throw new BlackCatError("INVALID_TYPE", "numberToSubtract", "number", typeOf(numberToSubtract));
|
|
623
918
|
}
|
|
624
|
-
|
|
919
|
+
await this.set(key, targetNumber - numberToSubtract);
|
|
920
|
+
return targetNumber - numberToSubtract;
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Thêm một hoặc nhiều phần tử vào đầu array.
|
|
924
|
+
*
|
|
925
|
+
* Chỉ thêm những phần tử chưa tồn tại trong array.
|
|
926
|
+
*
|
|
927
|
+
* @typeParam P - Path trỏ tới array.
|
|
928
|
+
*
|
|
929
|
+
* @param key - Đường dẫn array.
|
|
930
|
+
* @param values - Một hoặc nhiều phần tử cần thêm.
|
|
931
|
+
*
|
|
932
|
+
* @returns Array sau khi thêm.
|
|
933
|
+
*
|
|
934
|
+
* @example
|
|
935
|
+
* await db.unshift("users", newUser);
|
|
936
|
+
*/
|
|
937
|
+
async unshift(key, ...values) {
|
|
938
|
+
if (!values.length) {
|
|
939
|
+
throw new BlackCatError("REQUIRED_PARAMETER_MISSING", "values");
|
|
940
|
+
}
|
|
941
|
+
const root = await this.all();
|
|
942
|
+
const pathParts = key.split(".");
|
|
943
|
+
let target = root;
|
|
944
|
+
for (let i = 0; i < pathParts.length; i++) {
|
|
945
|
+
const part = pathParts[i];
|
|
946
|
+
if (!(part in target)) {
|
|
947
|
+
throw new BlackCatError("INVALID_KEY", key);
|
|
948
|
+
}
|
|
949
|
+
if (i === pathParts.length - 1) {
|
|
950
|
+
if (!Array.isArray(target[part])) {
|
|
951
|
+
throw new BlackCatError("INVALID_TARGET", "array", typeOf(target[part]));
|
|
952
|
+
}
|
|
953
|
+
const uniqueValues = values.filter((v) => !target[part].includes(v));
|
|
954
|
+
target[part].unshift(...uniqueValues);
|
|
955
|
+
} else {
|
|
956
|
+
target = target[part];
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
await this.set(pathParts[0], root[pathParts[0]]);
|
|
960
|
+
return target[pathParts[pathParts.length - 1]];
|
|
625
961
|
}
|
|
626
962
|
/**
|
|
627
963
|
* Thêm một hoặc nhiều phần tử vào cuối array tại key-path.
|
|
@@ -839,7 +1175,8 @@ var _Database = class _Database {
|
|
|
839
1175
|
* const userKeys = await db.keys("user");
|
|
840
1176
|
*/
|
|
841
1177
|
async keys(key) {
|
|
842
|
-
|
|
1178
|
+
const all = await this.all();
|
|
1179
|
+
if (!key) return TypedObject.keys(all);
|
|
843
1180
|
const data = await this.get(key);
|
|
844
1181
|
return TypedObject.keys(data).filter((key2) => data[key2] !== void 0 && data[key2] !== null);
|
|
845
1182
|
}
|
|
@@ -873,7 +1210,8 @@ var _Database = class _Database {
|
|
|
873
1210
|
* const userValues = await db.values("users");
|
|
874
1211
|
*/
|
|
875
1212
|
async values(key) {
|
|
876
|
-
|
|
1213
|
+
const all = await this.all();
|
|
1214
|
+
if (!key) return TypedObject.values(all);
|
|
877
1215
|
const data = await this.get(key);
|
|
878
1216
|
return TypedObject.values(data);
|
|
879
1217
|
}
|
|
@@ -998,12 +1336,21 @@ var _Database = class _Database {
|
|
|
998
1336
|
return values.every(queryFunction);
|
|
999
1337
|
}
|
|
1000
1338
|
};
|
|
1001
|
-
__name(_Database, "Database");
|
|
1002
|
-
var Database = _Database;
|
|
1003
1339
|
|
|
1004
1340
|
// src/drivers/JSONDriver.ts
|
|
1005
1341
|
import { promises as fs } from "fs";
|
|
1006
|
-
var
|
|
1342
|
+
var JSONDriver = class {
|
|
1343
|
+
static {
|
|
1344
|
+
__name(this, "JSONDriver");
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* Đường dẫn tới file database JSON.
|
|
1348
|
+
*/
|
|
1349
|
+
filePath;
|
|
1350
|
+
/**
|
|
1351
|
+
* Cho biết có minify JSON khi ghi file hay không.
|
|
1352
|
+
*/
|
|
1353
|
+
minifyJSON;
|
|
1007
1354
|
/**
|
|
1008
1355
|
* Khởi tạo một instance mới của {@link JSONDriver}.
|
|
1009
1356
|
*
|
|
@@ -1025,14 +1372,6 @@ var _JSONDriver = class _JSONDriver {
|
|
|
1025
1372
|
* ```
|
|
1026
1373
|
*/
|
|
1027
1374
|
constructor(options) {
|
|
1028
|
-
/**
|
|
1029
|
-
* Đường dẫn tới file database JSON.
|
|
1030
|
-
*/
|
|
1031
|
-
__publicField(this, "filePath");
|
|
1032
|
-
/**
|
|
1033
|
-
* Cho biết có minify JSON khi ghi file hay không.
|
|
1034
|
-
*/
|
|
1035
|
-
__publicField(this, "minifyJSON");
|
|
1036
1375
|
this.filePath = options.filePath || "database.json";
|
|
1037
1376
|
this.minifyJSON = options.minifyJSON || false;
|
|
1038
1377
|
}
|
|
@@ -1093,11 +1432,16 @@ var _JSONDriver = class _JSONDriver {
|
|
|
1093
1432
|
return true;
|
|
1094
1433
|
}
|
|
1095
1434
|
};
|
|
1096
|
-
__name(_JSONDriver, "JSONDriver");
|
|
1097
|
-
var JSONDriver = _JSONDriver;
|
|
1098
1435
|
|
|
1099
1436
|
// src/drivers/MemoryDriver.ts
|
|
1100
|
-
var
|
|
1437
|
+
var MemoryDriver = class {
|
|
1438
|
+
static {
|
|
1439
|
+
__name(this, "MemoryDriver");
|
|
1440
|
+
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Object chứa toàn bộ dữ liệu database trong RAM.
|
|
1443
|
+
*/
|
|
1444
|
+
store;
|
|
1101
1445
|
/**
|
|
1102
1446
|
* Khởi tạo MemoryDriver.
|
|
1103
1447
|
*
|
|
@@ -1124,10 +1468,6 @@ var _MemoryDriver = class _MemoryDriver {
|
|
|
1124
1468
|
* ```
|
|
1125
1469
|
*/
|
|
1126
1470
|
constructor(initialData = {}) {
|
|
1127
|
-
/**
|
|
1128
|
-
* Object chứa toàn bộ dữ liệu database trong RAM.
|
|
1129
|
-
*/
|
|
1130
|
-
__publicField(this, "store");
|
|
1131
1471
|
this.store = initialData;
|
|
1132
1472
|
}
|
|
1133
1473
|
/**
|
|
@@ -1158,12 +1498,21 @@ var _MemoryDriver = class _MemoryDriver {
|
|
|
1158
1498
|
return true;
|
|
1159
1499
|
}
|
|
1160
1500
|
};
|
|
1161
|
-
__name(_MemoryDriver, "MemoryDriver");
|
|
1162
|
-
var MemoryDriver = _MemoryDriver;
|
|
1163
1501
|
|
|
1164
1502
|
// src/drivers/SQLiteDriver.ts
|
|
1165
1503
|
import SQLite from "better-sqlite3";
|
|
1166
|
-
var
|
|
1504
|
+
var SQLiteDriver = class {
|
|
1505
|
+
static {
|
|
1506
|
+
__name(this, "SQLiteDriver");
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* SQLite database instance.
|
|
1510
|
+
*/
|
|
1511
|
+
db;
|
|
1512
|
+
/**
|
|
1513
|
+
* Tên table lưu trữ dữ liệu JSON.
|
|
1514
|
+
*/
|
|
1515
|
+
table;
|
|
1167
1516
|
/**
|
|
1168
1517
|
* Khởi tạo SQLiteDriver.
|
|
1169
1518
|
*
|
|
@@ -1180,14 +1529,6 @@ var _SQLiteDriver = class _SQLiteDriver {
|
|
|
1180
1529
|
* ```
|
|
1181
1530
|
*/
|
|
1182
1531
|
constructor(options = {}) {
|
|
1183
|
-
/**
|
|
1184
|
-
* SQLite database instance.
|
|
1185
|
-
*/
|
|
1186
|
-
__publicField(this, "db");
|
|
1187
|
-
/**
|
|
1188
|
-
* Tên table lưu trữ dữ liệu JSON.
|
|
1189
|
-
*/
|
|
1190
|
-
__publicField(this, "table");
|
|
1191
1532
|
this.db = new SQLite(options.filePath ?? "database.sqlite");
|
|
1192
1533
|
this.table = options.table ?? "json_store";
|
|
1193
1534
|
this.db.prepare(`CREATE TABLE IF NOT EXISTS ${this.table} (id INTEGER PRIMARY KEY, data TEXT)`).run();
|
|
@@ -1225,12 +1566,45 @@ var _SQLiteDriver = class _SQLiteDriver {
|
|
|
1225
1566
|
return true;
|
|
1226
1567
|
}
|
|
1227
1568
|
};
|
|
1228
|
-
__name(_SQLiteDriver, "SQLiteDriver");
|
|
1229
|
-
var SQLiteDriver = _SQLiteDriver;
|
|
1230
1569
|
|
|
1231
1570
|
// src/drivers/MongoDriver.ts
|
|
1232
1571
|
import { MongoClient } from "mongodb";
|
|
1233
|
-
var
|
|
1572
|
+
var MongoDriver = class {
|
|
1573
|
+
static {
|
|
1574
|
+
__name(this, "MongoDriver");
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* MongoDB client instance.
|
|
1578
|
+
*/
|
|
1579
|
+
client;
|
|
1580
|
+
/**
|
|
1581
|
+
* MongoDB database instance.
|
|
1582
|
+
*/
|
|
1583
|
+
db;
|
|
1584
|
+
/**
|
|
1585
|
+
* Collection lưu dữ liệu JSON.
|
|
1586
|
+
*/
|
|
1587
|
+
collection;
|
|
1588
|
+
/**
|
|
1589
|
+
* Tên database MongoDB.
|
|
1590
|
+
*/
|
|
1591
|
+
databaseName;
|
|
1592
|
+
/**
|
|
1593
|
+
* Tên collection MongoDB.
|
|
1594
|
+
*/
|
|
1595
|
+
collectionName;
|
|
1596
|
+
/**
|
|
1597
|
+
* Callback khi kết nối thành công.
|
|
1598
|
+
*/
|
|
1599
|
+
onLoad;
|
|
1600
|
+
/**
|
|
1601
|
+
* Callback khi xảy ra lỗi.
|
|
1602
|
+
*/
|
|
1603
|
+
onError;
|
|
1604
|
+
/**
|
|
1605
|
+
* Trạng thái đã gọi onLoad chưa (tránh spam)
|
|
1606
|
+
*/
|
|
1607
|
+
isLoaded = false;
|
|
1234
1608
|
/**
|
|
1235
1609
|
* Khởi tạo MongoDriver.
|
|
1236
1610
|
*
|
|
@@ -1257,38 +1631,6 @@ var _MongoDriver = class _MongoDriver {
|
|
|
1257
1631
|
* });
|
|
1258
1632
|
*/
|
|
1259
1633
|
constructor(options = {}) {
|
|
1260
|
-
/**
|
|
1261
|
-
* MongoDB client instance.
|
|
1262
|
-
*/
|
|
1263
|
-
__publicField(this, "client");
|
|
1264
|
-
/**
|
|
1265
|
-
* MongoDB database instance.
|
|
1266
|
-
*/
|
|
1267
|
-
__publicField(this, "db");
|
|
1268
|
-
/**
|
|
1269
|
-
* Collection lưu dữ liệu JSON.
|
|
1270
|
-
*/
|
|
1271
|
-
__publicField(this, "collection");
|
|
1272
|
-
/**
|
|
1273
|
-
* Tên database MongoDB.
|
|
1274
|
-
*/
|
|
1275
|
-
__publicField(this, "databaseName");
|
|
1276
|
-
/**
|
|
1277
|
-
* Tên collection MongoDB.
|
|
1278
|
-
*/
|
|
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);
|
|
1292
1634
|
const {
|
|
1293
1635
|
mongourl = "mongodb://localhost:27017",
|
|
1294
1636
|
databaseName = "database",
|
|
@@ -1372,8 +1714,6 @@ var _MongoDriver = class _MongoDriver {
|
|
|
1372
1714
|
return true;
|
|
1373
1715
|
}
|
|
1374
1716
|
};
|
|
1375
|
-
__name(_MongoDriver, "MongoDriver");
|
|
1376
|
-
var MongoDriver = _MongoDriver;
|
|
1377
1717
|
export {
|
|
1378
1718
|
Database,
|
|
1379
1719
|
JSONDriver,
|