blackcat.js-database 1.0.0 → 1.0.2

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 CHANGED
@@ -1,9 +1,10 @@
1
- # blackcat.js-database
1
+ # 🐈‍⬛ blackcat.js-database
2
2
 
3
3
  Một **database nhẹ, typed và hỗ trợ autocomplete path cho TypeScript**.
4
4
 
5
5
  `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
6
 
7
+ > [Xem tài liệu ở đây](blackcat-js-database.vercel.app)
7
8
  ---
8
9
 
9
10
  # Tính năng
@@ -29,10 +30,12 @@ npm install blackcat.js-database
29
30
  # Khởi tạo Database
30
31
 
31
32
  ```ts
32
- import { Database, MemoryDriver } from "blackcat.js-database";
33
+ import { Database, JSONDriver } from "blackcat.js-database";
33
34
 
34
35
  const db = new Database({
35
- driver: new MemoryDriver()
36
+ driver: db = new JSONDriver({
37
+ filePath: "./database.json"
38
+ })
36
39
  });
37
40
  ```
38
41
 
@@ -53,7 +56,9 @@ type Schema = {
53
56
  };
54
57
 
55
58
  const db = new Database<Schema>({
56
- driver: new MemoryDriver()
59
+ driver: db = new JSONDriver({
60
+ filePath: "./database.json"
61
+ })
57
62
  });
58
63
  ```
59
64
 
@@ -80,6 +85,14 @@ Lấy toàn bộ database
80
85
  await db.get();
81
86
  ```
82
87
 
88
+ Lấy bằng điều kiện nhất định
89
+
90
+ ```ts
91
+ const data = await database.findOne("users", {
92
+ name: "username"
93
+ });
94
+ ```
95
+
83
96
  ---
84
97
 
85
98
  # Kiểm tra key tồn tại
@@ -118,6 +131,14 @@ Xóa toàn bộ database
118
131
  await db.deleteAll();
119
132
  ```
120
133
 
134
+ xóa bằng điều kiện nhất đinh
135
+
136
+ ```ts
137
+ const data = await database.deleteMany("member.user.database", {
138
+ name: "username"
139
+ })
140
+ ```
141
+
121
142
  ---
122
143
 
123
144
  # Number Operations
package/dist/index.d.mts CHANGED
@@ -61,7 +61,7 @@ interface DatabaseDriver {
61
61
  }
62
62
  /**
63
63
  * Cấu hình khởi tạo cho một instance của {@link Database}.
64
- * @hidden
64
+ * @hidden
65
65
  *
66
66
  * Interface này xác định các tùy chọn cần thiết để thiết lập database,
67
67
  * bao gồm driver lưu trữ và các tùy chọn hành vi bổ sung.
@@ -92,7 +92,7 @@ interface DatabaseConfiguration {
92
92
  }
93
93
  /**
94
94
  * Đại diện cho một giá trị có thể là `T` hoặc `null`.
95
- * @hidden
95
+ * @hidden
96
96
  *
97
97
  * Utility type này loại bỏ `undefined` khỏi union để đảm bảo
98
98
  * giá trị chỉ có thể là kiểu `T` hoặc `null`.
@@ -110,10 +110,14 @@ interface DatabaseConfiguration {
110
110
  * const invalid: Maybe<User> = undefined; // lỗi
111
111
  */
112
112
  type Maybe<T> = Exclude<T | null, undefined>;
113
+ /**
114
+ *
115
+ */
116
+ type ArrayElement<T> = T extends (infer U)[] ? U : T;
113
117
  /**
114
118
  * Utility type điều kiện dùng để trả về một kiểu dữ liệu
115
119
  * dựa trên giá trị boolean của điều kiện.
116
- * @hidden
120
+ * @hidden
117
121
  *
118
122
  * Nếu `T` là `true` thì kiểu trả về sẽ là `IfTrue`.
119
123
  * Nếu `T` là `false` thì kiểu trả về sẽ là `IfFalse`.
@@ -505,6 +509,43 @@ declare class Database<V = any> {
505
509
  * ```
506
510
  */
507
511
  get<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>): Promise<Maybe<ObjectValue<V, P>> | V>;
512
+ /**
513
+ * Tìm và trả về một bản ghi đầu tiên khớp với điều kiện trong database.
514
+ *
515
+ * Hàm này có hai cách sử dụng:
516
+ *
517
+ * 1. **Chỉ truyền `key`**
518
+ * → Trả về toàn bộ dữ liệu của key (tương tự `get()`).
519
+ *
520
+ * 2. **Truyền `key` và `query`**
521
+ * → 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.
522
+ *
523
+ * @template V - Kiểu dữ liệu của database.
524
+ * @template P - Đường dẫn key trong object (`ObjectPath<V>`).
525
+ *
526
+ * @param key - Key hoặc đường dẫn đến dữ liệu cần truy vấn.
527
+ * @param query - Đối tượng điều kiện để tìm bản ghi phù hợp.
528
+ *
529
+ * @returns
530
+ * - Nếu chỉ có `key`: trả về toàn bộ dữ liệu của key.
531
+ * - Nếu có `query`: trả về bản ghi đầu tiên khớp điều kiện.
532
+ * - Nếu không tìm thấy: trả về `null`.
533
+ *
534
+ * @example
535
+ * Chỉ lấy dữ liệu theo key
536
+ * ```ts
537
+ * const users = await db.findOne("user");
538
+ * ```
539
+ *
540
+ * @example
541
+ * Tìm một bản ghi theo điều kiện
542
+ * ```ts
543
+ * const user = await db.findOne("user", {
544
+ * guild: 1234566
545
+ * });
546
+ * ```
547
+ */
548
+ findOne<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>, query?: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<Maybe<ObjectValue<V, P>> | V>;
508
549
  /**
509
550
  * Kiểm tra một key-path có tồn tại trong database hay không.
510
551
  *
@@ -577,6 +618,50 @@ declare class Database<V = any> {
577
618
  * await db.deleteAll();
578
619
  */
579
620
  deleteAll(): Promise<boolean>;
621
+ /**
622
+ * 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.
623
+ *
624
+ * ⚠️ Method này **chỉ hoạt động với dữ liệu dạng mảng (array)**.
625
+ * 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**
626
+ * và trả về `0`.
627
+ *
628
+ * Method sẽ duyệt qua toàn bộ phần tử trong mảng và xóa những phần tử
629
+ * khớp với điều kiện `query`.
630
+ *
631
+ * @template V - Kiểu dữ liệu của database.
632
+ * @template P - Đường dẫn key trong object (`ObjectPath<V>`).
633
+ *
634
+ * @param key - Đường dẫn đến mảng dữ liệu cần thao tác.
635
+ * @param query - Điều kiện để xác định các phần tử cần xóa.
636
+ * Có thể truyền:
637
+ * - Một object điều kiện
638
+ *
639
+ * @returns Số lượng phần tử đã bị xóa khỏi mảng.
640
+ *
641
+ * @example
642
+ * Database mẫu:
643
+ * ```json
644
+ * {
645
+ * "member": {
646
+ * "user": {
647
+ * "database": [
648
+ * { "guild": "123", "username": "vinh" },
649
+ * { "guild": "456", "username": "test" }
650
+ * ]
651
+ * }
652
+ * }
653
+ * }
654
+ * ```
655
+ *
656
+ * @example
657
+ * Xóa tất cả user có guild = "123"
658
+ * ```ts
659
+ * await db.deleteMany("member.user.database", {
660
+ * guild: "123"
661
+ * });
662
+ * ```
663
+ */
664
+ deleteMany<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, query: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<number>;
580
665
  /**
581
666
  * Cập nhật giá trị của một key-path trong database.
582
667
  *
@@ -953,6 +1038,11 @@ declare class JSONDriver implements DatabaseDriver {
953
1038
  * ```
954
1039
  */
955
1040
  constructor(options: JSONDriverOptions);
1041
+ /**
1042
+ * Đảm bảo file database tồn tại.
1043
+ * Nếu file chưa tồn tại sẽ tự động tạo file `{}`.
1044
+ */
1045
+ private ensureFile;
956
1046
  /**
957
1047
  * Đọc toàn bộ dữ liệu từ file database JSON.
958
1048
  *
package/dist/index.d.ts CHANGED
@@ -61,7 +61,7 @@ interface DatabaseDriver {
61
61
  }
62
62
  /**
63
63
  * Cấu hình khởi tạo cho một instance của {@link Database}.
64
- * @hidden
64
+ * @hidden
65
65
  *
66
66
  * Interface này xác định các tùy chọn cần thiết để thiết lập database,
67
67
  * bao gồm driver lưu trữ và các tùy chọn hành vi bổ sung.
@@ -92,7 +92,7 @@ interface DatabaseConfiguration {
92
92
  }
93
93
  /**
94
94
  * Đại diện cho một giá trị có thể là `T` hoặc `null`.
95
- * @hidden
95
+ * @hidden
96
96
  *
97
97
  * Utility type này loại bỏ `undefined` khỏi union để đảm bảo
98
98
  * giá trị chỉ có thể là kiểu `T` hoặc `null`.
@@ -110,10 +110,14 @@ interface DatabaseConfiguration {
110
110
  * const invalid: Maybe<User> = undefined; // lỗi
111
111
  */
112
112
  type Maybe<T> = Exclude<T | null, undefined>;
113
+ /**
114
+ *
115
+ */
116
+ type ArrayElement<T> = T extends (infer U)[] ? U : T;
113
117
  /**
114
118
  * Utility type điều kiện dùng để trả về một kiểu dữ liệu
115
119
  * dựa trên giá trị boolean của điều kiện.
116
- * @hidden
120
+ * @hidden
117
121
  *
118
122
  * Nếu `T` là `true` thì kiểu trả về sẽ là `IfTrue`.
119
123
  * Nếu `T` là `false` thì kiểu trả về sẽ là `IfFalse`.
@@ -505,6 +509,43 @@ declare class Database<V = any> {
505
509
  * ```
506
510
  */
507
511
  get<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>): Promise<Maybe<ObjectValue<V, P>> | V>;
512
+ /**
513
+ * Tìm và trả về một bản ghi đầu tiên khớp với điều kiện trong database.
514
+ *
515
+ * Hàm này có hai cách sử dụng:
516
+ *
517
+ * 1. **Chỉ truyền `key`**
518
+ * → Trả về toàn bộ dữ liệu của key (tương tự `get()`).
519
+ *
520
+ * 2. **Truyền `key` và `query`**
521
+ * → 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.
522
+ *
523
+ * @template V - Kiểu dữ liệu của database.
524
+ * @template P - Đường dẫn key trong object (`ObjectPath<V>`).
525
+ *
526
+ * @param key - Key hoặc đường dẫn đến dữ liệu cần truy vấn.
527
+ * @param query - Đối tượng điều kiện để tìm bản ghi phù hợp.
528
+ *
529
+ * @returns
530
+ * - Nếu chỉ có `key`: trả về toàn bộ dữ liệu của key.
531
+ * - Nếu có `query`: trả về bản ghi đầu tiên khớp điều kiện.
532
+ * - Nếu không tìm thấy: trả về `null`.
533
+ *
534
+ * @example
535
+ * Chỉ lấy dữ liệu theo key
536
+ * ```ts
537
+ * const users = await db.findOne("user");
538
+ * ```
539
+ *
540
+ * @example
541
+ * Tìm một bản ghi theo điều kiện
542
+ * ```ts
543
+ * const user = await db.findOne("user", {
544
+ * guild: 1234566
545
+ * });
546
+ * ```
547
+ */
548
+ findOne<P extends AutocompletableString<ObjectPath<V>>>(key?: AutocompletableString<P>, query?: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<Maybe<ObjectValue<V, P>> | V>;
508
549
  /**
509
550
  * Kiểm tra một key-path có tồn tại trong database hay không.
510
551
  *
@@ -577,6 +618,50 @@ declare class Database<V = any> {
577
618
  * await db.deleteAll();
578
619
  */
579
620
  deleteAll(): Promise<boolean>;
621
+ /**
622
+ * 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.
623
+ *
624
+ * ⚠️ Method này **chỉ hoạt động với dữ liệu dạng mảng (array)**.
625
+ * 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**
626
+ * và trả về `0`.
627
+ *
628
+ * Method sẽ duyệt qua toàn bộ phần tử trong mảng và xóa những phần tử
629
+ * khớp với điều kiện `query`.
630
+ *
631
+ * @template V - Kiểu dữ liệu của database.
632
+ * @template P - Đường dẫn key trong object (`ObjectPath<V>`).
633
+ *
634
+ * @param key - Đường dẫn đến mảng dữ liệu cần thao tác.
635
+ * @param query - Điều kiện để xác định các phần tử cần xóa.
636
+ * Có thể truyền:
637
+ * - Một object điều kiện
638
+ *
639
+ * @returns Số lượng phần tử đã bị xóa khỏi mảng.
640
+ *
641
+ * @example
642
+ * Database mẫu:
643
+ * ```json
644
+ * {
645
+ * "member": {
646
+ * "user": {
647
+ * "database": [
648
+ * { "guild": "123", "username": "vinh" },
649
+ * { "guild": "456", "username": "test" }
650
+ * ]
651
+ * }
652
+ * }
653
+ * }
654
+ * ```
655
+ *
656
+ * @example
657
+ * Xóa tất cả user có guild = "123"
658
+ * ```ts
659
+ * await db.deleteMany("member.user.database", {
660
+ * guild: "123"
661
+ * });
662
+ * ```
663
+ */
664
+ deleteMany<P extends AutocompletableString<ObjectPath<V>>>(key: AutocompletableString<P>, query: Partial<ArrayElement<ObjectValue<V, P>>>): Promise<number>;
580
665
  /**
581
666
  * Cập nhật giá trị của một key-path trong database.
582
667
  *
@@ -953,6 +1038,11 @@ declare class JSONDriver implements DatabaseDriver {
953
1038
  * ```
954
1039
  */
955
1040
  constructor(options: JSONDriverOptions);
1041
+ /**
1042
+ * Đảm bảo file database tồn tại.
1043
+ * Nếu file chưa tồn tại sẽ tự động tạo file `{}`.
1044
+ */
1045
+ private ensureFile;
956
1046
  /**
957
1047
  * Đọc toàn bộ dữ liệu từ file database JSON.
958
1048
  *
package/dist/index.js CHANGED
@@ -247,6 +247,51 @@ var _Database = class _Database {
247
247
  }
248
248
  return result;
249
249
  }
250
+ /**
251
+ * Tìm và trả về một bản ghi đầu tiên khớp với điều kiện trong database.
252
+ *
253
+ * Hàm này có hai cách sử dụng:
254
+ *
255
+ * 1. **Chỉ truyền `key`**
256
+ * → Trả về toàn bộ dữ liệu của key (tương tự `get()`).
257
+ *
258
+ * 2. **Truyền `key` và `query`**
259
+ * → 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.
260
+ *
261
+ * @template V - Kiểu dữ liệu của database.
262
+ * @template P - Đường dẫn key trong object (`ObjectPath<V>`).
263
+ *
264
+ * @param key - Key hoặc đường dẫn đến dữ liệu cần truy vấn.
265
+ * @param query - Đối tượng điều kiện để tìm bản ghi phù hợp.
266
+ *
267
+ * @returns
268
+ * - Nếu chỉ có `key`: trả về toàn bộ dữ liệu của key.
269
+ * - Nếu có `query`: trả về bản ghi đầu tiên khớp điều kiện.
270
+ * - Nếu không tìm thấy: trả về `null`.
271
+ *
272
+ * @example
273
+ * Chỉ lấy dữ liệu theo key
274
+ * ```ts
275
+ * const users = await db.findOne("user");
276
+ * ```
277
+ *
278
+ * @example
279
+ * Tìm một bản ghi theo điều kiện
280
+ * ```ts
281
+ * const user = await db.findOne("user", {
282
+ * guild: 1234566
283
+ * });
284
+ * ```
285
+ */
286
+ async findOne(key, query) {
287
+ const data = await this.get(key);
288
+ if (!query) return data;
289
+ if (!Array.isArray(data)) return null;
290
+ const result = data.find((item) => {
291
+ return Object.entries(query).every(([k, v]) => item[k] == v);
292
+ });
293
+ return result ?? null;
294
+ }
250
295
  /**
251
296
  * Kiểm tra một key-path có tồn tại trong database hay không.
252
297
  *
@@ -367,6 +412,59 @@ var _Database = class _Database {
367
412
  await this.driver.delete();
368
413
  return true;
369
414
  }
415
+ /**
416
+ * 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.
417
+ *
418
+ * ⚠️ Method này **chỉ hoạt động với dữ liệu dạng mảng (array)**.
419
+ * 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**
420
+ * và trả về `0`.
421
+ *
422
+ * Method sẽ duyệt qua toàn bộ phần tử trong mảng và xóa những phần tử
423
+ * khớp với điều kiện `query`.
424
+ *
425
+ * @template V - Kiểu dữ liệu của database.
426
+ * @template P - Đường dẫn key trong object (`ObjectPath<V>`).
427
+ *
428
+ * @param key - Đường dẫn đến mảng dữ liệu cần thao tác.
429
+ * @param query - Điều kiện để xác định các phần tử cần xóa.
430
+ * Có thể truyền:
431
+ * - Một object điều kiện
432
+ *
433
+ * @returns Số lượng phần tử đã bị xóa khỏi mảng.
434
+ *
435
+ * @example
436
+ * Database mẫu:
437
+ * ```json
438
+ * {
439
+ * "member": {
440
+ * "user": {
441
+ * "database": [
442
+ * { "guild": "123", "username": "vinh" },
443
+ * { "guild": "456", "username": "test" }
444
+ * ]
445
+ * }
446
+ * }
447
+ * }
448
+ * ```
449
+ *
450
+ * @example
451
+ * Xóa tất cả user có guild = "123"
452
+ * ```ts
453
+ * await db.deleteMany("member.user.database", {
454
+ * guild: "123"
455
+ * });
456
+ * ```
457
+ */
458
+ async deleteMany(key, query) {
459
+ const data = await this.get(key);
460
+ if (!Array.isArray(data)) return 0;
461
+ const originalLength = data.length;
462
+ const filtered = data.filter((item) => {
463
+ return !Object.entries(query).every(([k, v]) => item[k] == v);
464
+ });
465
+ await this.set(key, filtered);
466
+ return originalLength - filtered.length;
467
+ }
370
468
  /**
371
469
  * Cập nhật giá trị của một key-path trong database.
372
470
  *
@@ -877,6 +975,17 @@ var _JSONDriver = class _JSONDriver {
877
975
  this.filePath = options.filePath || "database.json";
878
976
  this.minifyJSON = options.minifyJSON || false;
879
977
  }
978
+ /**
979
+ * Đảm bảo file database tồn tại.
980
+ * Nếu file chưa tồn tại sẽ tự động tạo file `{}`.
981
+ */
982
+ async ensureFile() {
983
+ try {
984
+ await import_fs.promises.access(this.filePath);
985
+ } catch {
986
+ await import_fs.promises.writeFile(this.filePath, "{}");
987
+ }
988
+ }
880
989
  /**
881
990
  * Đọc toàn bộ dữ liệu từ file database JSON.
882
991
  *
@@ -887,6 +996,7 @@ var _JSONDriver = class _JSONDriver {
887
996
  * @returns Promise chứa toàn bộ dữ liệu database.
888
997
  */
889
998
  async all() {
999
+ await this.ensureFile();
890
1000
  return import_fs.promises.readFile(this.filePath, "utf-8").then((content) => JSON.parse(content)).catch((error) => {
891
1001
  console.error(`Kh\xF4ng th\u1EC3 \u0111\u1ECDc file database: ${this.filePath}`, error);
892
1002
  return {};
@@ -905,6 +1015,7 @@ var _JSONDriver = class _JSONDriver {
905
1015
  * @returns Promise chứa dữ liệu đã ghi.
906
1016
  */
907
1017
  async set(data) {
1018
+ await this.ensureFile();
908
1019
  await import_fs.promises.writeFile(this.filePath, JSON.stringify(data, null, this.minifyJSON ? void 0 : " "));
909
1020
  return data;
910
1021
  }
@@ -916,6 +1027,7 @@ var _JSONDriver = class _JSONDriver {
916
1027
  * @returns `true` nếu reset thành công.
917
1028
  */
918
1029
  async delete() {
1030
+ await this.ensureFile();
919
1031
  await import_fs.promises.writeFile(this.filePath, "{}");
920
1032
  return true;
921
1033
  }