blackcat.js-database 1.0.0-test → 1.0.1
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 +414 -2
- package/dist/index.d.mts +1101 -458
- package/dist/index.d.ts +1101 -458
- package/dist/index.js +742 -456
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +728 -455
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -2
package/dist/index.mjs
CHANGED
|
@@ -110,170 +110,192 @@ import { EventEmitter } from "events";
|
|
|
110
110
|
|
|
111
111
|
// src/Database.ts
|
|
112
112
|
var _Database = class _Database {
|
|
113
|
+
/**
|
|
114
|
+
* Khởi tạo Database instance.
|
|
115
|
+
*
|
|
116
|
+
* @param options Cấu hình database.
|
|
117
|
+
* @param options.driver Driver lưu trữ dữ liệu.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* const db = new Database({
|
|
122
|
+
* driver: new JSONDriver({ filePath: "./database.json" }),
|
|
123
|
+
* })
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
* Ví dụ với MongoDB:
|
|
127
|
+
*
|
|
128
|
+
* ```ts
|
|
129
|
+
* const db = new Database({
|
|
130
|
+
* driver: new MongoDriver({
|
|
131
|
+
* uri: "mongodb://localhost:27017",
|
|
132
|
+
* databaseName: "mydb"
|
|
133
|
+
* })
|
|
134
|
+
* });
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
113
137
|
constructor(options) {
|
|
114
138
|
/**
|
|
115
|
-
*
|
|
139
|
+
* Storage driver được sử dụng để đọc và ghi dữ liệu database.
|
|
140
|
+
*
|
|
141
|
+
* Driver phải implement interface `DatabaseDriver`.
|
|
142
|
+
*
|
|
143
|
+
* Ví dụ:
|
|
144
|
+
* ```ts
|
|
145
|
+
* const db = new Database({
|
|
146
|
+
* driver: new JSONDriver({ filePath: "./database.json" }),
|
|
147
|
+
* })
|
|
148
|
+
* ```
|
|
116
149
|
*/
|
|
117
150
|
__publicField(this, "driver");
|
|
118
151
|
this.driver = options.driver;
|
|
119
152
|
}
|
|
120
153
|
/**
|
|
121
|
-
*
|
|
154
|
+
* Lấy toàn bộ dữ liệu từ database thông qua driver.
|
|
122
155
|
*
|
|
123
|
-
*
|
|
156
|
+
* @template T Kiểu dữ liệu object database trả về.
|
|
124
157
|
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* @returns {T} Cached database contents.
|
|
128
|
-
*
|
|
129
|
-
* @template T (object, defaults to `Record<string, any>`) -
|
|
130
|
-
* The type of object of all the database object to be returned.
|
|
158
|
+
* @returns Promise chứa toàn bộ dữ liệu database.
|
|
131
159
|
*
|
|
132
160
|
* @example
|
|
133
|
-
*
|
|
134
|
-
*
|
|
161
|
+
* ```ts
|
|
162
|
+
* const data = await db.all();
|
|
163
|
+
* console.log(data.users);
|
|
164
|
+
* ```
|
|
135
165
|
*/
|
|
136
166
|
async all() {
|
|
137
|
-
|
|
138
|
-
return allDatabase;
|
|
167
|
+
return await this.driver.all();
|
|
139
168
|
}
|
|
140
169
|
/**
|
|
141
|
-
*
|
|
170
|
+
* Lấy giá trị từ database theo key-path.
|
|
142
171
|
*
|
|
143
|
-
*
|
|
144
|
-
* @returns {Maybe<ObjectValue<V, P>>} The value of the target in database.
|
|
172
|
+
* Key có thể là chuỗi dạng path:
|
|
145
173
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
174
|
+
* ```
|
|
175
|
+
* user.profile.name
|
|
176
|
+
* economy.users.123.balance
|
|
177
|
+
* ```
|
|
178
|
+
*
|
|
179
|
+
* Nếu không truyền `key`, method sẽ trả về **toàn bộ database**.
|
|
180
|
+
*
|
|
181
|
+
* @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.
|
|
149
182
|
*
|
|
150
|
-
*
|
|
151
|
-
* console.log(databaseObjectPropertyAccessed); // -> "hello world!"
|
|
183
|
+
* @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần lấy.
|
|
152
184
|
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
185
|
+
* @returns Giá trị tại key hoặc `null` nếu không tồn tại.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```ts
|
|
189
|
+
* const name = await db.get("user.profile.name");
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```ts
|
|
194
|
+
* const all = await db.get();
|
|
195
|
+
* ```
|
|
162
196
|
*/
|
|
163
197
|
async get(key) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return this.driver.get(key);
|
|
169
|
-
} else {
|
|
170
|
-
return this.all();
|
|
198
|
+
const data = await this.all();
|
|
199
|
+
if (key === void 0) return data;
|
|
200
|
+
if (typeof key !== "string") {
|
|
201
|
+
throw new BlackCatError("INVALID_TYPE", "key", "string", typeOf(key));
|
|
171
202
|
}
|
|
172
|
-
;
|
|
203
|
+
const keys = key.split(".");
|
|
204
|
+
let result = data;
|
|
205
|
+
for (const k of keys) {
|
|
206
|
+
if (!isObject(result) && !Array.isArray(result)) return null;
|
|
207
|
+
result = result[k];
|
|
208
|
+
if (result === void 0) return null;
|
|
209
|
+
}
|
|
210
|
+
return result;
|
|
173
211
|
}
|
|
174
212
|
/**
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* - This method is an alias for {@link Database.get()} method.
|
|
213
|
+
* Tìm và trả về một bản ghi đầu tiên khớp với điều kiện trong database.
|
|
178
214
|
*
|
|
179
|
-
*
|
|
180
|
-
* @returns {Maybe<ObjectValue<V, P>>} The value from database.
|
|
215
|
+
* Hàm này có hai cách sử dụng:
|
|
181
216
|
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
* console.log(simpleValue); // -> 123
|
|
217
|
+
* 1. **Chỉ truyền `key`**
|
|
218
|
+
* → Trả về toàn bộ dữ liệu của key (tương tự `get()`).
|
|
185
219
|
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
* console.log(playerInventory); // -> []
|
|
220
|
+
* 2. **Truyền `key` và `query`**
|
|
221
|
+
* → 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.
|
|
189
222
|
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
* // simpleValue: 123,
|
|
193
|
-
* // player: {
|
|
194
|
-
* // inventory: []
|
|
195
|
-
* // }
|
|
196
|
-
* // }
|
|
197
|
-
*/
|
|
198
|
-
async fetch(key) {
|
|
199
|
-
return this.get(key);
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Determines if the data is stored in database.
|
|
203
|
-
* @param {AutocompletableString<P>} key The key to access the target in database by.
|
|
204
|
-
* @returns {boolean} Whether the data is stored in database.
|
|
223
|
+
* @template V - Kiểu dữ liệu của database.
|
|
224
|
+
* @template P - Đường dẫn key trong object (`ObjectPath<V>`).
|
|
205
225
|
*
|
|
206
|
-
* @
|
|
207
|
-
*
|
|
208
|
-
* console.log(isSimpleValueInDatabase); // -> true
|
|
226
|
+
* @param key - Key hoặc đường dẫn đến dữ liệu cần truy vấn.
|
|
227
|
+
* @param query - Đối tượng điều kiện để tìm bản ghi phù hợp.
|
|
209
228
|
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
229
|
+
* @returns
|
|
230
|
+
* - Nếu chỉ có `key`: trả về toàn bộ dữ liệu của key.
|
|
231
|
+
* - Nếu có `query`: trả về bản ghi đầu tiên khớp điều kiện.
|
|
232
|
+
* - Nếu không tìm thấy: trả về `null`.
|
|
212
233
|
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
234
|
+
* @example
|
|
235
|
+
* Chỉ lấy dữ liệu theo key
|
|
236
|
+
* ```ts
|
|
237
|
+
* const users = await db.findOne("user");
|
|
238
|
+
* ```
|
|
216
239
|
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
* // accessObjectProperties: {
|
|
225
|
-
* // likeThat: "hello world!"
|
|
226
|
-
* // }
|
|
227
|
-
* // }
|
|
228
|
-
* // }
|
|
240
|
+
* @example
|
|
241
|
+
* Tìm một bản ghi theo điều kiện
|
|
242
|
+
* ```ts
|
|
243
|
+
* const user = await db.findOne("user", {
|
|
244
|
+
* guild: 1234566
|
|
245
|
+
* });
|
|
246
|
+
* ```
|
|
229
247
|
*/
|
|
230
|
-
async
|
|
231
|
-
|
|
248
|
+
async findOne(key, query) {
|
|
249
|
+
const data = await this.get(key);
|
|
250
|
+
if (!query) return data;
|
|
251
|
+
if (!Array.isArray(data)) return null;
|
|
252
|
+
const result = data.find((item) => {
|
|
253
|
+
return Object.entries(query).every(([k, v]) => item[k] == v);
|
|
254
|
+
});
|
|
255
|
+
return result ?? null;
|
|
232
256
|
}
|
|
233
257
|
/**
|
|
234
|
-
*
|
|
258
|
+
* Kiểm tra một key-path có tồn tại trong database hay không.
|
|
235
259
|
*
|
|
236
|
-
*
|
|
237
|
-
* @param {ObjectValue<V, P>} value The value to write.
|
|
260
|
+
* Method này sử dụng `get()` để xác định giá trị có tồn tại.
|
|
238
261
|
*
|
|
239
|
-
* @
|
|
240
|
-
* - If the `value` parameter's type is not an object (string, number, boolean, etc), then the specified
|
|
241
|
-
* `value` parameter (type of `ObjectValue<V, P>`) will be returned.
|
|
262
|
+
* @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.
|
|
242
263
|
*
|
|
243
|
-
*
|
|
244
|
-
* (type of `FirstObjectKey<P>` - first object key (e.g. in key `member.user.id`, the first key will be `member`))
|
|
264
|
+
* @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần kiểm tra.
|
|
245
265
|
*
|
|
246
|
-
* @
|
|
247
|
-
* // Assuming that the initial database object for this example is empty.
|
|
266
|
+
* @returns `true` nếu key tồn tại, ngược lại `false`.
|
|
248
267
|
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```ts
|
|
270
|
+
* const exists = await db.has("users.123");
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
273
|
+
async has(key) {
|
|
274
|
+
const value = await this.get(key);
|
|
275
|
+
return value !== null && value !== void 0;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Gán giá trị cho một key-path trong database.
|
|
251
279
|
*
|
|
252
|
-
*
|
|
280
|
+
* Nếu key-path chưa tồn tại, các object trung gian
|
|
281
|
+
* sẽ được tự động tạo.
|
|
253
282
|
*
|
|
254
|
-
*
|
|
255
|
-
* const dotNotationSetResult = await database.set("member.user.id", 2000);
|
|
256
|
-
* console.log(dotNotationSetResult); // -> 2000
|
|
283
|
+
* @template {AutocompletableString<ObjectPath<V>>} P Key path trong database.
|
|
257
284
|
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
285
|
+
* @param {AutocompletableString<P>} key Đường dẫn dữ liệu cần gán giá trị.
|
|
286
|
+
* @param {ObjectValue<V, P>} value Giá trị mới.
|
|
260
287
|
*
|
|
261
|
-
*
|
|
288
|
+
* @returns {Promise<If<IsObject<V>, ObjectValue<V, FirstObjectKey<P>>, V>>} Giá trị vừa được set hoặc object root nếu value là object.
|
|
262
289
|
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```ts
|
|
292
|
+
* await db.set("users.123.name", "Alice");
|
|
293
|
+
* ```
|
|
265
294
|
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
* // "inventory": [],
|
|
271
|
-
* // "user": {
|
|
272
|
-
* // "name": "Jerry",
|
|
273
|
-
* // "id": 2000
|
|
274
|
-
* // }
|
|
275
|
-
* // }
|
|
276
|
-
* // }
|
|
295
|
+
* @example
|
|
296
|
+
* ```ts
|
|
297
|
+
* await db.set("config.prefix", "!");
|
|
298
|
+
* ```
|
|
277
299
|
*/
|
|
278
300
|
async set(key, value) {
|
|
279
301
|
const allDatabase = await this.all();
|
|
@@ -297,21 +319,134 @@ var _Database = class _Database {
|
|
|
297
319
|
;
|
|
298
320
|
}
|
|
299
321
|
;
|
|
300
|
-
await this.driver.set(
|
|
322
|
+
await this.driver.set(allDatabase);
|
|
301
323
|
return typeof value == "object" && value !== null ? await this.get(keys[0]) : value;
|
|
302
324
|
}
|
|
303
325
|
/**
|
|
304
|
-
*
|
|
326
|
+
* Xóa một key khỏi database.
|
|
327
|
+
*
|
|
328
|
+
* Hỗ trợ nested path bằng dot notation.
|
|
329
|
+
*
|
|
330
|
+
* @typeParam P - Path của object.
|
|
331
|
+
*
|
|
332
|
+
* @param key - Đường dẫn key cần xóa.
|
|
333
|
+
*
|
|
334
|
+
* @returns
|
|
335
|
+
* - `true` nếu xóa thành công
|
|
336
|
+
* - `false` nếu key không tồn tại
|
|
337
|
+
*
|
|
338
|
+
* @throws BlackCatError
|
|
339
|
+
* - INVALID_TYPE nếu key không phải string
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* await db.delete("user.name");
|
|
343
|
+
*/
|
|
344
|
+
async delete(key) {
|
|
345
|
+
if (typeof key !== "string") {
|
|
346
|
+
throw new BlackCatError("INVALID_TYPE", "key", "string", typeof key);
|
|
347
|
+
}
|
|
348
|
+
const allDatabase = await this.all();
|
|
349
|
+
const keys = key.split(".");
|
|
350
|
+
const lastKey = keys.pop();
|
|
351
|
+
let currentObj = allDatabase;
|
|
352
|
+
for (const k of keys) {
|
|
353
|
+
if (!isObject(currentObj[k])) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
currentObj = currentObj[k];
|
|
357
|
+
}
|
|
358
|
+
if (!(lastKey in currentObj)) return false;
|
|
359
|
+
delete currentObj[lastKey];
|
|
360
|
+
await this.driver.set(allDatabase);
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Xóa toàn bộ dữ liệu trong database.
|
|
365
|
+
*
|
|
366
|
+
* Method này gọi trực tiếp `driver.delete()` để reset storage.
|
|
367
|
+
*
|
|
368
|
+
* @returns `true` sau khi dữ liệu đã được xóa.
|
|
369
|
+
*
|
|
370
|
+
* @example
|
|
371
|
+
* await db.deleteAll();
|
|
372
|
+
*/
|
|
373
|
+
async deleteAll() {
|
|
374
|
+
await this.driver.delete();
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* 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.
|
|
379
|
+
*
|
|
380
|
+
* ⚠️ Method này **chỉ hoạt động với dữ liệu dạng mảng (array)**.
|
|
381
|
+
* 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**
|
|
382
|
+
* và trả về `0`.
|
|
305
383
|
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
384
|
+
* Method sẽ duyệt qua toàn bộ phần tử trong mảng và xóa những phần tử
|
|
385
|
+
* khớp với điều kiện `query`.
|
|
308
386
|
*
|
|
309
|
-
* @
|
|
310
|
-
*
|
|
311
|
-
* `value` parameter (type of `ObjectValue<V, P>`) will be returned.
|
|
387
|
+
* @template V - Kiểu dữ liệu của database.
|
|
388
|
+
* @template P - Đường dẫn key trong object (`ObjectPath<V>`).
|
|
312
389
|
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
390
|
+
* @param key - Đường dẫn đến mảng dữ liệu cần thao tác.
|
|
391
|
+
* @param query - Điều kiện để xác định các phần tử cần xóa.
|
|
392
|
+
* Có thể truyền:
|
|
393
|
+
* - Một object điều kiện
|
|
394
|
+
*
|
|
395
|
+
* @returns Số lượng phần tử đã bị xóa khỏi mảng.
|
|
396
|
+
*
|
|
397
|
+
* @example
|
|
398
|
+
* Database mẫu:
|
|
399
|
+
* ```json
|
|
400
|
+
* {
|
|
401
|
+
* "member": {
|
|
402
|
+
* "user": {
|
|
403
|
+
* "database": [
|
|
404
|
+
* { "guild": "123", "username": "vinh" },
|
|
405
|
+
* { "guild": "456", "username": "test" }
|
|
406
|
+
* ]
|
|
407
|
+
* }
|
|
408
|
+
* }
|
|
409
|
+
* }
|
|
410
|
+
* ```
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* Xóa tất cả user có guild = "123"
|
|
414
|
+
* ```ts
|
|
415
|
+
* await db.deleteMany("member.user.database", {
|
|
416
|
+
* guild: "123"
|
|
417
|
+
* });
|
|
418
|
+
* ```
|
|
419
|
+
*/
|
|
420
|
+
async deleteMany(key, query) {
|
|
421
|
+
const data = await this.get(key);
|
|
422
|
+
if (!Array.isArray(data)) return 0;
|
|
423
|
+
const originalLength = data.length;
|
|
424
|
+
const filtered = data.filter((item) => {
|
|
425
|
+
return !Object.entries(query).every(([k, v]) => item[k] == v);
|
|
426
|
+
});
|
|
427
|
+
await this.set(key, filtered);
|
|
428
|
+
return originalLength - filtered.length;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Cập nhật giá trị của một key-path trong database.
|
|
432
|
+
*
|
|
433
|
+
* Khác với `set()`, method này chỉ ghi đè giá trị của key cuối cùng
|
|
434
|
+
* trong path mà không thay đổi cấu trúc object phía trên.
|
|
435
|
+
*
|
|
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.
|
|
438
|
+
*
|
|
439
|
+
* @template P Key path trong database.
|
|
440
|
+
*
|
|
441
|
+
* @param key Đường dẫn dữ liệu cần cập nhật.
|
|
442
|
+
* @param value Giá trị mới.
|
|
443
|
+
*
|
|
444
|
+
* @returns Object cha của key vừa cập nhật.
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```ts
|
|
448
|
+
* await db.update("users.123.name", "Alice");
|
|
449
|
+
* ```
|
|
315
450
|
*/
|
|
316
451
|
async update(key, value) {
|
|
317
452
|
const allDatabase = await this.all();
|
|
@@ -326,34 +461,25 @@ var _Database = class _Database {
|
|
|
326
461
|
}
|
|
327
462
|
const lastKey = keys[keys.length - 1];
|
|
328
463
|
current[lastKey] = value;
|
|
329
|
-
await this.driver.set(
|
|
464
|
+
await this.driver.set(allDatabase);
|
|
330
465
|
return current;
|
|
331
466
|
}
|
|
332
467
|
/**
|
|
333
|
-
*
|
|
468
|
+
* Cộng thêm giá trị vào một key dạng number.
|
|
334
469
|
*
|
|
335
|
-
*
|
|
470
|
+
* Nếu key chưa tồn tại, giá trị mặc định sẽ là `0`.
|
|
336
471
|
*
|
|
337
|
-
* @
|
|
338
|
-
* @param {number} numberToAdd The number to add to the target number in database.
|
|
339
|
-
* @returns {Promise<number>} Addition operation result.
|
|
472
|
+
* @template P Key path trong database.
|
|
340
473
|
*
|
|
341
|
-
* @
|
|
342
|
-
*
|
|
343
|
-
* console.log(additionResult); // -> 10 (5 + 5 = 10)
|
|
474
|
+
* @param key Đường dẫn dữ liệu dạng number.
|
|
475
|
+
* @param numberToAdd Số cần cộng thêm.
|
|
344
476
|
*
|
|
345
|
-
*
|
|
346
|
-
* // before performing an addition since the initial target value is 0 and will be used
|
|
347
|
-
* // as the value of the unexistent property:
|
|
348
|
-
* const unexistentAdditionResult = await database.add("somethingElse", 3);
|
|
477
|
+
* @returns Giá trị mới sau khi cộng.
|
|
349
478
|
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
* // {
|
|
355
|
-
* // points: 5
|
|
356
|
-
* // }
|
|
479
|
+
* @example
|
|
480
|
+
* ```ts
|
|
481
|
+
* await db.add("economy.users.123.balance", 50);
|
|
482
|
+
* ```
|
|
357
483
|
*/
|
|
358
484
|
async add(key, numberToAdd) {
|
|
359
485
|
const targetNumber = await this.get(key) ?? 0;
|
|
@@ -369,30 +495,21 @@ var _Database = class _Database {
|
|
|
369
495
|
return await this.set(key, targetNumber + numberToAdd);
|
|
370
496
|
}
|
|
371
497
|
/**
|
|
372
|
-
*
|
|
498
|
+
* Trừ giá trị khỏi một key dạng number.
|
|
373
499
|
*
|
|
374
|
-
*
|
|
500
|
+
* Nếu key chưa tồn tại, giá trị mặc định sẽ là `0`.
|
|
375
501
|
*
|
|
376
|
-
* @
|
|
377
|
-
* @param {number} numberToSubtract The number to subtract from the target number in database.
|
|
378
|
-
* @returns {Promise<number>} Subtraction operation result.
|
|
502
|
+
* @template P Key path trong database.
|
|
379
503
|
*
|
|
380
|
-
* @
|
|
381
|
-
*
|
|
382
|
-
* console.log(subtractionResult) // -> 5 (10 - 5 = 5)
|
|
504
|
+
* @param key Đường dẫn dữ liệu dạng number.
|
|
505
|
+
* @param numberToSubtract Số cần trừ.
|
|
383
506
|
*
|
|
384
|
-
*
|
|
385
|
-
* // before performing a subtraction since the initial target value is 0 and will be used
|
|
386
|
-
* // as the value of the unexistent property:
|
|
387
|
-
* const unexistentSubtractionitionResult = await database.subtract("somethingElse", 3)
|
|
507
|
+
* @returns Giá trị mới sau khi trừ.
|
|
388
508
|
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
* // {
|
|
394
|
-
* // points: 10
|
|
395
|
-
* // }
|
|
509
|
+
* @example
|
|
510
|
+
* ```ts
|
|
511
|
+
* await db.subtract("economy.users.123.balance", 20);
|
|
512
|
+
* ```
|
|
396
513
|
*/
|
|
397
514
|
async subtract(key, numberToSubtract) {
|
|
398
515
|
const targetNumber = await this.get(key) ?? 0;
|
|
@@ -408,27 +525,31 @@ var _Database = class _Database {
|
|
|
408
525
|
return await this.set(key, targetNumber - numberToSubtract);
|
|
409
526
|
}
|
|
410
527
|
/**
|
|
411
|
-
*
|
|
528
|
+
* Thêm một hoặc nhiều phần tử vào cuối array tại key-path.
|
|
412
529
|
*
|
|
413
|
-
*
|
|
414
|
-
*
|
|
530
|
+
* Method này sẽ:
|
|
531
|
+
* - kiểm tra target có phải array không
|
|
532
|
+
* - chỉ thêm các giá trị **chưa tồn tại** trong array
|
|
415
533
|
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
* The value(s) to be pushed into the target array in database.
|
|
534
|
+
* ⚠️ Nếu key không tồn tại hoặc target không phải array
|
|
535
|
+
* thì sẽ ném lỗi.
|
|
419
536
|
*
|
|
420
|
-
* @
|
|
537
|
+
* @template P Key path trong database.
|
|
538
|
+
*
|
|
539
|
+
* @param key Đường dẫn tới array cần thêm phần tử.
|
|
540
|
+
* @param values Một hoặc nhiều giá trị cần thêm.
|
|
541
|
+
*
|
|
542
|
+
* @returns Array sau khi thêm phần tử.
|
|
421
543
|
*
|
|
422
544
|
* @example
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
545
|
+
* ```ts
|
|
546
|
+
* await db.push("users.123.roles", "admin");
|
|
547
|
+
* ```
|
|
426
548
|
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
* // }
|
|
549
|
+
* @example
|
|
550
|
+
* ```ts
|
|
551
|
+
* await db.push("queue.songs", song1, song2);
|
|
552
|
+
* ```
|
|
432
553
|
*/
|
|
433
554
|
async push(key, ...values) {
|
|
434
555
|
if (!values.length) {
|
|
@@ -458,23 +579,25 @@ var _Database = class _Database {
|
|
|
458
579
|
return target[pathParts[pathParts.length - 1]];
|
|
459
580
|
}
|
|
460
581
|
/**
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
582
|
+
* Thay thế phần tử trong array theo index.
|
|
583
|
+
*
|
|
584
|
+
* @typeParam P - Path trỏ đến array.
|
|
585
|
+
*
|
|
586
|
+
* @param key - Đường dẫn array.
|
|
587
|
+
* @param targetArrayElementIndex - Index cần thay.
|
|
588
|
+
* @param value - Giá trị mới.
|
|
589
|
+
*
|
|
590
|
+
* @returns Array sau khi thay thế.
|
|
591
|
+
*
|
|
592
|
+
* @throws BlackCatError
|
|
593
|
+
* - INVALID_TYPE nếu index không phải number
|
|
594
|
+
* - REQUIRED_PARAMETER_MISSING nếu thiếu value
|
|
595
|
+
* - INVALID_KEY nếu path không tồn tại
|
|
596
|
+
* - INVALID_TARGET nếu target không phải array
|
|
597
|
+
*
|
|
598
|
+
* @example
|
|
599
|
+
* await db.pull("users", 0, { id: 2 });
|
|
600
|
+
*/
|
|
478
601
|
async pull(key, targetArrayElementIndex, value) {
|
|
479
602
|
if (!isNumber(targetArrayElementIndex)) {
|
|
480
603
|
throw new BlackCatError("INVALID_TYPE", "targetArrayElementIndex", "number", typeOf(targetArrayElementIndex));
|
|
@@ -514,26 +637,25 @@ var _Database = class _Database {
|
|
|
514
637
|
return target[pathParts[pathParts.length - 1]];
|
|
515
638
|
}
|
|
516
639
|
/**
|
|
517
|
-
*
|
|
640
|
+
* Xóa phần tử khỏi array theo index.
|
|
518
641
|
*
|
|
519
|
-
*
|
|
642
|
+
* Có thể truyền nhiều index hoặc một array index.
|
|
520
643
|
*
|
|
521
|
-
* @
|
|
522
|
-
* @param {RestOrArray<ExtractFromArray<number>>} targetArrayElementIndexes
|
|
523
|
-
* The index(es) to find the element(s) in target array by.
|
|
644
|
+
* @typeParam P - Path trỏ đến array.
|
|
524
645
|
*
|
|
525
|
-
* @
|
|
646
|
+
* @param key - Đường dẫn array.
|
|
647
|
+
* @param targetArrayElementIndexes - Các index cần xóa.
|
|
526
648
|
*
|
|
527
|
-
* @
|
|
528
|
-
* console.log(await database.pop("members", 1)); // -> ["Jerry", "Tom"]
|
|
649
|
+
* @returns Danh sách phần tử đã bị xóa.
|
|
529
650
|
*
|
|
530
|
-
*
|
|
651
|
+
* @throws BlackCatError
|
|
652
|
+
* - INVALID_TARGET nếu target không phải array
|
|
653
|
+
* - REQUIRED_PARAMETER_MISSING nếu thiếu index
|
|
654
|
+
* - ONE_OR_MORE_ARRAY_TYPES_INVALID nếu index không phải number
|
|
531
655
|
*
|
|
532
|
-
*
|
|
533
|
-
*
|
|
534
|
-
*
|
|
535
|
-
* // currencies: ["VND", "USD", "Euro"]
|
|
536
|
-
* // }
|
|
656
|
+
* @example
|
|
657
|
+
* await db.pop("users", 0);
|
|
658
|
+
* await db.pop("numbers", [1, 2, 3]);
|
|
537
659
|
*/
|
|
538
660
|
async pop(key, ...targetArrayElementIndexes) {
|
|
539
661
|
const targetArray = await this.get(key) ?? [];
|
|
@@ -570,87 +692,52 @@ var _Database = class _Database {
|
|
|
570
692
|
return removedElements;
|
|
571
693
|
}
|
|
572
694
|
/**
|
|
573
|
-
*
|
|
695
|
+
* Kiểm tra xem giá trị tại key có phải là Array hay không.
|
|
574
696
|
*
|
|
575
|
-
* @
|
|
576
|
-
* @
|
|
697
|
+
* @typeParam P - Path của object trong database.
|
|
698
|
+
* @param key - Đường dẫn key cần kiểm tra.
|
|
577
699
|
*
|
|
578
|
-
* @
|
|
579
|
-
* console.log(await databse.isTargetArray("array")); // => true
|
|
580
|
-
* console.log(await databse.isTargetArray("notArray")); // => false
|
|
700
|
+
* @returns `true` nếu giá trị là Array, ngược lại `false`.
|
|
581
701
|
*
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
* // notArray: 123
|
|
586
|
-
* // }
|
|
702
|
+
* @example
|
|
703
|
+
* const result = await db.isTargetArray("users");
|
|
704
|
+
* console.log(result);
|
|
587
705
|
*/
|
|
588
706
|
async isTargetArray(key) {
|
|
589
707
|
const target = await this.get(key);
|
|
590
708
|
return Array.isArray(target);
|
|
591
709
|
}
|
|
592
710
|
/**
|
|
593
|
-
*
|
|
711
|
+
* Kiểm tra xem giá trị tại key có phải là Number hay không.
|
|
594
712
|
*
|
|
595
|
-
* @
|
|
596
|
-
* @returns {Promise<boolean>} Whether the target is a number.
|
|
713
|
+
* @typeParam P - Path của object trong database.
|
|
597
714
|
*
|
|
598
|
-
* @
|
|
599
|
-
* console.log(await database.isTargetNumber("number")); // -> true
|
|
600
|
-
* console.log(await database.isTargetNumber("notNumber")); // -> false
|
|
715
|
+
* @param key - Đường dẫn key cần kiểm tra.
|
|
601
716
|
*
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
*
|
|
717
|
+
* @returns `true` nếu giá trị là Number, ngược lại `false`.
|
|
718
|
+
*
|
|
719
|
+
* @example
|
|
720
|
+
* const result = await db.isTargetNumber("stats.score");
|
|
721
|
+
* console.log(result);
|
|
607
722
|
*/
|
|
608
723
|
async isTargetNumber(key) {
|
|
609
724
|
const target = await this.get(key);
|
|
610
725
|
return isNumber(target);
|
|
611
726
|
}
|
|
612
727
|
/**
|
|
613
|
-
*
|
|
728
|
+
* Lấy danh sách các key của object trong database.
|
|
614
729
|
*
|
|
615
|
-
*
|
|
730
|
+
* Nếu không truyền `key` → trả về các key cấp cao nhất của database.
|
|
616
731
|
*
|
|
617
|
-
*
|
|
732
|
+
* @typeParam P - Path của object.
|
|
618
733
|
*
|
|
619
|
-
*
|
|
734
|
+
* @param key - Path của object cần lấy danh sách key.
|
|
620
735
|
*
|
|
621
|
-
* @
|
|
622
|
-
* @returns {Array<ObjectPath<P>>} Database object keys array.
|
|
736
|
+
* @returns Mảng các key tồn tại (không bao gồm `null` hoặc `undefined`).
|
|
623
737
|
*
|
|
624
738
|
* @example
|
|
625
|
-
* const
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
* const prop5Keys = await database.keys("prop3.prop5");
|
|
629
|
-
* console.log(prop5Keys) // -> ["prop6"]
|
|
630
|
-
*
|
|
631
|
-
* const prop6Keys = await database.keys("prop3.prop5.prop6");
|
|
632
|
-
* console.log(prop6Keys)
|
|
633
|
-
* // -> [] (empty since the value in `prop6`, 111, is a primitive value and not an actual object)
|
|
634
|
-
*
|
|
635
|
-
* const databaseKeys = await database.keys();
|
|
636
|
-
* // in this example, `key` parameter is omitted - object keys of database object are being returned
|
|
637
|
-
*
|
|
638
|
-
* console.log(databaseKeys) // -> ["prop1", "prop2", "prop3"]
|
|
639
|
-
*
|
|
640
|
-
* const unexistentKeys = await database.keys("somethingElse");
|
|
641
|
-
* console.log(unexistentKeys) // -> [] (empty since the key `somethingElse` does not exist in database)
|
|
642
|
-
*
|
|
643
|
-
* // Assuming that the initial database object for this example is:
|
|
644
|
-
* // {
|
|
645
|
-
* // prop1: 123,
|
|
646
|
-
* // prop2: 456,
|
|
647
|
-
* // prop3: {
|
|
648
|
-
* // prop4: 789,
|
|
649
|
-
* // prop5: {
|
|
650
|
-
* // prop6: 111
|
|
651
|
-
* // }
|
|
652
|
-
* // }
|
|
653
|
-
* // }
|
|
739
|
+
* const rootKeys = await db.keys();
|
|
740
|
+
* const userKeys = await db.keys("user");
|
|
654
741
|
*/
|
|
655
742
|
async keys(key) {
|
|
656
743
|
if (!key) return TypedObject.keys(await this.all());
|
|
@@ -658,51 +745,33 @@ var _Database = class _Database {
|
|
|
658
745
|
return TypedObject.keys(data).filter((key2) => data[key2] !== void 0 && data[key2] !== null);
|
|
659
746
|
}
|
|
660
747
|
/**
|
|
661
|
-
*
|
|
662
|
-
*
|
|
748
|
+
* Lấy số lượng key cấp cao nhất trong database.
|
|
749
|
+
*
|
|
750
|
+
* @returns Tổng số key ở root level.
|
|
751
|
+
*
|
|
752
|
+
* @example
|
|
753
|
+
* const count = await db.size();
|
|
663
754
|
*/
|
|
664
755
|
async size() {
|
|
665
756
|
const keys = await this.keys();
|
|
666
757
|
return keys.length;
|
|
667
758
|
}
|
|
668
759
|
/**
|
|
669
|
-
*
|
|
670
|
-
*
|
|
671
|
-
* If `key` parameter is omitted, then an array of object values of database root object will be returned.
|
|
672
|
-
*
|
|
673
|
-
* @param {P} [key] The key to access the target in database by.
|
|
674
|
-
* @returns {Array<ObjectValue<V, P>>} Database object values array.
|
|
675
|
-
*
|
|
676
|
-
* @example
|
|
677
|
-
* const prop3Values = await database.values("prop3");
|
|
678
|
-
* console.log(prop3Values); // -> [789, { prop6: 111 }]
|
|
760
|
+
* Lấy danh sách các giá trị từ database.
|
|
679
761
|
*
|
|
680
|
-
*
|
|
681
|
-
*
|
|
762
|
+
* Nếu không truyền `key` → trả về toàn bộ values ở root level.
|
|
763
|
+
* Nếu truyền `key` → trả về values của object tại path đó.
|
|
682
764
|
*
|
|
683
|
-
*
|
|
684
|
-
* console.log(prop6Values);
|
|
685
|
-
* // -> [] (empty since the value in `prop6`, 111, is a primitive value and not an actual object)
|
|
765
|
+
* @typeParam P - Path của object trong database.
|
|
686
766
|
*
|
|
687
|
-
*
|
|
688
|
-
* // in this example, `key` parameter is omitted - object values of database object are being returned
|
|
767
|
+
* @param key - Đường dẫn object cần lấy values.
|
|
689
768
|
*
|
|
690
|
-
*
|
|
769
|
+
* @returns Mảng các giá trị.
|
|
691
770
|
*
|
|
692
|
-
*
|
|
693
|
-
*
|
|
771
|
+
* @example
|
|
772
|
+
* const allValues = await db.values();
|
|
694
773
|
*
|
|
695
|
-
*
|
|
696
|
-
* // {
|
|
697
|
-
* // prop1: 123,
|
|
698
|
-
* // prop2: 456,
|
|
699
|
-
* // prop3: {
|
|
700
|
-
* // prop4: 789,
|
|
701
|
-
* // prop5: {
|
|
702
|
-
* // prop6: 111
|
|
703
|
-
* // }
|
|
704
|
-
* // }
|
|
705
|
-
* // }
|
|
774
|
+
* const userValues = await db.values("users");
|
|
706
775
|
*/
|
|
707
776
|
async values(key) {
|
|
708
777
|
if (!key) return TypedObject.values(await this.all());
|
|
@@ -710,160 +779,125 @@ var _Database = class _Database {
|
|
|
710
779
|
return TypedObject.values(data);
|
|
711
780
|
}
|
|
712
781
|
/**
|
|
713
|
-
*
|
|
782
|
+
* Lấy ngẫu nhiên một phần tử từ array tại path được chỉ định.
|
|
783
|
+
*
|
|
784
|
+
* @typeParam P - Path trỏ đến array trong database.
|
|
785
|
+
*
|
|
786
|
+
* @param key - Đường dẫn đến array.
|
|
787
|
+
*
|
|
788
|
+
* @returns Một phần tử ngẫu nhiên trong array hoặc `null` nếu array rỗng.
|
|
789
|
+
*
|
|
790
|
+
* @throws BlackCatError
|
|
791
|
+
* - INVALID_TARGET nếu giá trị tại key không phải array
|
|
792
|
+
*
|
|
793
|
+
* @example
|
|
794
|
+
* const randomUser = await db.random("users");
|
|
795
|
+
*/
|
|
796
|
+
async random(key) {
|
|
797
|
+
const array = await this.get(key);
|
|
798
|
+
if (!Array.isArray(array)) {
|
|
799
|
+
throw new BlackCatError("INVALID_TARGET", "array", typeOf(array));
|
|
800
|
+
}
|
|
801
|
+
return array[Math.floor(Math.random() * array.length)] ?? null;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Tìm phần tử đầu tiên thỏa điều kiện.
|
|
805
|
+
*
|
|
806
|
+
* Hoạt động tương tự `Array.prototype.find`.
|
|
714
807
|
*
|
|
715
|
-
*
|
|
716
|
-
* by specified condition in the callback function and returns the result.
|
|
808
|
+
* @param queryFunction - Hàm kiểm tra điều kiện.
|
|
717
809
|
*
|
|
718
|
-
* @
|
|
719
|
-
* A function that accepts up to three arguments.
|
|
720
|
-
* The `find` method calls the `queryFunction` once for each element in database object values array.
|
|
810
|
+
* @returns Phần tử đầu tiên thỏa điều kiện hoặc `null` nếu không tìm thấy.
|
|
721
811
|
*
|
|
722
|
-
* @
|
|
812
|
+
* @example
|
|
813
|
+
* const user = await db.find(u => u.id === 1);
|
|
723
814
|
*/
|
|
724
815
|
async find(queryFunction) {
|
|
725
816
|
const values = await this.values();
|
|
726
817
|
return values.find(queryFunction) ?? null;
|
|
727
818
|
}
|
|
728
819
|
/**
|
|
729
|
-
*
|
|
820
|
+
* Biến đổi tất cả giá trị trong database thành một mảng mới.
|
|
821
|
+
*
|
|
822
|
+
* Hoạt động giống `Array.prototype.map`.
|
|
730
823
|
*
|
|
731
|
-
*
|
|
732
|
-
* and returns an array that contains the results.
|
|
824
|
+
* @typeParam TReturnType - Kiểu dữ liệu của phần tử trả về.
|
|
733
825
|
*
|
|
734
|
-
* @param
|
|
735
|
-
* A function that accepts up to three arguments.
|
|
736
|
-
* The `map` method calls the `queryFunction` once for each element in database object values array.
|
|
826
|
+
* @param queryFunction - Hàm transform từng phần tử.
|
|
737
827
|
*
|
|
738
|
-
* @returns
|
|
828
|
+
* @returns Mảng kết quả sau khi transform.
|
|
829
|
+
*
|
|
830
|
+
* @example
|
|
831
|
+
* const names = await db.map(user => user.name);
|
|
739
832
|
*/
|
|
740
833
|
async map(queryFunction) {
|
|
741
834
|
const values = await this.values();
|
|
742
835
|
return values.map(queryFunction);
|
|
743
836
|
}
|
|
744
837
|
/**
|
|
745
|
-
*
|
|
838
|
+
* Tìm index của phần tử đầu tiên thỏa điều kiện.
|
|
839
|
+
*
|
|
840
|
+
* Hoạt động giống `Array.prototype.findIndex`.
|
|
746
841
|
*
|
|
747
|
-
*
|
|
748
|
-
* by specified condition in the callback function and returns the result.
|
|
842
|
+
* @param queryFunction - Hàm kiểm tra điều kiện.
|
|
749
843
|
*
|
|
750
|
-
* @
|
|
751
|
-
* A function that accepts up to three arguments.
|
|
752
|
-
* The `findIndex` method calls the `queryFunction` once for each element in database object values array.
|
|
844
|
+
* @returns Index của phần tử hoặc `-1` nếu không tìm thấy.
|
|
753
845
|
*
|
|
754
|
-
* @
|
|
846
|
+
* @example
|
|
847
|
+
* const index = await db.findIndex(user => user.id === 1);
|
|
755
848
|
*/
|
|
756
849
|
async findIndex(queryFunction) {
|
|
757
850
|
const values = await this.values();
|
|
758
851
|
return values.findIndex(queryFunction);
|
|
759
852
|
}
|
|
760
853
|
/**
|
|
761
|
-
*
|
|
854
|
+
* Lọc các phần tử thỏa điều kiện.
|
|
855
|
+
*
|
|
856
|
+
* Hoạt động giống `Array.prototype.filter`.
|
|
762
857
|
*
|
|
763
|
-
*
|
|
764
|
-
* specified condition in the callback function and returns the result.
|
|
858
|
+
* @param queryFunction - Hàm kiểm tra điều kiện.
|
|
765
859
|
*
|
|
766
|
-
* @
|
|
767
|
-
* A function that accepts up to three arguments.
|
|
768
|
-
* The `filter` method calls the `queryFunction` once for each element in database object values array.
|
|
860
|
+
* @returns Mảng các phần tử thỏa điều kiện.
|
|
769
861
|
*
|
|
770
|
-
* @
|
|
862
|
+
* @example
|
|
863
|
+
* const admins = await db.filter(user => user.role === "admin");
|
|
771
864
|
*/
|
|
772
865
|
async filter(queryFunction) {
|
|
773
866
|
const values = await this.values();
|
|
774
867
|
return values.filter(queryFunction);
|
|
775
868
|
}
|
|
776
869
|
/**
|
|
777
|
-
*
|
|
870
|
+
* Kiểm tra có ít nhất một phần tử thỏa điều kiện hay không.
|
|
871
|
+
*
|
|
872
|
+
* Hoạt động giống `Array.prototype.some`.
|
|
778
873
|
*
|
|
779
|
-
*
|
|
780
|
-
* specified condition in the callback function returns `true`
|
|
781
|
-
* for **any** of the elements of the database object values array.
|
|
874
|
+
* @param queryFunction - Hàm kiểm tra điều kiện.
|
|
782
875
|
*
|
|
783
|
-
* @
|
|
784
|
-
* A function that accepts up to three arguments.
|
|
785
|
-
* The `some` method calls the `queryFunction` once for each element in database object values array.
|
|
876
|
+
* @returns `true` nếu tồn tại phần tử thỏa điều kiện.
|
|
786
877
|
*
|
|
787
|
-
* @
|
|
878
|
+
* @example
|
|
879
|
+
* const hasAdmin = await db.some(user => user.role === "admin");
|
|
788
880
|
*/
|
|
789
881
|
async some(queryFunction) {
|
|
790
882
|
const values = await this.values();
|
|
791
883
|
return values.some(queryFunction);
|
|
792
884
|
}
|
|
793
885
|
/**
|
|
794
|
-
*
|
|
886
|
+
* Kiểm tra tất cả phần tử có thỏa điều kiện hay không.
|
|
795
887
|
*
|
|
796
|
-
*
|
|
797
|
-
* specified condition in the callback function returns `true`
|
|
798
|
-
* for **all** of the elements of the database object values array.
|
|
888
|
+
* Hoạt động giống `Array.prototype.every`.
|
|
799
889
|
*
|
|
800
|
-
* @param
|
|
801
|
-
* A function that accepts up to three arguments.
|
|
802
|
-
* The `every` method calls the `queryFunction` once for each element in database object values array.
|
|
890
|
+
* @param queryFunction - Hàm kiểm tra điều kiện.
|
|
803
891
|
*
|
|
804
|
-
* @returns
|
|
892
|
+
* @returns `true` nếu tất cả phần tử đều thỏa điều kiện.
|
|
893
|
+
*
|
|
894
|
+
* @example
|
|
895
|
+
* const allActive = await db.every(user => user.active === true);
|
|
805
896
|
*/
|
|
806
897
|
async every(queryFunction) {
|
|
807
898
|
const values = await this.values();
|
|
808
899
|
return values.every(queryFunction);
|
|
809
900
|
}
|
|
810
|
-
/**
|
|
811
|
-
* Picks a random element of array in database and returns the picked array element.
|
|
812
|
-
*
|
|
813
|
-
* [!!!] The type of target value must be an array.
|
|
814
|
-
*
|
|
815
|
-
* @param {AutocompletableString<P>} key The key to access the target in database by.
|
|
816
|
-
* @returns {Promise<Maybe<ObjectValue<V, P>>>} The randomly picked element in the database array.
|
|
817
|
-
*
|
|
818
|
-
* @example
|
|
819
|
-
* const array = await database.get("array"); // assuming that the array is ['example1', 'example2', 'example3']
|
|
820
|
-
* console.log(array); // -> ['example1', 'example2', 'example3']
|
|
821
|
-
*
|
|
822
|
-
* const randomArrayElement = await database.random("exampleArray");
|
|
823
|
-
* console.log(randomArrayElement); // -> randomly picked array element: either 'example1', 'example2', or 'example3'
|
|
824
|
-
*/
|
|
825
|
-
async random(key) {
|
|
826
|
-
const array = await this.get(key);
|
|
827
|
-
if (!Array.isArray(array)) {
|
|
828
|
-
throw new BlackCatError("INVALID_TARGET", "array", typeOf(array));
|
|
829
|
-
}
|
|
830
|
-
return array[Math.floor(Math.random() * array.length)] ?? null;
|
|
831
|
-
}
|
|
832
|
-
/**
|
|
833
|
-
* Deletes the data from database by key.
|
|
834
|
-
* @param {AutocompletableString<P>} key The key to access the target in database by.
|
|
835
|
-
* @returns {Promise<boolean>} Whether the deletion was successful.
|
|
836
|
-
*/
|
|
837
|
-
async delete(key) {
|
|
838
|
-
if (typeof key !== "string") {
|
|
839
|
-
throw new BlackCatError("INVALID_TYPE", "key", "string", typeof key);
|
|
840
|
-
}
|
|
841
|
-
;
|
|
842
|
-
const allDatabase = await this.all();
|
|
843
|
-
const keys = key.split(".");
|
|
844
|
-
const lastKey = keys.pop();
|
|
845
|
-
let currentObj = allDatabase;
|
|
846
|
-
for (const k of keys) {
|
|
847
|
-
if (!isObject(currentObj[k])) {
|
|
848
|
-
return false;
|
|
849
|
-
}
|
|
850
|
-
currentObj = currentObj[k];
|
|
851
|
-
}
|
|
852
|
-
if (!(lastKey in currentObj)) return false;
|
|
853
|
-
delete currentObj[lastKey];
|
|
854
|
-
await this.driver.delete(allDatabase);
|
|
855
|
-
return true;
|
|
856
|
-
}
|
|
857
|
-
/**
|
|
858
|
-
* Deletes everything from the database.
|
|
859
|
-
*
|
|
860
|
-
* - This method is an alias for {@link QuickMongo.clear()} method.
|
|
861
|
-
* @returns {Promise<boolean>} `true` if cleared successfully, `false` otherwise.
|
|
862
|
-
*/
|
|
863
|
-
async deleteAll() {
|
|
864
|
-
await this.driver.delete();
|
|
865
|
-
return true;
|
|
866
|
-
}
|
|
867
901
|
};
|
|
868
902
|
__name(_Database, "Database");
|
|
869
903
|
var Database = _Database;
|
|
@@ -872,98 +906,337 @@ var Database = _Database;
|
|
|
872
906
|
import { promises as fs } from "fs";
|
|
873
907
|
var _JSONDriver = class _JSONDriver {
|
|
874
908
|
/**
|
|
875
|
-
* JSONDriver
|
|
876
|
-
*
|
|
877
|
-
* @param options
|
|
909
|
+
* Khởi tạo một instance mới của {@link JSONDriver}.
|
|
910
|
+
*
|
|
911
|
+
* @param options - Cấu hình driver
|
|
912
|
+
*
|
|
913
|
+
* @param options.filePath
|
|
914
|
+
* Đường dẫn tới file JSON dùng làm database.
|
|
915
|
+
*
|
|
916
|
+
* @param options.minifyJSON
|
|
917
|
+
* Nếu `true`, nội dung JSON sẽ được minify khi ghi ra file để giảm dung lượng.
|
|
918
|
+
*
|
|
919
|
+
* @example
|
|
920
|
+
* ```ts
|
|
921
|
+
* const database = new Database({
|
|
922
|
+
* driver: db = new JSONDriver({
|
|
923
|
+
* filePath: "./database.json"
|
|
924
|
+
* })
|
|
925
|
+
* });
|
|
926
|
+
* ```
|
|
878
927
|
*/
|
|
879
928
|
constructor(options) {
|
|
880
929
|
/**
|
|
881
|
-
*
|
|
882
|
-
* @type {string}
|
|
930
|
+
* Đường dẫn tới file database JSON.
|
|
883
931
|
*/
|
|
884
932
|
__publicField(this, "filePath");
|
|
885
933
|
/**
|
|
886
|
-
*
|
|
887
|
-
* @type {boolean}
|
|
934
|
+
* Cho biết có minify JSON khi ghi file hay không.
|
|
888
935
|
*/
|
|
889
936
|
__publicField(this, "minifyJSON");
|
|
890
937
|
this.filePath = options.filePath || "database.json";
|
|
891
938
|
this.minifyJSON = options.minifyJSON || false;
|
|
892
939
|
}
|
|
893
940
|
/**
|
|
894
|
-
*
|
|
895
|
-
*
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
941
|
+
* Đảm bảo file database tồn tại.
|
|
942
|
+
* Nếu file chưa tồn tại sẽ tự động tạo file `{}`.
|
|
943
|
+
*/
|
|
944
|
+
async ensureFile() {
|
|
945
|
+
try {
|
|
946
|
+
await fs.access(this.filePath);
|
|
947
|
+
} catch {
|
|
948
|
+
await fs.writeFile(this.filePath, "{}");
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Đọc toàn bộ dữ liệu từ file database JSON.
|
|
953
|
+
*
|
|
954
|
+
* Nếu file không tồn tại hoặc lỗi parse,
|
|
955
|
+
* method sẽ trả về object rỗng.
|
|
956
|
+
*
|
|
957
|
+
* @template V Kiểu dữ liệu database.
|
|
958
|
+
* @returns Promise chứa toàn bộ dữ liệu database.
|
|
899
959
|
*/
|
|
900
960
|
async all() {
|
|
961
|
+
await this.ensureFile();
|
|
901
962
|
return fs.readFile(this.filePath, "utf-8").then((content) => JSON.parse(content)).catch((error) => {
|
|
902
|
-
console.error(`
|
|
963
|
+
console.error(`Kh\xF4ng th\u1EC3 \u0111\u1ECDc file database: ${this.filePath}`, error);
|
|
903
964
|
return {};
|
|
904
965
|
});
|
|
905
966
|
}
|
|
906
967
|
/**
|
|
907
|
-
*
|
|
968
|
+
* Ghi toàn bộ dữ liệu database xuống file JSON.
|
|
908
969
|
*
|
|
909
|
-
*
|
|
970
|
+
* Method này **không xử lý key path**.
|
|
971
|
+
* Logic cập nhật dữ liệu sẽ được xử lý ở class `Database`
|
|
972
|
+
* trước khi truyền object hoàn chỉnh vào đây.
|
|
973
|
+
*
|
|
974
|
+
* @param data Toàn bộ dữ liệu database sau khi đã được cập nhật.
|
|
910
975
|
*
|
|
911
|
-
*
|
|
976
|
+
* @template R Kiểu dữ liệu database.
|
|
977
|
+
* @returns Promise chứa dữ liệu đã ghi.
|
|
978
|
+
*/
|
|
979
|
+
async set(data) {
|
|
980
|
+
await this.ensureFile();
|
|
981
|
+
await fs.writeFile(this.filePath, JSON.stringify(data, null, this.minifyJSON ? void 0 : " "));
|
|
982
|
+
return data;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Xóa toàn bộ database.
|
|
912
986
|
*
|
|
913
|
-
*
|
|
914
|
-
* @returns {Promise<V>} The data from JSON database.
|
|
987
|
+
* Method này chỉ reset file JSON về `{}`.
|
|
915
988
|
*
|
|
916
|
-
* @
|
|
989
|
+
* @returns `true` nếu reset thành công.
|
|
917
990
|
*/
|
|
918
|
-
async
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
for (const k of keys) {
|
|
923
|
-
if (result === null || typeof result !== "object") return null;
|
|
924
|
-
result = result[k];
|
|
925
|
-
}
|
|
926
|
-
return result;
|
|
991
|
+
async delete() {
|
|
992
|
+
await this.ensureFile();
|
|
993
|
+
await fs.writeFile(this.filePath, "{}");
|
|
994
|
+
return true;
|
|
927
995
|
}
|
|
996
|
+
};
|
|
997
|
+
__name(_JSONDriver, "JSONDriver");
|
|
998
|
+
var JSONDriver = _JSONDriver;
|
|
999
|
+
|
|
1000
|
+
// src/drivers/MemoryDriver.ts
|
|
1001
|
+
var _MemoryDriver = class _MemoryDriver {
|
|
928
1002
|
/**
|
|
929
|
-
*
|
|
1003
|
+
* Khởi tạo MemoryDriver.
|
|
1004
|
+
*
|
|
1005
|
+
* @param initialData Dữ liệu khởi tạo ban đầu.
|
|
1006
|
+
* * @example
|
|
1007
|
+
* ```ts
|
|
1008
|
+
* const database = new Database({
|
|
1009
|
+
* driver: new MemoryDriver({
|
|
1010
|
+
* users: {},
|
|
1011
|
+
* guilds: {},
|
|
1012
|
+
* settings: {
|
|
1013
|
+
* prefix: "!"
|
|
1014
|
+
* }
|
|
1015
|
+
* })
|
|
1016
|
+
* });
|
|
1017
|
+
* ```
|
|
1018
|
+
*
|
|
1019
|
+
* hoặc
|
|
1020
|
+
*
|
|
1021
|
+
* ```ts
|
|
1022
|
+
* const database = new Database({
|
|
1023
|
+
* driver: new MemoryDriver()
|
|
1024
|
+
* });
|
|
1025
|
+
* ```
|
|
1026
|
+
*/
|
|
1027
|
+
constructor(initialData = {}) {
|
|
1028
|
+
/**
|
|
1029
|
+
* Object chứa toàn bộ dữ liệu database trong RAM.
|
|
1030
|
+
*/
|
|
1031
|
+
__publicField(this, "store");
|
|
1032
|
+
this.store = initialData;
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Trả về toàn bộ dữ liệu database.
|
|
930
1036
|
*
|
|
931
|
-
*
|
|
1037
|
+
* @template T Kiểu dữ liệu database.
|
|
1038
|
+
*/
|
|
1039
|
+
async all() {
|
|
1040
|
+
return this.store;
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Ghi toàn bộ database vào memory.
|
|
1044
|
+
*
|
|
1045
|
+
* ⚠️ Method này **không xử lý key-path**.
|
|
1046
|
+
* Dữ liệu đã được xử lý trước bởi `Database`.
|
|
1047
|
+
*
|
|
1048
|
+
* @param data Toàn bộ database object
|
|
1049
|
+
*/
|
|
1050
|
+
async set(data) {
|
|
1051
|
+
this.store = data;
|
|
1052
|
+
return data;
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Xóa toàn bộ dữ liệu database trong memory.
|
|
1056
|
+
*/
|
|
1057
|
+
async delete() {
|
|
1058
|
+
this.store = {};
|
|
1059
|
+
return true;
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
__name(_MemoryDriver, "MemoryDriver");
|
|
1063
|
+
var MemoryDriver = _MemoryDriver;
|
|
1064
|
+
|
|
1065
|
+
// src/drivers/SQLiteDriver.ts
|
|
1066
|
+
import SQLite from "better-sqlite3";
|
|
1067
|
+
var _SQLiteDriver = class _SQLiteDriver {
|
|
1068
|
+
/**
|
|
1069
|
+
* Khởi tạo SQLiteDriver.
|
|
1070
|
+
*
|
|
1071
|
+
* @param filePath Đường dẫn file SQLite
|
|
1072
|
+
* @param table Tên table lưu JSON database
|
|
1073
|
+
* @example
|
|
1074
|
+
* ```ts
|
|
1075
|
+
* const database = new Database({
|
|
1076
|
+
* driver: new SQLiteDriver({
|
|
1077
|
+
* filePath: "database.sqlite",
|
|
1078
|
+
* table: "json_store"
|
|
1079
|
+
* })
|
|
1080
|
+
* })
|
|
1081
|
+
* ```
|
|
1082
|
+
*/
|
|
1083
|
+
constructor(options = {}) {
|
|
1084
|
+
/**
|
|
1085
|
+
* SQLite database instance.
|
|
1086
|
+
*/
|
|
1087
|
+
__publicField(this, "db");
|
|
1088
|
+
/**
|
|
1089
|
+
* Tên table lưu trữ dữ liệu JSON.
|
|
1090
|
+
*/
|
|
1091
|
+
__publicField(this, "table");
|
|
1092
|
+
this.db = new SQLite(options.filePath ?? "database.sqlite");
|
|
1093
|
+
this.table = options.table ?? "json_store";
|
|
1094
|
+
this.db.prepare(`CREATE TABLE IF NOT EXISTS ${this.table} (id INTEGER PRIMARY KEY, data TEXT)`).run();
|
|
1095
|
+
const row = this.db.prepare(`SELECT * FROM ${this.table} WHERE id = 1`).get();
|
|
1096
|
+
if (!row) {
|
|
1097
|
+
this.db.prepare(`INSERT INTO ${this.table} (id, data) VALUES (1, '{}')`).run();
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
/**
|
|
1101
|
+
* Lấy toàn bộ dữ liệu database từ SQLite.
|
|
932
1102
|
*
|
|
933
|
-
*
|
|
934
|
-
|
|
1103
|
+
* @template T Kiểu dữ liệu database.
|
|
1104
|
+
*/
|
|
1105
|
+
async all() {
|
|
1106
|
+
const row = this.db.prepare(`SELECT data FROM ${this.table} WHERE id = 1`).get();
|
|
1107
|
+
return JSON.parse(row.data);
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Ghi toàn bộ database vào SQLite.
|
|
935
1111
|
*
|
|
936
|
-
*
|
|
937
|
-
*
|
|
1112
|
+
* ⚠️ Method này **không xử lý key-path**.
|
|
1113
|
+
* `Database` đã cập nhật object trước khi truyền vào đây.
|
|
938
1114
|
*
|
|
939
|
-
* @
|
|
940
|
-
* @template R The type of data being returned.
|
|
1115
|
+
* @param data Toàn bộ database object
|
|
941
1116
|
*/
|
|
942
|
-
async set(
|
|
943
|
-
|
|
944
|
-
await fs.writeFile(this.filePath, JSON.stringify(value, null, this.minifyJSON ? void 0 : " "));
|
|
1117
|
+
async set(data) {
|
|
1118
|
+
this.db.prepare(`UPDATE ${this.table} SET data = ? WHERE id = 1`).run(JSON.stringify(data));
|
|
945
1119
|
return data;
|
|
946
1120
|
}
|
|
947
1121
|
/**
|
|
948
|
-
*
|
|
949
|
-
* @param {V} key The key in JSON database.
|
|
950
|
-
* @returns {Promise<boolean>} `true` if deleted successfully.
|
|
1122
|
+
* Reset toàn bộ database.
|
|
951
1123
|
*/
|
|
952
|
-
async delete(
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1124
|
+
async delete() {
|
|
1125
|
+
this.db.prepare(`UPDATE ${this.table} SET data = '{}' WHERE id = 1`).run();
|
|
1126
|
+
return true;
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
__name(_SQLiteDriver, "SQLiteDriver");
|
|
1130
|
+
var SQLiteDriver = _SQLiteDriver;
|
|
1131
|
+
|
|
1132
|
+
// src/drivers/MongoDriver.ts
|
|
1133
|
+
import { MongoClient } from "mongodb";
|
|
1134
|
+
var _MongoDriver = class _MongoDriver {
|
|
1135
|
+
/**
|
|
1136
|
+
* Khởi tạo MongoDriver.
|
|
1137
|
+
*
|
|
1138
|
+
* @param options Cấu hình MongoDB driver.
|
|
1139
|
+
*
|
|
1140
|
+
* @example
|
|
1141
|
+
* ```ts
|
|
1142
|
+
* const database = new Database({
|
|
1143
|
+
* driver: new MongoDriver({
|
|
1144
|
+
* mongourl: "mongodb://localhost:27017",
|
|
1145
|
+
* databaseName: "mydb",
|
|
1146
|
+
* collectionName: "store"
|
|
1147
|
+
* })
|
|
1148
|
+
* });
|
|
1149
|
+
*/
|
|
1150
|
+
constructor(options = {}) {
|
|
1151
|
+
/**
|
|
1152
|
+
* MongoDB client instance.
|
|
1153
|
+
*/
|
|
1154
|
+
__publicField(this, "client");
|
|
1155
|
+
/**
|
|
1156
|
+
* MongoDB database instance.
|
|
1157
|
+
*/
|
|
1158
|
+
__publicField(this, "db");
|
|
1159
|
+
/**
|
|
1160
|
+
* Collection lưu dữ liệu JSON.
|
|
1161
|
+
*/
|
|
1162
|
+
__publicField(this, "collection");
|
|
1163
|
+
/**
|
|
1164
|
+
* Tên database MongoDB.
|
|
1165
|
+
*/
|
|
1166
|
+
__publicField(this, "databaseName");
|
|
1167
|
+
/**
|
|
1168
|
+
* Tên collection MongoDB.
|
|
1169
|
+
*/
|
|
1170
|
+
__publicField(this, "collectionName");
|
|
1171
|
+
const {
|
|
1172
|
+
mongourl = "mongodb://localhost:27017",
|
|
1173
|
+
databaseName = "database",
|
|
1174
|
+
collectionName = "json_store"
|
|
1175
|
+
} = options;
|
|
1176
|
+
this.client = new MongoClient(mongourl);
|
|
1177
|
+
this.databaseName = databaseName;
|
|
1178
|
+
this.collectionName = collectionName;
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Thiết lập kết nối MongoDB nếu chưa kết nối.
|
|
1182
|
+
*/
|
|
1183
|
+
async connect() {
|
|
1184
|
+
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: {}
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
958
1195
|
}
|
|
959
|
-
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Lấy toàn bộ dữ liệu database từ MongoDB.
|
|
1199
|
+
*/
|
|
1200
|
+
async all() {
|
|
1201
|
+
await this.connect();
|
|
1202
|
+
const doc = await this.collection.findOne({ _id: "database" });
|
|
1203
|
+
return doc?.data ?? {};
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Ghi toàn bộ database vào MongoDB.
|
|
1207
|
+
*
|
|
1208
|
+
* ⚠️ Method này **không xử lý key-path**.
|
|
1209
|
+
* Object database đã được xử lý bởi class `Database`.
|
|
1210
|
+
*
|
|
1211
|
+
* @param data Toàn bộ object database
|
|
1212
|
+
*/
|
|
1213
|
+
async set(data) {
|
|
1214
|
+
await this.connect();
|
|
1215
|
+
await this.collection.updateOne(
|
|
1216
|
+
{ _id: "database" },
|
|
1217
|
+
{ $set: { data } }
|
|
1218
|
+
);
|
|
1219
|
+
return data;
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Reset toàn bộ database về object rỗng.
|
|
1223
|
+
*/
|
|
1224
|
+
async delete() {
|
|
1225
|
+
await this.connect();
|
|
1226
|
+
await this.collection.updateOne(
|
|
1227
|
+
{ _id: "database" },
|
|
1228
|
+
{ $set: { data: {} } }
|
|
1229
|
+
);
|
|
960
1230
|
return true;
|
|
961
1231
|
}
|
|
962
1232
|
};
|
|
963
|
-
__name(
|
|
964
|
-
var
|
|
1233
|
+
__name(_MongoDriver, "MongoDriver");
|
|
1234
|
+
var MongoDriver = _MongoDriver;
|
|
965
1235
|
export {
|
|
966
1236
|
Database,
|
|
967
|
-
JSONDriver
|
|
1237
|
+
JSONDriver,
|
|
1238
|
+
MemoryDriver,
|
|
1239
|
+
MongoDriver,
|
|
1240
|
+
SQLiteDriver
|
|
968
1241
|
};
|
|
969
1242
|
//# sourceMappingURL=index.mjs.map
|