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
|
@@ -5,7 +5,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
8
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
10
9
|
var __export = (target, all) => {
|
|
11
10
|
for (var name in all)
|
|
@@ -28,7 +27,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
27
|
mod
|
|
29
28
|
));
|
|
30
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
31
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
32
30
|
|
|
33
31
|
// src/index.ts
|
|
34
32
|
var index_exports = {};
|
|
@@ -68,7 +66,10 @@ var errors = {
|
|
|
68
66
|
INVALID_KEY: "{1}"
|
|
69
67
|
};
|
|
70
68
|
var createTypesArray = /* @__PURE__ */ __name((...elements) => `[${elements.map((element) => typeOf(element))}]`, "createTypesArray");
|
|
71
|
-
var
|
|
69
|
+
var BlackCatError = class extends Error {
|
|
70
|
+
static {
|
|
71
|
+
__name(this, "BlackCatError");
|
|
72
|
+
}
|
|
72
73
|
/**
|
|
73
74
|
* Creates a BlackCatError instance.
|
|
74
75
|
* @param {string} errorCode Quick Mongo error code.
|
|
@@ -85,11 +86,12 @@ var _BlackCatError = class _BlackCatError extends Error {
|
|
|
85
86
|
this.name = `BlackCatError [${code}]`;
|
|
86
87
|
}
|
|
87
88
|
};
|
|
88
|
-
__name(_BlackCatError, "BlackCatError");
|
|
89
|
-
var BlackCatError = _BlackCatError;
|
|
90
89
|
|
|
91
90
|
// src/utils/TypedObject.ts
|
|
92
|
-
var
|
|
91
|
+
var TypedObject = class {
|
|
92
|
+
static {
|
|
93
|
+
__name(this, "TypedObject");
|
|
94
|
+
}
|
|
93
95
|
/**
|
|
94
96
|
* Lấy danh sách key của object với type chính xác.
|
|
95
97
|
*
|
|
@@ -197,11 +199,25 @@ var _TypedObject = class _TypedObject {
|
|
|
197
199
|
return Object.entries(obj || {});
|
|
198
200
|
}
|
|
199
201
|
};
|
|
200
|
-
__name(_TypedObject, "TypedObject");
|
|
201
|
-
var TypedObject = _TypedObject;
|
|
202
202
|
|
|
203
203
|
// src/Database.ts
|
|
204
|
-
var
|
|
204
|
+
var Database = class {
|
|
205
|
+
static {
|
|
206
|
+
__name(this, "Database");
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Storage driver được sử dụng để đọc và ghi dữ liệu database.
|
|
210
|
+
*
|
|
211
|
+
* Driver phải implement interface `DatabaseDriver`.
|
|
212
|
+
*
|
|
213
|
+
* Ví dụ:
|
|
214
|
+
* ```ts
|
|
215
|
+
* const db = new Database({
|
|
216
|
+
* driver: new JSONDriver({ filePath: "./database.json" }),
|
|
217
|
+
* })
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
driver;
|
|
205
221
|
/**
|
|
206
222
|
* Khởi tạo Database instance.
|
|
207
223
|
*
|
|
@@ -227,19 +243,6 @@ var _Database = class _Database {
|
|
|
227
243
|
* ```
|
|
228
244
|
*/
|
|
229
245
|
constructor(options) {
|
|
230
|
-
/**
|
|
231
|
-
* Storage driver được sử dụng để đọc và ghi dữ liệu database.
|
|
232
|
-
*
|
|
233
|
-
* Driver phải implement interface `DatabaseDriver`.
|
|
234
|
-
*
|
|
235
|
-
* Ví dụ:
|
|
236
|
-
* ```ts
|
|
237
|
-
* const db = new Database({
|
|
238
|
-
* driver: new JSONDriver({ filePath: "./database.json" }),
|
|
239
|
-
* })
|
|
240
|
-
* ```
|
|
241
|
-
*/
|
|
242
|
-
__publicField(this, "driver");
|
|
243
246
|
this.driver = options.driver;
|
|
244
247
|
}
|
|
245
248
|
/**
|
|
@@ -288,7 +291,6 @@ var _Database = class _Database {
|
|
|
288
291
|
*/
|
|
289
292
|
async get(key) {
|
|
290
293
|
const data = await this.all();
|
|
291
|
-
if (key === void 0) return data;
|
|
292
294
|
if (typeof key !== "string") {
|
|
293
295
|
throw new BlackCatError("INVALID_TYPE", "key", "string", typeOf(key));
|
|
294
296
|
}
|
|
@@ -341,9 +343,7 @@ var _Database = class _Database {
|
|
|
341
343
|
const data = await this.get(key);
|
|
342
344
|
if (!query) return data;
|
|
343
345
|
if (!Array.isArray(data)) return null;
|
|
344
|
-
const result = data.find((item) =>
|
|
345
|
-
return Object.entries(query).every(([k, v]) => item[k] == v);
|
|
346
|
-
});
|
|
346
|
+
const result = data.find((item) => Object.entries(query).every(([k, v]) => item[k] == v));
|
|
347
347
|
return result ?? null;
|
|
348
348
|
}
|
|
349
349
|
/**
|
|
@@ -377,7 +377,7 @@ var _Database = class _Database {
|
|
|
377
377
|
* @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần gán giá trị.
|
|
378
378
|
* @param {ObjectValue<V, P>} value Giá trị mới.
|
|
379
379
|
*
|
|
380
|
-
* @returns {
|
|
380
|
+
* @returns {void} Giá trị vừa được set hoặc object root nếu value là object.
|
|
381
381
|
*
|
|
382
382
|
* @example
|
|
383
383
|
* ```ts
|
|
@@ -412,26 +412,71 @@ var _Database = class _Database {
|
|
|
412
412
|
}
|
|
413
413
|
;
|
|
414
414
|
await this.driver.set(allDatabase);
|
|
415
|
-
return typeof value == "object" && value !== null ? await this.get(keys[0]) : value;
|
|
416
415
|
}
|
|
417
416
|
/**
|
|
418
|
-
*
|
|
417
|
+
* Đảm bảo một key tồn tại với giá trị mặc định.
|
|
418
|
+
* Nếu key đã tồn tại → giữ nguyên và trả về giá trị hiện tại.
|
|
419
|
+
* Nếu chưa tồn tại → set giá trị default và trả về default đó.
|
|
419
420
|
*
|
|
420
|
-
*
|
|
421
|
+
* Khác với `set()` — không bao giờ ghi đè dữ liệu đã có.
|
|
422
|
+
*
|
|
423
|
+
* @template P Key path trong database.
|
|
424
|
+
*
|
|
425
|
+
* @param key Đường dẫn cần đảm bảo tồn tại.
|
|
426
|
+
* @param defaultValue Giá trị mặc định nếu key chưa có.
|
|
427
|
+
*
|
|
428
|
+
* @returns Giá trị tại key sau khi ensure (current hoặc default).
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* // "config.maxRetries" chưa tồn tại → set về 3, trả về 3
|
|
432
|
+
* const retries = await db.ensure("config.maxRetries", 3);
|
|
433
|
+
*
|
|
434
|
+
* @example
|
|
435
|
+
* // "config.maxRetries" đã là 10 → không đổi, trả về 10
|
|
436
|
+
* const retries = await db.ensure("config.maxRetries", 3);
|
|
437
|
+
*
|
|
438
|
+
* @example
|
|
439
|
+
* // Dùng với object — đảm bảo cấu trúc user tồn tại
|
|
440
|
+
* const user = await db.ensure("users.123", {
|
|
441
|
+
* balance: 0,
|
|
442
|
+
* level: 1,
|
|
443
|
+
* joinedAt: Date.now(),
|
|
444
|
+
* });
|
|
445
|
+
*/
|
|
446
|
+
async ensure(key, defaultValue) {
|
|
447
|
+
const current = await this.get(key);
|
|
448
|
+
if (current !== null && current !== void 0) return current;
|
|
449
|
+
await this.set(key, defaultValue);
|
|
450
|
+
return defaultValue;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Xóa dữ liệu khỏi database.
|
|
454
|
+
* Hỗ trợ truy cập dữ liệu lồng nhau bằng dot notation.
|
|
455
|
+
* 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`.
|
|
421
456
|
*
|
|
422
457
|
* @typeParam P - Path của object.
|
|
423
458
|
*
|
|
424
|
-
* @param key - Đường dẫn
|
|
459
|
+
* @param key - Đường dẫn dữ liệu cần xóa.
|
|
425
460
|
*
|
|
426
461
|
* @returns
|
|
427
|
-
* - `true` nếu xóa thành công
|
|
428
|
-
* - `false` nếu key không tồn tại
|
|
462
|
+
* - `true` nếu xóa thành công.
|
|
463
|
+
* - `false` nếu key không tồn tại hoặc đường dẫn không hợp lệ.
|
|
429
464
|
*
|
|
430
465
|
* @throws BlackCatError
|
|
431
|
-
* - INVALID_TYPE nếu key không phải
|
|
466
|
+
* - INVALID_TYPE nếu `key` không phải là chuỗi.
|
|
432
467
|
*
|
|
433
468
|
* @example
|
|
469
|
+
* // Xóa một thuộc tính
|
|
434
470
|
* await db.delete("user.name");
|
|
471
|
+
*
|
|
472
|
+
* @example
|
|
473
|
+
* // Xóa object lồng nhau
|
|
474
|
+
* await db.delete("users.0.profile");
|
|
475
|
+
*
|
|
476
|
+
* @example
|
|
477
|
+
* // Key không tồn tại
|
|
478
|
+
* const deleted = await db.delete("user.address");
|
|
479
|
+
* console.log(deleted); // false
|
|
435
480
|
*/
|
|
436
481
|
async delete(key) {
|
|
437
482
|
if (typeof key !== "string") {
|
|
@@ -463,8 +508,8 @@ var _Database = class _Database {
|
|
|
463
508
|
* await db.deleteAll();
|
|
464
509
|
*/
|
|
465
510
|
async deleteAll() {
|
|
466
|
-
await this.driver.delete();
|
|
467
|
-
return
|
|
511
|
+
const result = await this.driver.delete();
|
|
512
|
+
return result;
|
|
468
513
|
}
|
|
469
514
|
/**
|
|
470
515
|
* 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.
|
|
@@ -520,25 +565,57 @@ var _Database = class _Database {
|
|
|
520
565
|
return originalLength - filtered.length;
|
|
521
566
|
}
|
|
522
567
|
/**
|
|
523
|
-
* Cập nhật dữ liệu trong database theo đường dẫn key.
|
|
568
|
+
* Cập nhật dữ liệu trong database theo đường dẫn (`key`).
|
|
569
|
+
*
|
|
570
|
+
* ## Chức năng
|
|
571
|
+
* - Cập nhật giá trị tại một key hoặc nested key trong database.
|
|
572
|
+
* - Tự động tạo object trung gian nếu đường dẫn chưa tồn tại.
|
|
573
|
+
* - 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ó.
|
|
574
|
+
*
|
|
575
|
+
* ## Mô tả hoạt động
|
|
576
|
+
* Hàm sẽ đọc toàn bộ dữ liệu database, tìm đến vị trí tương ứng với `key`
|
|
577
|
+
* và cập nhật giá trị mới theo các quy tắc sau:
|
|
524
578
|
*
|
|
525
|
-
*
|
|
526
|
-
* Nếu
|
|
527
|
-
*
|
|
579
|
+
* - **Đối với Array**
|
|
580
|
+
* - Nếu cả giá trị hiện tại và giá trị mới đều là mảng thì sẽ **không ghi đè**.
|
|
581
|
+
* - Các phần tử mới sẽ được thêm vào cuối mảng.
|
|
582
|
+
* - 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:
|
|
583
|
+
* - `username`
|
|
584
|
+
* - `guild`
|
|
585
|
+
* - Đ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.
|
|
528
586
|
*
|
|
529
|
-
*
|
|
587
|
+
* - **Đối với Object**
|
|
588
|
+
* - Nếu cả hai đều là object sẽ thực hiện **shallow merge** (`...old, ...new`).
|
|
589
|
+
* - Các thuộc tính mới sẽ ghi đè thuộc tính cùng tên.
|
|
590
|
+
* - Những thuộc tính khác vẫn được giữ nguyên.
|
|
530
591
|
*
|
|
531
|
-
*
|
|
592
|
+
* - **Các kiểu dữ liệu khác**
|
|
593
|
+
* - Giá trị mới sẽ ghi đè hoàn toàn giá trị cũ.
|
|
532
594
|
*
|
|
533
|
-
*
|
|
534
|
-
* Hỗ trợ nested path dạng `"a.b.c"`.
|
|
595
|
+
* Sau khi cập nhật xong, toàn bộ database sẽ được ghi lại thông qua driver.
|
|
535
596
|
*
|
|
536
|
-
* @
|
|
597
|
+
* @template P
|
|
598
|
+
* Đường dẫn hợp lệ của object trong database.
|
|
599
|
+
*
|
|
600
|
+
* @param key
|
|
601
|
+
* Đường dẫn cần cập nhật.
|
|
602
|
+
*
|
|
603
|
+
* Hỗ trợ nested path:
|
|
604
|
+
* ```ts
|
|
605
|
+
* "guilds.123.settings.prefix"
|
|
606
|
+
* "users.456.profile.name"
|
|
607
|
+
* ```
|
|
608
|
+
*
|
|
609
|
+
* @param value
|
|
610
|
+
* Giá trị mới cần cập nhật.
|
|
537
611
|
*
|
|
538
612
|
* @returns
|
|
539
|
-
* Trả về giá trị cuối cùng sau khi
|
|
613
|
+
* Trả về giá trị cuối cùng sau khi được lưu vào database.
|
|
614
|
+
*
|
|
615
|
+
* ## Cách sử dụng
|
|
616
|
+
*
|
|
617
|
+
* ### Ví dụ 1 - Cập nhật object
|
|
540
618
|
*
|
|
541
|
-
* @example
|
|
542
619
|
* Database ban đầu:
|
|
543
620
|
* ```json
|
|
544
621
|
* {
|
|
@@ -550,10 +627,9 @@ var _Database = class _Database {
|
|
|
550
627
|
* }
|
|
551
628
|
* ```
|
|
552
629
|
*
|
|
553
|
-
* Cập nhật:
|
|
554
630
|
* ```ts
|
|
555
631
|
* await db.update("123", {
|
|
556
|
-
*
|
|
632
|
+
* history: [1, 2, 3]
|
|
557
633
|
* });
|
|
558
634
|
* ```
|
|
559
635
|
*
|
|
@@ -563,14 +639,120 @@ var _Database = class _Database {
|
|
|
563
639
|
* "123": {
|
|
564
640
|
* "guildID": "123",
|
|
565
641
|
* "guildName": "BlackCat",
|
|
566
|
-
* "history": [1,2,3]
|
|
642
|
+
* "history": [1, 2, 3]
|
|
643
|
+
* }
|
|
644
|
+
* }
|
|
645
|
+
* ```
|
|
646
|
+
*
|
|
647
|
+
* ---
|
|
648
|
+
*
|
|
649
|
+
* ### Ví dụ 2 - Cập nhật nested key
|
|
650
|
+
*
|
|
651
|
+
* ```ts
|
|
652
|
+
* await db.update("guilds.123.settings.prefix", "!");
|
|
653
|
+
* ```
|
|
654
|
+
*
|
|
655
|
+
* Nếu đường dẫn chưa tồn tại:
|
|
656
|
+
*
|
|
657
|
+
* ```json
|
|
658
|
+
* {}
|
|
659
|
+
* ```
|
|
660
|
+
*
|
|
661
|
+
* Sau khi cập nhật:
|
|
662
|
+
*
|
|
663
|
+
* ```json
|
|
664
|
+
* {
|
|
665
|
+
* "guilds": {
|
|
666
|
+
* "123": {
|
|
667
|
+
* "settings": {
|
|
668
|
+
* "prefix": "!"
|
|
669
|
+
* }
|
|
670
|
+
* }
|
|
567
671
|
* }
|
|
568
672
|
* }
|
|
569
673
|
* ```
|
|
570
674
|
*
|
|
675
|
+
* ---
|
|
676
|
+
*
|
|
677
|
+
* ### Ví dụ 3 - Merge object
|
|
678
|
+
*
|
|
679
|
+
* Giá trị hiện tại:
|
|
680
|
+
*
|
|
681
|
+
* ```json
|
|
682
|
+
* {
|
|
683
|
+
* "name": "BlackCat",
|
|
684
|
+
* "language": "vi",
|
|
685
|
+
* "prefix": "!"
|
|
686
|
+
* }
|
|
687
|
+
* ```
|
|
688
|
+
*
|
|
689
|
+
* ```ts
|
|
690
|
+
* await db.update("config", {
|
|
691
|
+
* prefix: "?",
|
|
692
|
+
* color: "#5865F2"
|
|
693
|
+
* });
|
|
694
|
+
* ```
|
|
695
|
+
*
|
|
696
|
+
* Kết quả:
|
|
697
|
+
*
|
|
698
|
+
* ```json
|
|
699
|
+
* {
|
|
700
|
+
* "name": "BlackCat",
|
|
701
|
+
* "language": "vi",
|
|
702
|
+
* "prefix": "?",
|
|
703
|
+
* "color": "#5865F2"
|
|
704
|
+
* }
|
|
705
|
+
* ```
|
|
706
|
+
*
|
|
707
|
+
* ---
|
|
708
|
+
*
|
|
709
|
+
* ### Ví dụ 4 - Merge mảng và loại bỏ phần tử trùng
|
|
710
|
+
*
|
|
711
|
+
* Giá trị hiện tại:
|
|
712
|
+
*
|
|
713
|
+
* ```json
|
|
714
|
+
* [
|
|
715
|
+
* {
|
|
716
|
+
* "username": "Alice",
|
|
717
|
+
* "guild": "123"
|
|
718
|
+
* }
|
|
719
|
+
* ]
|
|
720
|
+
* ```
|
|
721
|
+
*
|
|
722
|
+
* ```ts
|
|
723
|
+
* await db.update("history", [
|
|
724
|
+
* {
|
|
725
|
+
* username: "Alice",
|
|
726
|
+
* guild: "123"
|
|
727
|
+
* },
|
|
728
|
+
* {
|
|
729
|
+
* username: "Bob",
|
|
730
|
+
* guild: "123"
|
|
731
|
+
* }
|
|
732
|
+
* ]);
|
|
733
|
+
* ```
|
|
734
|
+
*
|
|
735
|
+
* Kết quả:
|
|
736
|
+
*
|
|
737
|
+
* ```json
|
|
738
|
+
* [
|
|
739
|
+
* {
|
|
740
|
+
* "username": "Alice",
|
|
741
|
+
* "guild": "123"
|
|
742
|
+
* },
|
|
743
|
+
* {
|
|
744
|
+
* "username": "Bob",
|
|
745
|
+
* "guild": "123"
|
|
746
|
+
* }
|
|
747
|
+
* ]
|
|
748
|
+
* ```
|
|
749
|
+
*
|
|
750
|
+
* Phần tử `"Alice"` sẽ không được thêm lần nữa vì đã tồn tại với cùng
|
|
751
|
+
* `username` và `guild`.
|
|
752
|
+
*
|
|
571
753
|
* @throws {BlackCatError}
|
|
572
|
-
* - `REQUIRED_PARAMETER_MISSING` nếu
|
|
573
|
-
* - `INVALID_TYPE` nếu key không phải string
|
|
754
|
+
* - `REQUIRED_PARAMETER_MISSING` nếu không truyền `key`.
|
|
755
|
+
* - `INVALID_TYPE` nếu `key` không phải kiểu `string`.
|
|
574
756
|
*/
|
|
575
757
|
async update(key, value) {
|
|
576
758
|
if (!key) {
|
|
@@ -590,9 +772,13 @@ var _Database = class _Database {
|
|
|
590
772
|
current = current[part];
|
|
591
773
|
}
|
|
592
774
|
const lastKey = keys[keys.length - 1];
|
|
593
|
-
|
|
775
|
+
const currentValue = current[lastKey];
|
|
776
|
+
if (Array.isArray(value) && Array.isArray(currentValue)) {
|
|
777
|
+
const unique = value.filter((item) => !currentValue.some((existing) => existing.username === item.username && existing.guild === item.guild));
|
|
778
|
+
current[lastKey] = [...currentValue, ...unique];
|
|
779
|
+
} else if (isObject(value) && isObject(currentValue)) {
|
|
594
780
|
current[lastKey] = {
|
|
595
|
-
...
|
|
781
|
+
...currentValue,
|
|
596
782
|
...value
|
|
597
783
|
};
|
|
598
784
|
} else {
|
|
@@ -601,6 +787,114 @@ var _Database = class _Database {
|
|
|
601
787
|
await this.driver.set(allDatabase);
|
|
602
788
|
return current[lastKey];
|
|
603
789
|
}
|
|
790
|
+
/**
|
|
791
|
+
* ## Đồng bộ dữ liệu với cơ sở dữ liệu
|
|
792
|
+
*
|
|
793
|
+
* ### Chức năng
|
|
794
|
+
* Đồng bộ dữ liệu tại một đường dẫn (`keys`) với giá trị mới (`value`).
|
|
795
|
+
*
|
|
796
|
+
* Hàm sẽ tự động:
|
|
797
|
+
* - Tạo mới dữ liệu nếu chưa tồn tại.
|
|
798
|
+
* - So sánh dữ liệu cũ và mới.
|
|
799
|
+
* - Chỉ cập nhật các trường thực sự thay đổi đối với Object.
|
|
800
|
+
* - Không thực hiện ghi nếu dữ liệu không thay đổi.
|
|
801
|
+
*
|
|
802
|
+
* Đ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.
|
|
803
|
+
*
|
|
804
|
+
* ---
|
|
805
|
+
*
|
|
806
|
+
* ### Cơ chế hoạt động
|
|
807
|
+
*
|
|
808
|
+
* 1. Lấy dữ liệu hiện tại bằng `get()`.
|
|
809
|
+
* 2. Nếu chưa tồn tại (`undefined` hoặc `null`)
|
|
810
|
+
* → gọi `set()` để tạo mới.
|
|
811
|
+
* 3. Nếu truyền hàm `compare` và hàm này trả về `true`
|
|
812
|
+
* → bỏ qua đồng bộ.
|
|
813
|
+
* 4. Nếu dữ liệu không phải Object (hoặc là Array)
|
|
814
|
+
* → so sánh bằng `Object.is()`, nếu khác thì gọi `update()`.
|
|
815
|
+
* 5. Nếu dữ liệu là Object
|
|
816
|
+
* → chỉ lấy các thuộc tính thay đổi và cập nhật đúng các trường đó.
|
|
817
|
+
* 6. Nếu không có trường nào thay đổi thì không ghi dữ liệu.
|
|
818
|
+
*
|
|
819
|
+
* ---
|
|
820
|
+
*
|
|
821
|
+
* ### Giá trị trả về
|
|
822
|
+
*
|
|
823
|
+
* - `undefined`
|
|
824
|
+
* - Khi tạo mới dữ liệu.
|
|
825
|
+
* - Khi không có thay đổi.
|
|
826
|
+
* - Khi dữ liệu nguyên thủy được cập nhật.
|
|
827
|
+
* - `Partial<ObjectValue<V, P>>`
|
|
828
|
+
* - Trả về object chỉ chứa các trường đã được cập nhật khi đồng bộ Object.
|
|
829
|
+
*
|
|
830
|
+
* ---
|
|
831
|
+
*
|
|
832
|
+
* ### Ví dụ
|
|
833
|
+
*
|
|
834
|
+
* ```ts
|
|
835
|
+
* // Tạo mới nếu chưa tồn tại
|
|
836
|
+
* await db.syncDatabase({
|
|
837
|
+
* keys: "users.1",
|
|
838
|
+
* value: {
|
|
839
|
+
* name: "BlackCat",
|
|
840
|
+
* age: 20
|
|
841
|
+
* }
|
|
842
|
+
* });
|
|
843
|
+
*
|
|
844
|
+
* // Chỉ cập nhật trường age
|
|
845
|
+
* await db.syncDatabase({
|
|
846
|
+
* keys: "users.1",
|
|
847
|
+
* value: {
|
|
848
|
+
* name: "BlackCat",
|
|
849
|
+
* age: 21
|
|
850
|
+
* }
|
|
851
|
+
* });
|
|
852
|
+
*
|
|
853
|
+
* // Sử dụng compare để bỏ qua đồng bộ
|
|
854
|
+
* await db.syncDatabase({
|
|
855
|
+
* keys: "users.1",
|
|
856
|
+
* value: newData,
|
|
857
|
+
* compare(oldData, newData) {
|
|
858
|
+
* return oldData.version >= newData.version;
|
|
859
|
+
* }
|
|
860
|
+
* });
|
|
861
|
+
* ```
|
|
862
|
+
*
|
|
863
|
+
* @template P Đường dẫn tới dữ liệu trong cơ sở dữ liệu.
|
|
864
|
+
*
|
|
865
|
+
* @param options Thông tin đồng bộ.
|
|
866
|
+
* @param options.keys Đường dẫn của dữ liệu cần đồng bộ.
|
|
867
|
+
* @param options.value Giá trị mới cần ghi.
|
|
868
|
+
* @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ộ.
|
|
869
|
+
*
|
|
870
|
+
* @returns
|
|
871
|
+
* - `undefined` nếu không có thay đổi hoặc dữ liệu được tạo mới.
|
|
872
|
+
* - `Partial<ObjectValue<V, P>>` chứa các trường đã thay đổi khi cập nhật Object.
|
|
873
|
+
*/
|
|
874
|
+
async syncDatabase({ keys, value, compare }) {
|
|
875
|
+
const oldValue = await this.get(keys);
|
|
876
|
+
if (oldValue === void 0 || oldValue === null) {
|
|
877
|
+
await this.set(keys, value);
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
if (compare?.(oldValue, value)) return;
|
|
881
|
+
if (!isObject(oldValue) || !isObject(value) || Array.isArray(oldValue) || Array.isArray(value)) {
|
|
882
|
+
if (!Object.is(oldValue, value)) {
|
|
883
|
+
await this.update(keys, value);
|
|
884
|
+
}
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
const changed = {};
|
|
888
|
+
for (const k in value) {
|
|
889
|
+
const field = k;
|
|
890
|
+
if (!Object.is(oldValue[field], value[field])) {
|
|
891
|
+
changed[field] = value[field];
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
if (Object.keys(changed).length === 0) return;
|
|
895
|
+
await this.update(keys, changed);
|
|
896
|
+
return changed;
|
|
897
|
+
}
|
|
604
898
|
/**
|
|
605
899
|
* Cộng thêm giá trị vào một key dạng number.
|
|
606
900
|
*
|
|
@@ -629,7 +923,8 @@ var _Database = class _Database {
|
|
|
629
923
|
if (!isNumber(numberToAdd)) {
|
|
630
924
|
throw new BlackCatError("INVALID_TYPE", "numberToAdd", "number", typeOf(numberToAdd));
|
|
631
925
|
}
|
|
632
|
-
|
|
926
|
+
await this.set(key, targetNumber + numberToAdd);
|
|
927
|
+
return targetNumber + numberToAdd;
|
|
633
928
|
}
|
|
634
929
|
/**
|
|
635
930
|
* Trừ giá trị khỏi một key dạng number.
|
|
@@ -659,7 +954,48 @@ var _Database = class _Database {
|
|
|
659
954
|
if (!isNumber(numberToSubtract)) {
|
|
660
955
|
throw new BlackCatError("INVALID_TYPE", "numberToSubtract", "number", typeOf(numberToSubtract));
|
|
661
956
|
}
|
|
662
|
-
|
|
957
|
+
await this.set(key, targetNumber - numberToSubtract);
|
|
958
|
+
return targetNumber - numberToSubtract;
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Thêm một hoặc nhiều phần tử vào đầu array.
|
|
962
|
+
*
|
|
963
|
+
* Chỉ thêm những phần tử chưa tồn tại trong array.
|
|
964
|
+
*
|
|
965
|
+
* @typeParam P - Path trỏ tới array.
|
|
966
|
+
*
|
|
967
|
+
* @param key - Đường dẫn array.
|
|
968
|
+
* @param values - Một hoặc nhiều phần tử cần thêm.
|
|
969
|
+
*
|
|
970
|
+
* @returns Array sau khi thêm.
|
|
971
|
+
*
|
|
972
|
+
* @example
|
|
973
|
+
* await db.unshift("users", newUser);
|
|
974
|
+
*/
|
|
975
|
+
async unshift(key, ...values) {
|
|
976
|
+
if (!values.length) {
|
|
977
|
+
throw new BlackCatError("REQUIRED_PARAMETER_MISSING", "values");
|
|
978
|
+
}
|
|
979
|
+
const root = await this.all();
|
|
980
|
+
const pathParts = key.split(".");
|
|
981
|
+
let target = root;
|
|
982
|
+
for (let i = 0; i < pathParts.length; i++) {
|
|
983
|
+
const part = pathParts[i];
|
|
984
|
+
if (!(part in target)) {
|
|
985
|
+
throw new BlackCatError("INVALID_KEY", key);
|
|
986
|
+
}
|
|
987
|
+
if (i === pathParts.length - 1) {
|
|
988
|
+
if (!Array.isArray(target[part])) {
|
|
989
|
+
throw new BlackCatError("INVALID_TARGET", "array", typeOf(target[part]));
|
|
990
|
+
}
|
|
991
|
+
const uniqueValues = values.filter((v) => !target[part].includes(v));
|
|
992
|
+
target[part].unshift(...uniqueValues);
|
|
993
|
+
} else {
|
|
994
|
+
target = target[part];
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
await this.set(pathParts[0], root[pathParts[0]]);
|
|
998
|
+
return target[pathParts[pathParts.length - 1]];
|
|
663
999
|
}
|
|
664
1000
|
/**
|
|
665
1001
|
* Thêm một hoặc nhiều phần tử vào cuối array tại key-path.
|
|
@@ -877,7 +1213,8 @@ var _Database = class _Database {
|
|
|
877
1213
|
* const userKeys = await db.keys("user");
|
|
878
1214
|
*/
|
|
879
1215
|
async keys(key) {
|
|
880
|
-
|
|
1216
|
+
const all = await this.all();
|
|
1217
|
+
if (!key) return TypedObject.keys(all);
|
|
881
1218
|
const data = await this.get(key);
|
|
882
1219
|
return TypedObject.keys(data).filter((key2) => data[key2] !== void 0 && data[key2] !== null);
|
|
883
1220
|
}
|
|
@@ -911,7 +1248,8 @@ var _Database = class _Database {
|
|
|
911
1248
|
* const userValues = await db.values("users");
|
|
912
1249
|
*/
|
|
913
1250
|
async values(key) {
|
|
914
|
-
|
|
1251
|
+
const all = await this.all();
|
|
1252
|
+
if (!key) return TypedObject.values(all);
|
|
915
1253
|
const data = await this.get(key);
|
|
916
1254
|
return TypedObject.values(data);
|
|
917
1255
|
}
|
|
@@ -1036,12 +1374,21 @@ var _Database = class _Database {
|
|
|
1036
1374
|
return values.every(queryFunction);
|
|
1037
1375
|
}
|
|
1038
1376
|
};
|
|
1039
|
-
__name(_Database, "Database");
|
|
1040
|
-
var Database = _Database;
|
|
1041
1377
|
|
|
1042
1378
|
// src/drivers/JSONDriver.ts
|
|
1043
1379
|
var import_fs = require("fs");
|
|
1044
|
-
var
|
|
1380
|
+
var JSONDriver = class {
|
|
1381
|
+
static {
|
|
1382
|
+
__name(this, "JSONDriver");
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Đường dẫn tới file database JSON.
|
|
1386
|
+
*/
|
|
1387
|
+
filePath;
|
|
1388
|
+
/**
|
|
1389
|
+
* Cho biết có minify JSON khi ghi file hay không.
|
|
1390
|
+
*/
|
|
1391
|
+
minifyJSON;
|
|
1045
1392
|
/**
|
|
1046
1393
|
* Khởi tạo một instance mới của {@link JSONDriver}.
|
|
1047
1394
|
*
|
|
@@ -1063,14 +1410,6 @@ var _JSONDriver = class _JSONDriver {
|
|
|
1063
1410
|
* ```
|
|
1064
1411
|
*/
|
|
1065
1412
|
constructor(options) {
|
|
1066
|
-
/**
|
|
1067
|
-
* Đường dẫn tới file database JSON.
|
|
1068
|
-
*/
|
|
1069
|
-
__publicField(this, "filePath");
|
|
1070
|
-
/**
|
|
1071
|
-
* Cho biết có minify JSON khi ghi file hay không.
|
|
1072
|
-
*/
|
|
1073
|
-
__publicField(this, "minifyJSON");
|
|
1074
1413
|
this.filePath = options.filePath || "database.json";
|
|
1075
1414
|
this.minifyJSON = options.minifyJSON || false;
|
|
1076
1415
|
}
|
|
@@ -1131,11 +1470,16 @@ var _JSONDriver = class _JSONDriver {
|
|
|
1131
1470
|
return true;
|
|
1132
1471
|
}
|
|
1133
1472
|
};
|
|
1134
|
-
__name(_JSONDriver, "JSONDriver");
|
|
1135
|
-
var JSONDriver = _JSONDriver;
|
|
1136
1473
|
|
|
1137
1474
|
// src/drivers/MemoryDriver.ts
|
|
1138
|
-
var
|
|
1475
|
+
var MemoryDriver = class {
|
|
1476
|
+
static {
|
|
1477
|
+
__name(this, "MemoryDriver");
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* Object chứa toàn bộ dữ liệu database trong RAM.
|
|
1481
|
+
*/
|
|
1482
|
+
store;
|
|
1139
1483
|
/**
|
|
1140
1484
|
* Khởi tạo MemoryDriver.
|
|
1141
1485
|
*
|
|
@@ -1162,10 +1506,6 @@ var _MemoryDriver = class _MemoryDriver {
|
|
|
1162
1506
|
* ```
|
|
1163
1507
|
*/
|
|
1164
1508
|
constructor(initialData = {}) {
|
|
1165
|
-
/**
|
|
1166
|
-
* Object chứa toàn bộ dữ liệu database trong RAM.
|
|
1167
|
-
*/
|
|
1168
|
-
__publicField(this, "store");
|
|
1169
1509
|
this.store = initialData;
|
|
1170
1510
|
}
|
|
1171
1511
|
/**
|
|
@@ -1196,12 +1536,21 @@ var _MemoryDriver = class _MemoryDriver {
|
|
|
1196
1536
|
return true;
|
|
1197
1537
|
}
|
|
1198
1538
|
};
|
|
1199
|
-
__name(_MemoryDriver, "MemoryDriver");
|
|
1200
|
-
var MemoryDriver = _MemoryDriver;
|
|
1201
1539
|
|
|
1202
1540
|
// src/drivers/SQLiteDriver.ts
|
|
1203
1541
|
var import_better_sqlite3 = __toESM(require("better-sqlite3"));
|
|
1204
|
-
var
|
|
1542
|
+
var SQLiteDriver = class {
|
|
1543
|
+
static {
|
|
1544
|
+
__name(this, "SQLiteDriver");
|
|
1545
|
+
}
|
|
1546
|
+
/**
|
|
1547
|
+
* SQLite database instance.
|
|
1548
|
+
*/
|
|
1549
|
+
db;
|
|
1550
|
+
/**
|
|
1551
|
+
* Tên table lưu trữ dữ liệu JSON.
|
|
1552
|
+
*/
|
|
1553
|
+
table;
|
|
1205
1554
|
/**
|
|
1206
1555
|
* Khởi tạo SQLiteDriver.
|
|
1207
1556
|
*
|
|
@@ -1218,14 +1567,6 @@ var _SQLiteDriver = class _SQLiteDriver {
|
|
|
1218
1567
|
* ```
|
|
1219
1568
|
*/
|
|
1220
1569
|
constructor(options = {}) {
|
|
1221
|
-
/**
|
|
1222
|
-
* SQLite database instance.
|
|
1223
|
-
*/
|
|
1224
|
-
__publicField(this, "db");
|
|
1225
|
-
/**
|
|
1226
|
-
* Tên table lưu trữ dữ liệu JSON.
|
|
1227
|
-
*/
|
|
1228
|
-
__publicField(this, "table");
|
|
1229
1570
|
this.db = new import_better_sqlite3.default(options.filePath ?? "database.sqlite");
|
|
1230
1571
|
this.table = options.table ?? "json_store";
|
|
1231
1572
|
this.db.prepare(`CREATE TABLE IF NOT EXISTS ${this.table} (id INTEGER PRIMARY KEY, data TEXT)`).run();
|
|
@@ -1263,12 +1604,45 @@ var _SQLiteDriver = class _SQLiteDriver {
|
|
|
1263
1604
|
return true;
|
|
1264
1605
|
}
|
|
1265
1606
|
};
|
|
1266
|
-
__name(_SQLiteDriver, "SQLiteDriver");
|
|
1267
|
-
var SQLiteDriver = _SQLiteDriver;
|
|
1268
1607
|
|
|
1269
1608
|
// src/drivers/MongoDriver.ts
|
|
1270
1609
|
var import_mongodb = require("mongodb");
|
|
1271
|
-
var
|
|
1610
|
+
var MongoDriver = class {
|
|
1611
|
+
static {
|
|
1612
|
+
__name(this, "MongoDriver");
|
|
1613
|
+
}
|
|
1614
|
+
/**
|
|
1615
|
+
* MongoDB client instance.
|
|
1616
|
+
*/
|
|
1617
|
+
client;
|
|
1618
|
+
/**
|
|
1619
|
+
* MongoDB database instance.
|
|
1620
|
+
*/
|
|
1621
|
+
db;
|
|
1622
|
+
/**
|
|
1623
|
+
* Collection lưu dữ liệu JSON.
|
|
1624
|
+
*/
|
|
1625
|
+
collection;
|
|
1626
|
+
/**
|
|
1627
|
+
* Tên database MongoDB.
|
|
1628
|
+
*/
|
|
1629
|
+
databaseName;
|
|
1630
|
+
/**
|
|
1631
|
+
* Tên collection MongoDB.
|
|
1632
|
+
*/
|
|
1633
|
+
collectionName;
|
|
1634
|
+
/**
|
|
1635
|
+
* Callback khi kết nối thành công.
|
|
1636
|
+
*/
|
|
1637
|
+
onLoad;
|
|
1638
|
+
/**
|
|
1639
|
+
* Callback khi xảy ra lỗi.
|
|
1640
|
+
*/
|
|
1641
|
+
onError;
|
|
1642
|
+
/**
|
|
1643
|
+
* Trạng thái đã gọi onLoad chưa (tránh spam)
|
|
1644
|
+
*/
|
|
1645
|
+
isLoaded = false;
|
|
1272
1646
|
/**
|
|
1273
1647
|
* Khởi tạo MongoDriver.
|
|
1274
1648
|
*
|
|
@@ -1295,38 +1669,6 @@ var _MongoDriver = class _MongoDriver {
|
|
|
1295
1669
|
* });
|
|
1296
1670
|
*/
|
|
1297
1671
|
constructor(options = {}) {
|
|
1298
|
-
/**
|
|
1299
|
-
* MongoDB client instance.
|
|
1300
|
-
*/
|
|
1301
|
-
__publicField(this, "client");
|
|
1302
|
-
/**
|
|
1303
|
-
* MongoDB database instance.
|
|
1304
|
-
*/
|
|
1305
|
-
__publicField(this, "db");
|
|
1306
|
-
/**
|
|
1307
|
-
* Collection lưu dữ liệu JSON.
|
|
1308
|
-
*/
|
|
1309
|
-
__publicField(this, "collection");
|
|
1310
|
-
/**
|
|
1311
|
-
* Tên database MongoDB.
|
|
1312
|
-
*/
|
|
1313
|
-
__publicField(this, "databaseName");
|
|
1314
|
-
/**
|
|
1315
|
-
* Tên collection MongoDB.
|
|
1316
|
-
*/
|
|
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);
|
|
1330
1672
|
const {
|
|
1331
1673
|
mongourl = "mongodb://localhost:27017",
|
|
1332
1674
|
databaseName = "database",
|
|
@@ -1410,8 +1752,6 @@ var _MongoDriver = class _MongoDriver {
|
|
|
1410
1752
|
return true;
|
|
1411
1753
|
}
|
|
1412
1754
|
};
|
|
1413
|
-
__name(_MongoDriver, "MongoDriver");
|
|
1414
|
-
var MongoDriver = _MongoDriver;
|
|
1415
1755
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1416
1756
|
0 && (module.exports = {
|
|
1417
1757
|
Database,
|
|
@@ -1420,4 +1760,4 @@ var MongoDriver = _MongoDriver;
|
|
|
1420
1760
|
MongoDriver,
|
|
1421
1761
|
SQLiteDriver
|
|
1422
1762
|
});
|
|
1423
|
-
//# sourceMappingURL=index.
|
|
1763
|
+
//# sourceMappingURL=index.cjs.map
|