@frogfish/k2db 1.0.15 → 2.0.3

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/db.js DELETED
@@ -1,616 +0,0 @@
1
- "use strict";
2
- // src/db.ts
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.K2DB = void 0;
8
- const k2error_1 = require("@frogfish/k2error"); // Keep the existing error structure
9
- const mongodb_1 = require("mongodb");
10
- const uuid_1 = require("uuid");
11
- const debug_1 = __importDefault(require("debug"));
12
- const debug = (0, debug_1.default)("k2:db");
13
- class K2DB {
14
- constructor(conf) {
15
- this.conf = conf;
16
- }
17
- /**
18
- * Initializes the MongoDB connection.
19
- */
20
- async init() {
21
- // 1. dbName from config
22
- const dbName = this.conf.name;
23
- // 2. Build the connection string with user/password if available
24
- // (Change 'mongodb+srv://' back to 'mongodb://' if you're not using an SRV connection)
25
- let connectUrl = "mongodb+srv://";
26
- if (this.conf.user && this.conf.password) {
27
- connectUrl += `${encodeURIComponent(this.conf.user)}:${encodeURIComponent(this.conf.password)}@`;
28
- }
29
- // 3. If no hosts, throw an error
30
- if (!this.conf.hosts || this.conf.hosts.length === 0) {
31
- throw new k2error_1.K2Error(k2error_1.ServiceError.CONFIGURATION_ERROR, "No valid hosts provided in configuration", "sys_mdb_no_hosts");
32
- }
33
- // 4. Handle single vs multiple hosts
34
- // - If SRV, you typically only specify the first host (no port)
35
- // - If non-SRV, you'd do: .map((host) => `${host.host}:${host.port || 27017}`).join(",")
36
- //
37
- // For SRV, we *usually* just do the first host:
38
- connectUrl += this.conf.hosts[0].host;
39
- // 5. Append the DB name
40
- // If SRV with Atlas, you can also append `retryWrites=true&w=majority`, etc.
41
- // If you need to pass additional params (e.g., replicaSet), you can do so below.
42
- connectUrl += `/${dbName}`;
43
- // 6. Append replicaset if more than one host and replicaset is defined.
44
- // (Typically, SRV records handle the replicaSet automatically, so you may not need this.
45
- // But if you do, keep this logic.)
46
- if (this.conf.hosts.length > 1 && this.conf.replicaset) {
47
- // If you already have `/${dbName}?...`, you need to add `&` instead of `?`.
48
- // For simplicity, we do a conditional:
49
- if (connectUrl.includes("?")) {
50
- connectUrl += `&replicaSet=${this.conf.replicaset}&keepAlive=true&autoReconnect=true&socketTimeoutMS=0`;
51
- }
52
- else {
53
- connectUrl += `?replicaSet=${this.conf.replicaset}&keepAlive=true&autoReconnect=true&socketTimeoutMS=0`;
54
- }
55
- }
56
- else {
57
- // For SRV + Atlas: often we want at least `?retryWrites=true&w=majority`
58
- if (!connectUrl.includes("?")) {
59
- connectUrl += "?retryWrites=true&w=majority";
60
- }
61
- else {
62
- connectUrl += "&retryWrites=true&w=majority";
63
- }
64
- }
65
- // Mask sensitive information in logs
66
- const safeConnectUrl = connectUrl.replace(/\/\/.*?:.*?@/, "//*****:*****@");
67
- debug(`Connecting to MongoDB: ${safeConnectUrl}`);
68
- // 7. Define connection options with timeouts
69
- // (Keep from original code, or update as needed)
70
- const options = {
71
- connectTimeoutMS: 2000,
72
- serverSelectionTimeoutMS: 2000,
73
- // If you want the Stable API (like in your _init), do:
74
- // serverApi: {
75
- // version: ServerApiVersion.v1,
76
- // strict: true,
77
- // deprecationErrors: true,
78
- // },
79
- };
80
- try {
81
- // 8. Establish MongoDB connection
82
- this.connection = await mongodb_1.MongoClient.connect(connectUrl, options);
83
- this.db = this.connection.db(dbName);
84
- debug("Successfully connected to MongoDB");
85
- }
86
- catch (err) {
87
- // 9. Handle connection error
88
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, `Failed to connect to MongoDB: ${err.message}`, "sys_mdb_init", this.normalizeError(err));
89
- }
90
- }
91
- /**
92
- * Retrieves a collection from the database.
93
- * @param collectionName - Name of the collection.
94
- */
95
- async getCollection(collectionName) {
96
- try {
97
- this.validateCollectionName(collectionName); // Validate the collection name
98
- const collection = this.db.collection(collectionName);
99
- return collection;
100
- }
101
- catch (err) {
102
- // If the error is already an K2Error, rethrow it
103
- if (err instanceof k2error_1.K2Error) {
104
- throw err;
105
- }
106
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, `Error getting collection: ${collectionName}`, "sys_mdb_gc", this.normalizeError(err));
107
- }
108
- }
109
- async get(collectionName, uuid) {
110
- const res = await this.findOne(collectionName, {
111
- _uuid: uuid,
112
- _deleted: { $ne: true },
113
- });
114
- if (!res) {
115
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Error getting the document with provided identity", "sys_mdb_get");
116
- }
117
- return res;
118
- }
119
- /**
120
- * Retrieves a single document by UUID.
121
- * @param collectionName - Name of the collection.
122
- * @param uuid - UUID of the document.
123
- * @param objectTypeName - Optional object type name.
124
- * @param fields - Optional array of fields to include.
125
- */
126
- async findOne(collectionName, criteria, fields) {
127
- const collection = await this.getCollection(collectionName);
128
- const projection = {};
129
- if (fields && fields.length > 0) {
130
- fields.forEach((field) => {
131
- projection[field] = 1;
132
- });
133
- }
134
- try {
135
- const item = await collection.findOne(criteria, { projection });
136
- if (item) {
137
- const { _id, ...rest } = item;
138
- return rest;
139
- }
140
- return null;
141
- }
142
- catch (err) {
143
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Error finding document", "sys_mdb_fo", this.normalizeError(err));
144
- }
145
- }
146
- /**
147
- * Finds documents based on parameters with pagination support.
148
- * @param collectionName - Name of the collection.
149
- * @param filter - Criteria to filter the documents.
150
- * @param params - Optional search parameters (for sorting, including/excluding fields).
151
- * @param skip - Number of documents to skip (for pagination).
152
- * @param limit - Maximum number of documents to return.
153
- */
154
- async find(collectionName, filter, params = {}, skip = 0, limit = 100) {
155
- const collection = await this.getCollection(collectionName);
156
- // Ensure filter is valid, defaulting to an empty object
157
- const criteria = filter || {};
158
- // Handle the _deleted field if params specify not to include deleted documents
159
- if (params.includeDeleted) {
160
- // No _deleted filter, include all documents
161
- }
162
- else if (params.deleted === true) {
163
- criteria._deleted = true; // Explicitly search for deleted documents
164
- }
165
- else {
166
- criteria._deleted = { $ne: true }; // Exclude deleted by default
167
- }
168
- // Build projection (fields to include or exclude)
169
- let projection = { _id: 0 }; // Exclude _id by default
170
- if (typeof params.filter === "string" && params.filter === "all") {
171
- projection = {}; // Include all fields
172
- }
173
- else if (Array.isArray(params.filter)) {
174
- params.filter.forEach((field) => {
175
- projection[field] = 1; // Only include the specified fields
176
- });
177
- }
178
- if (Array.isArray(params.exclude)) {
179
- params.exclude.forEach((field) => {
180
- projection[field] = 0; // Exclude the specified fields
181
- });
182
- }
183
- // Build sorting options
184
- let sort = undefined;
185
- if (params.order) {
186
- sort = {};
187
- for (const [key, value] of Object.entries(params.order)) {
188
- sort[key] = value === "asc" ? 1 : -1;
189
- }
190
- }
191
- try {
192
- let cursor = collection.find(criteria, { projection });
193
- // Apply pagination
194
- cursor = cursor.skip(skip).limit(limit);
195
- if (sort) {
196
- cursor = cursor.sort(sort);
197
- }
198
- const data = await cursor.toArray();
199
- // Remove _id safely from each document
200
- const result = data.map((doc) => {
201
- const { _id, ...rest } = doc;
202
- return rest;
203
- });
204
- return result;
205
- }
206
- catch (err) {
207
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Error executing find query", "sys_mdb_find_error", this.normalizeError(err));
208
- }
209
- }
210
- /**
211
- * Aggregates documents based on criteria with pagination support.
212
- * @param collectionName - Name of the collection.
213
- * @param criteria - Aggregation pipeline criteria.
214
- * @param skip - Number of documents to skip (for pagination).
215
- * @param limit - Maximum number of documents to return.
216
- */
217
- async aggregate(collectionName, criteria, skip = 0, limit = 100) {
218
- if (criteria.length === 0) {
219
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Aggregation criteria cannot be empty", "sys_mdb_ag_empty");
220
- }
221
- // Ensure we always exclude soft-deleted documents
222
- if (criteria[0].$match) {
223
- criteria[0].$match = { ...criteria[0].$match, _deleted: { $ne: true } };
224
- }
225
- else {
226
- criteria.unshift({ $match: { _deleted: { $ne: true } } });
227
- }
228
- // Add pagination stages to the aggregation pipeline
229
- if (skip > 0) {
230
- criteria.push({ $skip: skip });
231
- }
232
- if (limit > 0) {
233
- criteria.push({ $limit: limit });
234
- }
235
- debug(`Aggregating with criteria: ${JSON.stringify(criteria, null, 2)}`);
236
- const collection = await this.getCollection(collectionName);
237
- // Sanitize criteria
238
- const sanitizedCriteria = criteria.map((stage) => {
239
- if (stage.$match) {
240
- return K2DB.sanitiseCriteria(stage);
241
- }
242
- return stage;
243
- });
244
- try {
245
- const data = await collection.aggregate(sanitizedCriteria).toArray();
246
- // Enforce BaseDocument type on each document
247
- return data.map((doc) => doc);
248
- }
249
- catch (err) {
250
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Aggregation failed", "sys_mdb_ag", this.normalizeError(err));
251
- }
252
- }
253
- /**
254
- * Creates a new document in the collection.
255
- * @param collectionName - Name of the collection.
256
- * @param owner - Owner of the document.
257
- * @param data - Data to insert.
258
- */
259
- async create(collectionName, owner, data) {
260
- if (!collectionName || !owner || !data) {
261
- throw new k2error_1.K2Error(k2error_1.ServiceError.BAD_REQUEST, "Invalid method usage, parameters not defined", "sys_mdb_crv1");
262
- }
263
- if (typeof owner !== "string") {
264
- throw new k2error_1.K2Error(k2error_1.ServiceError.BAD_REQUEST, "Owner must be of a string type", "sys_mdb_crv2");
265
- }
266
- const collection = await this.getCollection(collectionName);
267
- const timestamp = Date.now();
268
- // Generate a new UUID
269
- const newUuid = (0, uuid_1.v4)();
270
- // Spread `data` first, then set internal fields to prevent overwriting
271
- const document = {
272
- ...data,
273
- _created: timestamp,
274
- _updated: timestamp,
275
- _owner: owner,
276
- _uuid: newUuid,
277
- };
278
- try {
279
- const result = await collection.insertOne(document);
280
- return { id: document._uuid };
281
- }
282
- catch (err) {
283
- // Use appropriate error typing
284
- // Check if the error is a duplicate key error
285
- if (err.code === 11000 && err.keyPattern && err.keyPattern._uuid) {
286
- throw new k2error_1.K2Error(k2error_1.ServiceError.ALREADY_EXISTS, `A document with _uuid ${document._uuid} already exists.`, "sys_mdb_crv3");
287
- }
288
- // Log the error details for debugging
289
- debug(`Was trying to insert into collection ${collectionName}, data: ${JSON.stringify(document)}`);
290
- debug(err);
291
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Error saving object to database", "sys_mdb_sav", this.normalizeError(err));
292
- }
293
- }
294
- /**
295
- * Updates multiple documents based on criteria.
296
- * Can either replace the documents or patch them.
297
- * @param collectionName - Name of the collection.
298
- * @param criteria - Update criteria.
299
- * @param values - Values to update or replace with.
300
- */
301
- async updateAll(collectionName, criteria, values) {
302
- this.validateCollectionName(collectionName);
303
- const collection = await this.getCollection(collectionName);
304
- debug(`Updating ${collectionName} with criteria: ${JSON.stringify(criteria)}`);
305
- values._updated = Date.now();
306
- criteria = {
307
- ...criteria,
308
- _deleted: { $ne: true },
309
- };
310
- try {
311
- const res = await collection.updateMany(criteria, { $set: values });
312
- return {
313
- updated: res.modifiedCount,
314
- };
315
- }
316
- catch (err) {
317
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, `Error updating ${collectionName}`, "sys_mdb_update1", this.normalizeError(err));
318
- }
319
- }
320
- /**
321
- * Updates a single document by UUID.
322
- * Can either replace the document or patch it.
323
- * @param collectionName - Name of the collection.
324
- * @param id - UUID string to identify the document.
325
- * @param data - Data to update or replace with.
326
- * @param replace - If true, replaces the entire document (PUT), otherwise patches (PATCH).
327
- */
328
- async update(collectionName, id, data, replace = false) {
329
- this.validateCollectionName(collectionName);
330
- const collection = await this.getCollection(collectionName);
331
- data._updated = Date.now(); // Set the _updated timestamp
332
- try {
333
- let res;
334
- // If replacing the document, first get the original document
335
- if (replace) {
336
- // Get the original document to preserve fields starting with underscore
337
- const originalDoc = await this.get(collectionName, id);
338
- // Override all fields starting with underscore from the original document
339
- const fieldsToPreserve = Object.keys(originalDoc).reduce((acc, key) => {
340
- if (key.startsWith("_")) {
341
- acc[key] = originalDoc[key];
342
- }
343
- return acc;
344
- }, {});
345
- // Merge the preserved fields into the data
346
- data = { ...data, ...fieldsToPreserve };
347
- data._updated = Date.now();
348
- // Now replace the document with the merged data
349
- res = await collection.replaceOne({ _uuid: id }, data);
350
- }
351
- else {
352
- // If patching, just update specific fields using $set
353
- res = await collection.updateOne({ _uuid: id }, { $set: data });
354
- }
355
- // Check if exactly one document was updated
356
- if (res.modifiedCount === 1) {
357
- return { updated: 1 };
358
- }
359
- // If no document was updated, throw a NOT_FOUND error
360
- if (res.modifiedCount === 0) {
361
- throw new k2error_1.K2Error(k2error_1.ServiceError.NOT_FOUND, `Object in ${collectionName} with UUID ${id} not found`, "sys_mdb_update_not_found");
362
- }
363
- // If more than one document was updated (though this should never happen with a single UUID), throw a SYSTEM_ERROR
364
- if (res.modifiedCount > 1) {
365
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, `Multiple objects in ${collectionName} were updated when only one was expected`, "sys_mdb_update_multiple_found");
366
- }
367
- // Return updated: 0 if no documents were modified (though this is unlikely)
368
- return { updated: 0 };
369
- }
370
- catch (err) {
371
- if (err instanceof k2error_1.K2Error) {
372
- throw err;
373
- }
374
- // Catch any other unhandled errors and throw a system error
375
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, `Error updating ${collectionName}`, "sys_mdb_update_error", this.normalizeError(err));
376
- }
377
- }
378
- /**
379
- * Removes (soft deletes) multiple documents based on criteria.
380
- * @param collectionName - Name of the collection.
381
- * @param criteria - Removal criteria.
382
- */
383
- async deleteAll(collectionName, criteria) {
384
- this.validateCollectionName(collectionName);
385
- try {
386
- let result = await this.updateAll(collectionName, criteria, {
387
- _deleted: true,
388
- });
389
- return { deleted: result.updated };
390
- }
391
- catch (err) {
392
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, `Error updating ${collectionName}`, "sys_mdb_deleteall_update", this.normalizeError(err));
393
- }
394
- }
395
- /**
396
- * Removes (soft deletes) a single document by UUID.
397
- * @param collectionName - Name of the collection.
398
- * @param id - UUID of the document.
399
- */
400
- async delete(collectionName, id) {
401
- try {
402
- // Call deleteAll to soft delete the document by UUID
403
- const result = await this.deleteAll(collectionName, { _uuid: id });
404
- // Check the result of the deleteAll operation
405
- if (result.deleted === 1) {
406
- // Successfully deleted one document
407
- return { deleted: 1 };
408
- }
409
- else if (result.deleted === 0) {
410
- // No document was found to delete
411
- throw new k2error_1.K2Error(k2error_1.ServiceError.NOT_FOUND, "Document not found", "sys_mdb_remove_not_found");
412
- }
413
- else {
414
- // More than one document was deleted, which is unexpected
415
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Multiple documents deleted when only one was expected", "sys_mdb_remove_multiple_deleted");
416
- }
417
- }
418
- catch (err) {
419
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Error removing object from collection", "sys_mdb_remove_upd", this.normalizeError(err));
420
- }
421
- }
422
- /**
423
- * Permanently deletes a document that has been soft-deleted.
424
- * @param collectionName - Name of the collection.
425
- * @param id - UUID of the document.
426
- */
427
- async purge(collectionName, id) {
428
- const collection = await this.getCollection(collectionName);
429
- try {
430
- const item = await collection.findOne({
431
- _uuid: id,
432
- _deleted: true,
433
- });
434
- if (!item) {
435
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Cannot purge item that is not deleted", "sys_mdb_gcol_pg2");
436
- }
437
- await collection.deleteMany({ _uuid: id });
438
- return { id };
439
- }
440
- catch (err) {
441
- if (err instanceof k2error_1.K2Error) {
442
- throw err;
443
- }
444
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, `Error purging item with id: ${id}`, "sys_mdb_pg", this.normalizeError(err));
445
- }
446
- }
447
- /**
448
- * Restores a soft-deleted document.
449
- * @param collectionName - Name of the collection.
450
- * @param criteria - Criteria to identify the document.
451
- */
452
- async restore(collectionName, criteria) {
453
- const collection = await this.getCollection(collectionName);
454
- criteria._deleted = true;
455
- try {
456
- const res = await collection.updateMany(criteria, {
457
- $set: { _deleted: false },
458
- });
459
- return { status: "restored", modified: res.modifiedCount };
460
- }
461
- catch (err) {
462
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Error restoring a deleted item", "sys_mdb_pres", this.normalizeError(err));
463
- }
464
- }
465
- /**
466
- * Counts documents based on criteria.
467
- * @param collectionName - Name of the collection.
468
- * @param criteria - Counting criteria.
469
- */
470
- async count(collectionName, criteria) {
471
- const collection = await this.getCollection(collectionName);
472
- try {
473
- const cnt = await collection.countDocuments(criteria);
474
- return { count: cnt };
475
- }
476
- catch (err) {
477
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Error counting objects with given criteria", "sys_mdb_cn", this.normalizeError(err));
478
- }
479
- }
480
- /**
481
- * Drops an entire collection.
482
- * @param collectionName - Name of the collection.
483
- */
484
- async drop(collectionName) {
485
- const collection = await this.getCollection(collectionName);
486
- try {
487
- await collection.drop();
488
- return { status: "ok" };
489
- }
490
- catch (err) {
491
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Error dropping collection", "sys_mdb_drop", this.normalizeError(err));
492
- }
493
- }
494
- /**
495
- * Sanitizes aggregation criteria.
496
- * @param criteria - Aggregation stage criteria.
497
- */
498
- static sanitiseCriteria(criteria) {
499
- if (criteria.$match) {
500
- for (const key of Object.keys(criteria.$match)) {
501
- if (typeof criteria.$match[key] !== "string") {
502
- criteria.$match[key] = K2DB.sanitiseCriteria({
503
- [key]: criteria.$match[key],
504
- })[key];
505
- }
506
- else {
507
- if (key === "$exists") {
508
- criteria.$match[key] = criteria.$match[key] === "true";
509
- }
510
- }
511
- }
512
- }
513
- return criteria;
514
- }
515
- /**
516
- * Optional: Executes a transaction with the provided operations.
517
- * @param operations - A function that performs operations within a transaction session.
518
- */
519
- async executeTransaction(operations) {
520
- const session = this.connection.startSession();
521
- session.startTransaction();
522
- try {
523
- await operations(session);
524
- await session.commitTransaction();
525
- }
526
- catch (error) {
527
- await session.abortTransaction();
528
- throw this.normalizeError(error);
529
- }
530
- finally {
531
- session.endSession();
532
- }
533
- }
534
- /**
535
- * Optional: Creates an index on the specified collection.
536
- * @param collectionName - Name of the collection.
537
- * @param indexSpec - Specification of the index.
538
- * @param options - Optional index options.
539
- */
540
- async createIndex(collectionName, indexSpec, options) {
541
- const collection = await this.getCollection(collectionName);
542
- try {
543
- await collection.createIndex(indexSpec, options);
544
- debug(`Index created on ${collectionName}: ${JSON.stringify(indexSpec)}`);
545
- }
546
- catch (err) {
547
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, `Error creating index on ${collectionName}`, "sys_mdb_idx", this.normalizeError(err));
548
- }
549
- }
550
- /**
551
- * Releases the MongoDB connection.
552
- */
553
- async release() {
554
- await this.connection.close();
555
- debug("MongoDB connection released");
556
- }
557
- /**
558
- * Closes the MongoDB connection.
559
- */
560
- close() {
561
- this.connection.close();
562
- }
563
- /**
564
- * Drops the entire database.
565
- */
566
- async dropDatabase() {
567
- try {
568
- await this.db.dropDatabase();
569
- debug("Database dropped successfully");
570
- }
571
- catch (err) {
572
- throw new k2error_1.K2Error(k2error_1.ServiceError.SYSTEM_ERROR, "Error dropping database", "sys_mdb_drop_db", this.normalizeError(err));
573
- }
574
- }
575
- /**
576
- * Validates the MongoDB collection name.
577
- * @param collectionName - The name of the collection to validate.
578
- * @throws {K2Error} - If the collection name is invalid.
579
- */
580
- validateCollectionName(collectionName) {
581
- // Check for null character
582
- if (collectionName.includes("\0")) {
583
- throw new k2error_1.K2Error(k2error_1.ServiceError.BAD_REQUEST, "Collection name cannot contain null characters", "sys_mdb_invalid_collection_name");
584
- }
585
- // Check if it starts with 'system.'
586
- if (collectionName.startsWith("system.")) {
587
- throw new k2error_1.K2Error(k2error_1.ServiceError.BAD_REQUEST, "Collection name cannot start with 'system.'", "sys_mdb_invalid_collection_name");
588
- }
589
- // Check for invalid characters (e.g., '$')
590
- if (collectionName.includes("$")) {
591
- throw new k2error_1.K2Error(k2error_1.ServiceError.BAD_REQUEST, "Collection name cannot contain the '$' character", "sys_mdb_invalid_collection_name");
592
- }
593
- // Additional checks can be added here as needed
594
- }
595
- /**
596
- * Optional: Checks the health of the database connection.
597
- */
598
- async isHealthy() {
599
- try {
600
- await this.db.command({ ping: 1 });
601
- return true;
602
- }
603
- catch {
604
- return false;
605
- }
606
- }
607
- /**
608
- * Utility to normalize the error type.
609
- * @param err - The caught error of type `unknown`.
610
- * @returns A normalized error of type `Error`.
611
- */
612
- normalizeError(err) {
613
- return err instanceof Error ? err : new Error(String(err));
614
- }
615
- }
616
- exports.K2DB = K2DB;