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