@storehouse/mongodb 2.4.1 → 3.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 +369 -63
- package/lib/index.d.ts +291 -12
- package/lib/index.js +256 -34
- package/lib/index.js.map +1 -1
- package/package.json +19 -19
package/README.md
CHANGED
|
@@ -1,122 +1,428 @@
|
|
|
1
1
|
# @storehouse/mongodb
|
|
2
|
-
MongoDB driver manager for @storehouse/core.
|
|
3
2
|
|
|
4
|
-
[
|
|
3
|
+
MongoDB driver manager adapter for [@storehouse/core](https://www.npmjs.com/package/@storehouse/core). Provides seamless integration with [MongoDB](https://www.mongodb.com/) using the official [Node.js driver](https://www.npmjs.com/package/mongodb).
|
|
5
4
|
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- **Type-safe MongoDB operations** with TypeScript support
|
|
8
|
+
- **Connection lifecycle management** with automatic event logging
|
|
9
|
+
- **Health check utilities** for monitoring (works without admin privileges)
|
|
10
|
+
- **Multi-manager support** via Storehouse registry
|
|
11
|
+
- **Cross-database access** using dot notation
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
- **MongoDB server**
|
|
16
|
+
- **Node.js** 18 or higher
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
10
19
|
|
|
11
20
|
```bash
|
|
12
|
-
npm install @storehouse/mongodb
|
|
21
|
+
npm install @storehouse/core mongodb @storehouse/mongodb
|
|
13
22
|
```
|
|
14
23
|
|
|
15
|
-
##
|
|
24
|
+
## Quick Start
|
|
16
25
|
|
|
17
|
-
###
|
|
26
|
+
### 1. Define Your Types
|
|
18
27
|
|
|
19
|
-
|
|
28
|
+
**models/movie.ts**
|
|
20
29
|
```ts
|
|
21
30
|
export interface Movie {
|
|
22
31
|
title: string;
|
|
23
|
-
|
|
32
|
+
director: string;
|
|
33
|
+
year: number;
|
|
34
|
+
rating?: number;
|
|
24
35
|
}
|
|
25
36
|
```
|
|
26
37
|
|
|
27
|
-
|
|
38
|
+
### 2. Register the Manager
|
|
39
|
+
|
|
40
|
+
**index.ts**
|
|
28
41
|
```ts
|
|
29
|
-
import Storehouse from '@storehouse/core';
|
|
30
|
-
import {
|
|
42
|
+
import { Storehouse } from '@storehouse/core';
|
|
43
|
+
import { MongoDbManager } from '@storehouse/mongodb';
|
|
31
44
|
|
|
32
|
-
//
|
|
45
|
+
// Register the manager
|
|
33
46
|
Storehouse.add({
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
type: MongoDBManager,
|
|
47
|
+
mongodb: {
|
|
48
|
+
type: MongoDbManager,
|
|
37
49
|
config: {
|
|
38
|
-
|
|
39
|
-
url: 'mongodb://localhost:27017/database',
|
|
40
|
-
|
|
50
|
+
url: 'mongodb://localhost:27017/mydb',
|
|
41
51
|
// MongoClientOptions
|
|
42
52
|
options: {
|
|
43
|
-
|
|
53
|
+
maxPoolSize: 10,
|
|
54
|
+
minPoolSize: 5
|
|
44
55
|
}
|
|
45
56
|
}
|
|
46
57
|
}
|
|
47
58
|
});
|
|
48
59
|
```
|
|
49
60
|
|
|
50
|
-
|
|
61
|
+
### 3. Connect and Use
|
|
51
62
|
|
|
52
63
|
```ts
|
|
53
|
-
import Storehouse from '@storehouse/core';
|
|
54
|
-
import {
|
|
64
|
+
import { Storehouse } from '@storehouse/core';
|
|
65
|
+
import { MongoDbManager } from '@storehouse/mongodb';
|
|
55
66
|
import { Collection, MongoClient } from 'mongodb';
|
|
56
|
-
import { Movie } from './
|
|
67
|
+
import { Movie } from './models/movie';
|
|
68
|
+
|
|
69
|
+
// Get the manager and connect
|
|
70
|
+
const manager = Storehouse.getManager<MongoDbManager>('mongodb');
|
|
57
71
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
if (manager) {
|
|
73
|
+
// Open the connection
|
|
74
|
+
await manager.connect();
|
|
75
|
+
|
|
76
|
+
console.log('Connected to database:', manager.db().databaseName);
|
|
77
|
+
|
|
78
|
+
// Get a collection
|
|
79
|
+
const moviesCollection = manager.getModel<Movie>('movies');
|
|
80
|
+
|
|
81
|
+
// Insert a document
|
|
82
|
+
await moviesCollection.insertOne({
|
|
83
|
+
title: 'Sinners',
|
|
84
|
+
director: 'Ryan Coogler',
|
|
85
|
+
year: 2025,
|
|
86
|
+
rating: 8.5
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Query documents
|
|
90
|
+
const movies = await moviesCollection.find({ year: { $gte: 2010 } }).toArray();
|
|
91
|
+
console.log('Movies:', movies);
|
|
92
|
+
|
|
93
|
+
// Count documents
|
|
94
|
+
const count = await moviesCollection.countDocuments();
|
|
95
|
+
console.log('Total movies:', count);
|
|
62
96
|
}
|
|
97
|
+
```
|
|
63
98
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
99
|
+
## API Reference
|
|
100
|
+
|
|
101
|
+
### Helper Functions
|
|
102
|
+
|
|
103
|
+
The package provides helper functions that throw errors instead of returning undefined, making your code cleaner and safer.
|
|
104
|
+
|
|
105
|
+
#### `getManager()`
|
|
106
|
+
|
|
107
|
+
Retrieves a MongoDbManager instance from the registry.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { Storehouse } from '@storehouse/core';
|
|
111
|
+
import { getManager } from '@storehouse/mongodb';
|
|
112
|
+
|
|
113
|
+
const manager = getManager(Storehouse, 'mongodb');
|
|
114
|
+
await manager.connect();
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Throws:**
|
|
118
|
+
- `ManagerNotFoundError` - If the manager doesn't exist
|
|
119
|
+
- `InvalidManagerConfigError` - If the manager is not a MongoDbManager instance
|
|
120
|
+
|
|
121
|
+
#### `getConnection()`
|
|
122
|
+
|
|
123
|
+
Retrieves the underlying MongoDB client connection.
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import { Storehouse } from '@storehouse/core';
|
|
127
|
+
import { getConnection } from '@storehouse/mongodb';
|
|
128
|
+
|
|
129
|
+
const client = getConnection(Storehouse, 'mongodb');
|
|
130
|
+
await client.connect();
|
|
131
|
+
|
|
132
|
+
// Access the database
|
|
133
|
+
const db = client.db('mydb');
|
|
134
|
+
const collections = await db.listCollections().toArray();
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Throws:**
|
|
138
|
+
- `ManagerNotFoundError` - If the manager doesn't exist
|
|
139
|
+
- `InvalidManagerConfigError` - If the manager is not a MongoClient instance
|
|
140
|
+
|
|
141
|
+
#### `getModel()`
|
|
142
|
+
|
|
143
|
+
Retrieves a MongoDB Collection by name.
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { Storehouse } from '@storehouse/core';
|
|
147
|
+
import { getModel } from '@storehouse/mongodb';
|
|
148
|
+
import { Movie } from './models/movie';
|
|
149
|
+
|
|
150
|
+
// Get model from default manager
|
|
151
|
+
const movies = getModel<Movie>(Storehouse, 'movies');
|
|
152
|
+
|
|
153
|
+
// Get model from specific manager
|
|
154
|
+
const users = getModel(Storehouse, 'mongodb', 'users');
|
|
155
|
+
|
|
156
|
+
// Use the collection
|
|
157
|
+
const count = await movies.countDocuments();
|
|
158
|
+
console.log('Total movies:', count);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Throws:**
|
|
162
|
+
- `ModelNotFoundError` - If the model doesn't exist
|
|
163
|
+
|
|
164
|
+
### MongoDbManager Class
|
|
165
|
+
|
|
166
|
+
#### Methods
|
|
167
|
+
|
|
168
|
+
##### `connect(): Promise<this>`
|
|
169
|
+
|
|
170
|
+
Establishes connection to MongoDB.
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
await manager.connect();
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
##### `close(force?: boolean): Promise<void>`
|
|
177
|
+
|
|
178
|
+
Closes the MongoDB connection.
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
// Graceful close
|
|
182
|
+
await manager.close();
|
|
183
|
+
|
|
184
|
+
// Force close
|
|
185
|
+
await manager.close(true);
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
##### `closeConnection(force?: boolean): Promise<void>`
|
|
189
|
+
|
|
190
|
+
Alias for `close()`. Closes the MongoDB connection.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
await manager.closeConnection();
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
##### `getConnection(): MongoClient`
|
|
197
|
+
|
|
198
|
+
Returns the underlying MongoDB client instance.
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
const client = manager.getConnection();
|
|
202
|
+
const db = client.db('mydb');
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
##### `getModel<T>(name: string): Collection<T>`
|
|
206
|
+
|
|
207
|
+
Retrieves a MongoDB collection by name. Supports dot notation for cross-database access.
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
// Get collection from default database
|
|
211
|
+
const movies = manager.getModel<Movie>('movies');
|
|
212
|
+
|
|
213
|
+
// Get collection from specific database
|
|
214
|
+
const users = manager.getModel('otherdb.users');
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
##### `isConnected(): Promise<boolean>`
|
|
218
|
+
|
|
219
|
+
Checks if the connection is currently active. Works without admin privileges.
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
const connected = await manager.isConnected();
|
|
223
|
+
if (connected) {
|
|
224
|
+
console.log('MongoDB is connected');
|
|
72
225
|
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
##### `healthCheck(): Promise<MongoDbHealthCheckResult>`
|
|
229
|
+
|
|
230
|
+
Performs a comprehensive health check including ping test and latency measurement. Works without admin privileges.
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
const health = await manager.healthCheck();
|
|
73
234
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
console.log(
|
|
235
|
+
if (health.healthy) {
|
|
236
|
+
console.log(`✓ MongoDB is healthy`);
|
|
237
|
+
console.log(` Database: ${health.details.databaseName}`);
|
|
238
|
+
console.log(` Latency: ${health.details.latency}`);
|
|
239
|
+
} else {
|
|
240
|
+
console.error(`✗ MongoDB is unhealthy: ${health.message}`);
|
|
78
241
|
}
|
|
79
242
|
```
|
|
80
243
|
|
|
81
|
-
###
|
|
244
|
+
### Health Check Result
|
|
245
|
+
|
|
246
|
+
The health check returns a detailed result object:
|
|
247
|
+
|
|
248
|
+
- `healthy: boolean` - Overall health status
|
|
249
|
+
- `message: string` - Descriptive message about the health status
|
|
250
|
+
- `timestamp: number` - Timestamp when the health check was performed
|
|
251
|
+
- `latency?: number` - Response time in milliseconds
|
|
252
|
+
- `details: object` - Detailed connection information
|
|
253
|
+
- `name: string` - Manager name
|
|
254
|
+
- `isOpen: boolean` - Connection open status
|
|
255
|
+
- `isReady: boolean` - Connection ready status
|
|
256
|
+
- `pingResponse?: Document` - MongoDB ping response
|
|
257
|
+
- `latency?: string` - Response time in ms
|
|
258
|
+
- `error?: string` - Error details (if unhealthy)
|
|
259
|
+
|
|
260
|
+
## Advanced Usage
|
|
261
|
+
|
|
262
|
+
### Multiple Managers
|
|
263
|
+
|
|
264
|
+
You can register multiple MongoDB connections:
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
import { Storehouse } from '@storehouse/core';
|
|
268
|
+
import { MongoDbManager, getManager } from '@storehouse/mongodb';
|
|
269
|
+
|
|
270
|
+
Storehouse.add({
|
|
271
|
+
primary: {
|
|
272
|
+
type: MongoDbManager,
|
|
273
|
+
config: {
|
|
274
|
+
url: 'mongodb://localhost:27017/maindb'
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
analytics: {
|
|
278
|
+
type: MongoDbManager,
|
|
279
|
+
config: {
|
|
280
|
+
url: 'mongodb://localhost:27017/analyticsdb'
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Access specific managers
|
|
286
|
+
const primaryManager = getManager(Storehouse, 'primary');
|
|
287
|
+
const analyticsManager = getManager(Storehouse, 'analytics');
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Using the Manager Type
|
|
291
|
+
|
|
292
|
+
Set the manager type to simplify configuration and use string identifiers instead of class references:
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
import { Storehouse } from '@storehouse/core';
|
|
296
|
+
import { MongoDbManager } from '@storehouse/mongodb';
|
|
297
|
+
|
|
298
|
+
// Set default manager type
|
|
299
|
+
Storehouse.setManagerType(MongoDbManager);
|
|
300
|
+
|
|
301
|
+
// Now you can use type string instead of class
|
|
302
|
+
Storehouse.add({
|
|
303
|
+
mongodb: {
|
|
304
|
+
type: '@storehouse/mongodb',
|
|
305
|
+
config: {
|
|
306
|
+
url: 'mongodb://localhost:27017/mydb'
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Cross-Database Access
|
|
82
313
|
|
|
83
|
-
|
|
84
|
-
Those methods throw an error when they fail.
|
|
314
|
+
Access collections from different databases sharing the same socket connection using dot notation:
|
|
85
315
|
|
|
86
316
|
```ts
|
|
87
|
-
import Storehouse from '@storehouse/core';
|
|
88
|
-
import {
|
|
89
|
-
|
|
90
|
-
|
|
317
|
+
import { Storehouse } from '@storehouse/core';
|
|
318
|
+
import { getModel } from '@storehouse/mongodb';
|
|
319
|
+
|
|
320
|
+
// Access collection from another database
|
|
321
|
+
const otherDbMovies = getModel(Storehouse, 'mongodb', 'otherdatabase.movies');
|
|
322
|
+
|
|
323
|
+
// Or using Storehouse directly
|
|
324
|
+
const Movies = Storehouse.getModel('mongodb', 'otherdatabase.movies');
|
|
91
325
|
|
|
92
|
-
//
|
|
93
|
-
const
|
|
94
|
-
|
|
326
|
+
// Query the collection
|
|
327
|
+
const movies = await otherDbMovies?.find({}).toArray();
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
The format is: `<database-name>.<collection-name>`
|
|
331
|
+
|
|
332
|
+
### Connection Event Handling
|
|
333
|
+
|
|
334
|
+
The manager automatically logs connection lifecycle events. These are logged using the `@novice1/logger` package and can be enabled with Debug mode:
|
|
95
335
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
manager.getModel<Collection<Movie>>('movies');
|
|
336
|
+
```ts
|
|
337
|
+
import { Debug } from '@novice1/logger';
|
|
99
338
|
|
|
100
|
-
|
|
101
|
-
const Movies = getModel<Movie>(Storehouse, 'local', 'movies');
|
|
102
|
-
console.log('nb movies', await Movies.countDocuments());
|
|
339
|
+
Debug.enable('@storehouse/mongodb*');
|
|
103
340
|
```
|
|
104
341
|
|
|
105
|
-
|
|
342
|
+
**Events logged:**
|
|
343
|
+
- `topologyOpening` - Connection initiated
|
|
344
|
+
- `serverOpening` - Server connection established
|
|
345
|
+
- `serverClosed` - Server connection closed
|
|
346
|
+
- `topologyClosed` - Connection closed
|
|
347
|
+
- `error` - Connection errors
|
|
348
|
+
|
|
349
|
+
## TypeScript Support
|
|
106
350
|
|
|
107
|
-
|
|
108
|
-
To get access to a collection from another database with the method `getModel`, the name of the model should be in the following format: `<database-name>.<collection-name>`.
|
|
351
|
+
The package is written in TypeScript and provides full type definitions for type-safe operations:
|
|
109
352
|
|
|
110
353
|
```ts
|
|
111
|
-
|
|
354
|
+
import { Storehouse } from '@storehouse/core';
|
|
355
|
+
import { MongoClient, Collection } from 'mongodb';
|
|
356
|
+
import { MongoDbManager, getManager, getConnection, getModel } from '@storehouse/mongodb';
|
|
357
|
+
|
|
358
|
+
// Typed manager
|
|
359
|
+
const manager = getManager<MongoDbManager>(Storehouse, 'mongodb');
|
|
360
|
+
|
|
361
|
+
// Typed connection
|
|
362
|
+
const client: MongoClient = getConnection(Storehouse, 'mongodb');
|
|
363
|
+
|
|
364
|
+
// Typed collection with document interface
|
|
365
|
+
interface User {
|
|
366
|
+
name: string;
|
|
367
|
+
email: string;
|
|
368
|
+
age: number;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const users = getModel<User>(Storehouse, 'mongodb', 'users');
|
|
372
|
+
// users is typed as Collection<User>
|
|
373
|
+
|
|
374
|
+
// Type-safe operations
|
|
375
|
+
const allUsers = await users.find({}).toArray();
|
|
376
|
+
// allUsers is typed as User[]
|
|
112
377
|
```
|
|
378
|
+
|
|
379
|
+
## Error Handling
|
|
380
|
+
|
|
381
|
+
All helper functions throw specific errors for better error handling:
|
|
382
|
+
|
|
113
383
|
```ts
|
|
114
|
-
|
|
384
|
+
import { Storehouse } from '@storehouse/core';
|
|
385
|
+
import { getManager, getModel, getConnection } from '@storehouse/mongodb';
|
|
386
|
+
import {
|
|
387
|
+
ManagerNotFoundError,
|
|
388
|
+
ModelNotFoundError,
|
|
389
|
+
InvalidManagerConfigError
|
|
390
|
+
} from '@storehouse/core';
|
|
391
|
+
|
|
392
|
+
try {
|
|
393
|
+
const manager = getManager(Storehouse, 'nonexistent');
|
|
394
|
+
} catch (error) {
|
|
395
|
+
if (error instanceof ManagerNotFoundError) {
|
|
396
|
+
console.error('Manager not found:', error.message);
|
|
397
|
+
} else if (error instanceof InvalidManagerConfigError) {
|
|
398
|
+
console.error('Invalid manager type:', error.message);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
try {
|
|
403
|
+
const model = getModel(Storehouse, 'nonexistent');
|
|
404
|
+
} catch (error) {
|
|
405
|
+
if (error instanceof ModelNotFoundError) {
|
|
406
|
+
console.error('Model not found:', error.message);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
115
409
|
```
|
|
116
410
|
|
|
117
|
-
##
|
|
411
|
+
## Best Practices
|
|
412
|
+
|
|
413
|
+
1. **Always connect** - Call `connect()` after registering the manager to establish the connection
|
|
414
|
+
2. **Use health checks** - Monitor connection health in production environments
|
|
415
|
+
3. **Handle disconnections** - Implement reconnection and retry logic for critical operations
|
|
416
|
+
4. **Close connections** - Always call `close()` when shutting down your application
|
|
417
|
+
5. **Use TypeScript** - Leverage type definitions for safer database operations
|
|
418
|
+
|
|
419
|
+
## Resources
|
|
118
420
|
|
|
119
421
|
- [Documentation](https://kisiwu.github.io/storehouse/mongodb/latest/)
|
|
120
422
|
- [@storehouse/core](https://www.npmjs.com/package/@storehouse/core)
|
|
121
|
-
- [
|
|
423
|
+
- [MongoDB Node.js Driver](https://www.npmjs.com/package/mongodb)
|
|
424
|
+
- [MongoDB Documentation](https://www.mongodb.com/docs/)
|
|
425
|
+
|
|
426
|
+
## License
|
|
122
427
|
|
|
428
|
+
MIT
|
package/lib/index.d.ts
CHANGED
|
@@ -1,28 +1,307 @@
|
|
|
1
|
-
import { IManager, ManagerArg } from '@storehouse/core
|
|
2
|
-
import { Registry } from '@storehouse/core/lib/registry';
|
|
1
|
+
import { HealthCheckResult, IManager, ManagerArg, Registry } from '@storehouse/core';
|
|
3
2
|
import { MongoClient, MongoClientOptions, Document, Collection } from 'mongodb';
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Configuration argument for creating a MongoDbManager instance.
|
|
5
|
+
*
|
|
6
|
+
* @extends ManagerArg
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const managerArg: MongoDbManagerArg = {
|
|
11
|
+
* name: 'my-mongodb-manager',
|
|
12
|
+
* config: {
|
|
13
|
+
* url: 'mongodb://localhost:27017/mydb',
|
|
14
|
+
* options: {
|
|
15
|
+
* maxPoolSize: 10
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* };
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export interface MongoDbManagerArg extends ManagerArg {
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for the MongoDB connection.
|
|
24
|
+
*/
|
|
5
25
|
config?: {
|
|
26
|
+
/**
|
|
27
|
+
* MongoDB connection URL.
|
|
28
|
+
* @example 'mongodb://localhost:27017/mydb'
|
|
29
|
+
*/
|
|
6
30
|
url: string;
|
|
31
|
+
/**
|
|
32
|
+
* MongoDB client connection options.
|
|
33
|
+
* See MongoDB driver documentation for available options.
|
|
34
|
+
*/
|
|
7
35
|
options?: MongoClientOptions;
|
|
8
36
|
};
|
|
9
37
|
}
|
|
10
38
|
/**
|
|
39
|
+
* Retrieves a MongoDB Collection (model) from the registry.
|
|
40
|
+
*
|
|
41
|
+
* This function has two overload signatures:
|
|
42
|
+
* 1. When called with 2 arguments, retrieves the model using the second argument as the model name from the default manager
|
|
43
|
+
* 2. When called with 3 arguments, retrieves the model from a specific manager
|
|
44
|
+
*
|
|
45
|
+
* @template T - The document type for the collection, defaults to Document
|
|
11
46
|
*
|
|
12
|
-
* @param registry
|
|
13
|
-
* @param
|
|
14
|
-
* @
|
|
15
|
-
*
|
|
47
|
+
* @param registry - The Storehouse registry containing registered managers and models
|
|
48
|
+
* @param modelName - When used with 2 arguments, this is the name of the model to retrieve
|
|
49
|
+
* @returns The requested MongoDB Collection
|
|
50
|
+
*
|
|
51
|
+
* @throws {ModelNotFoundError} If the model is not found in the registry
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* // Get model from default manager
|
|
56
|
+
* const users = getModel(registry, 'users');
|
|
57
|
+
* const allUsers = await users.find({}).toArray();
|
|
58
|
+
*
|
|
59
|
+
* // With type parameter
|
|
60
|
+
* interface User {
|
|
61
|
+
* name: string;
|
|
62
|
+
* email: string;
|
|
63
|
+
* }
|
|
64
|
+
* const users = getModel<User>(registry, 'users');
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function getModel<T extends Document = Document>(registry: Registry, modelName: string): Collection<T>;
|
|
68
|
+
/**
|
|
69
|
+
* Retrieves a MongoDB Collection (model) from a specific manager in the registry.
|
|
70
|
+
*
|
|
71
|
+
* @template T - The document type for the collection, defaults to Document
|
|
72
|
+
*
|
|
73
|
+
* @param registry - The Storehouse registry containing registered managers and models
|
|
74
|
+
* @param managerName - The name of the manager containing the model
|
|
75
|
+
* @param modelName - The name of the specific model to retrieve
|
|
76
|
+
* @returns The requested MongoDB Collection
|
|
77
|
+
*
|
|
78
|
+
* @throws {ModelNotFoundError} If the model is not found in the registry
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* // Get model from specific manager
|
|
83
|
+
* const users = getModel(registry, 'mongodb', 'users');
|
|
84
|
+
*
|
|
85
|
+
* // With type parameter
|
|
86
|
+
* interface Product {
|
|
87
|
+
* title: string;
|
|
88
|
+
* price: number;
|
|
89
|
+
* }
|
|
90
|
+
* const products = getModel<Product>(registry, 'mongodb', 'products');
|
|
91
|
+
* const allProducts = await products.find({}).toArray();
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export declare function getModel<T extends Document = Document>(registry: Registry, managerName: string, modelName: string): Collection<T>;
|
|
95
|
+
/**
|
|
96
|
+
* Retrieves a MongoDbManager instance from the registry.
|
|
97
|
+
*
|
|
98
|
+
* @template M - The specific MongoDbManager type to return, defaults to MongoDbManager
|
|
99
|
+
*
|
|
100
|
+
* @param registry - The Storehouse registry containing registered managers
|
|
101
|
+
* @param managerName - Optional name of the manager to retrieve. If omitted, retrieves the default manager
|
|
102
|
+
*
|
|
103
|
+
* @returns The requested MongoDbManager instance
|
|
104
|
+
*
|
|
105
|
+
* @throws {ManagerNotFoundError} If the manager is not found in the registry
|
|
106
|
+
* @throws {InvalidManagerConfigError} If the manager exists but is not an instance of MongoDbManager
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* const mongoManager = getManager(registry, 'mongodb');
|
|
111
|
+
* await mongoManager.connect();
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export declare function getManager<M extends MongoDbManager = MongoDbManager>(registry: Registry, managerName?: string): M;
|
|
115
|
+
/**
|
|
116
|
+
* Retrieves the underlying MongoDB client connection from a manager in the registry.
|
|
117
|
+
*
|
|
118
|
+
* @param registry - The Storehouse registry containing registered managers
|
|
119
|
+
* @param managerName - Optional name of the manager. If omitted, uses the default manager
|
|
120
|
+
*
|
|
121
|
+
* @returns The MongoDB client instance
|
|
122
|
+
*
|
|
123
|
+
* @throws {ManagerNotFoundError} If the manager is not found in the registry
|
|
124
|
+
* @throws {InvalidManagerConfigError} If the connection is not an instance of MongoClient
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* const client = getConnection(registry, 'mongodb');
|
|
129
|
+
* const admin = client.db().admin();
|
|
130
|
+
* const dbs = await admin.listDatabases();
|
|
131
|
+
* ```
|
|
16
132
|
*/
|
|
17
|
-
export declare function getModel<T extends Document = Document>(registry: Registry, managerName: string, modelName?: string): Collection<T>;
|
|
18
|
-
export declare function getManager<M extends MongoDBManager = MongoDBManager>(registry: Registry, managerName?: string): M;
|
|
19
133
|
export declare function getConnection(registry: Registry, managerName?: string): MongoClient;
|
|
20
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Extended health check result specific to MongoDB managers.
|
|
136
|
+
* Includes MongoDB connection status and ping response.
|
|
137
|
+
*
|
|
138
|
+
* @extends HealthCheckResult
|
|
139
|
+
*/
|
|
140
|
+
export interface MongoDbHealthCheckResult extends HealthCheckResult {
|
|
141
|
+
/**
|
|
142
|
+
* Detailed information about the MongoDB connection health.
|
|
143
|
+
*/
|
|
144
|
+
details: {
|
|
145
|
+
/** The name of the manager */
|
|
146
|
+
name: string;
|
|
147
|
+
/** The name of the database */
|
|
148
|
+
databaseName?: string;
|
|
149
|
+
/** Whether the MongoDB connection is currently open */
|
|
150
|
+
isOpen: boolean;
|
|
151
|
+
/** Whether the MongoDB connection is ready to accept commands */
|
|
152
|
+
isReady: boolean;
|
|
153
|
+
/** The response from the MongoDB PING command */
|
|
154
|
+
pingResponse?: Document;
|
|
155
|
+
/** Time taken to perform the health check in milliseconds */
|
|
156
|
+
latency?: string;
|
|
157
|
+
/** Error message if the health check failed */
|
|
158
|
+
error?: string;
|
|
159
|
+
/** Additional custom properties */
|
|
160
|
+
[key: string]: unknown;
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Manager class for MongoDB integration with Storehouse.
|
|
165
|
+
* Provides connection management, model registration, and health checking for MongoDB databases.
|
|
166
|
+
*
|
|
167
|
+
* This manager extends the MongoDB MongoClient, offering a unified interface
|
|
168
|
+
* for working with MongoDB databases through the Storehouse registry system.
|
|
169
|
+
*
|
|
170
|
+
* @extends MongoClient
|
|
171
|
+
* @implements {IManager}
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* const manager = new MongoDbManager({
|
|
176
|
+
* name: 'mongodb-main',
|
|
177
|
+
* config: {
|
|
178
|
+
* url: 'mongodb://localhost:27017/mydb',
|
|
179
|
+
* options: {
|
|
180
|
+
* maxPoolSize: 10,
|
|
181
|
+
* minPoolSize: 5
|
|
182
|
+
* }
|
|
183
|
+
* }
|
|
184
|
+
* });
|
|
185
|
+
*
|
|
186
|
+
* await manager.connect();
|
|
187
|
+
*
|
|
188
|
+
* const usersCollection = manager.getModel('users');
|
|
189
|
+
* const users = await usersCollection.find({}).toArray();
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
export declare class MongoDbManager extends MongoClient implements IManager {
|
|
193
|
+
#private;
|
|
194
|
+
/**
|
|
195
|
+
* Identifier for the manager type.
|
|
196
|
+
* @readonly
|
|
197
|
+
*/
|
|
21
198
|
static readonly type = "@storehouse/mongodb";
|
|
199
|
+
/**
|
|
200
|
+
* The name of this manager instance.
|
|
201
|
+
* @protected
|
|
202
|
+
*/
|
|
22
203
|
protected name: string;
|
|
23
|
-
|
|
24
|
-
|
|
204
|
+
/**
|
|
205
|
+
* Creates a new MongoDbManager instance.
|
|
206
|
+
*
|
|
207
|
+
* @param settings - Configuration settings for the manager
|
|
208
|
+
*
|
|
209
|
+
* @throws {InvalidManagerConfigError} If the connection URL is missing
|
|
210
|
+
*
|
|
211
|
+
* @remarks
|
|
212
|
+
* The connection is created but not opened. You must call `connect()` to establish the connection.
|
|
213
|
+
* Connection events (topologyOpening, serverOpening, serverClosed, topologyClosed, error) are automatically registered and logged.
|
|
214
|
+
*/
|
|
215
|
+
constructor(settings: MongoDbManagerArg);
|
|
216
|
+
/**
|
|
217
|
+
* Gets the underlying MongoDB client connection.
|
|
218
|
+
*
|
|
219
|
+
* @returns The MongoDB client instance (this instance)
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```typescript
|
|
223
|
+
* const client = manager.getConnection();
|
|
224
|
+
* const db = client.db('mydb');
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
25
227
|
getConnection(): MongoClient;
|
|
228
|
+
/**
|
|
229
|
+
* Closes the MongoDB connection.
|
|
230
|
+
*
|
|
231
|
+
* @param force - Optional flag to force close the connection, bypassing any connection pool cleanup
|
|
232
|
+
* @returns A promise that resolves when the connection is closed
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```typescript
|
|
236
|
+
* // Graceful close
|
|
237
|
+
* await manager.closeConnection();
|
|
238
|
+
*
|
|
239
|
+
* // Force close
|
|
240
|
+
* await manager.closeConnection(true);
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
26
243
|
closeConnection(force?: boolean): Promise<void>;
|
|
244
|
+
/**
|
|
245
|
+
* Retrieves a MongoDB collection by name.
|
|
246
|
+
* Supports dot notation for database.collection format.
|
|
247
|
+
*
|
|
248
|
+
* @template T - The document type for the collection, defaults to Document
|
|
249
|
+
*
|
|
250
|
+
* @param name - The name of the collection, or database.collection format
|
|
251
|
+
* @returns The MongoDB Collection instance
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```typescript
|
|
255
|
+
* // Get collection from default database
|
|
256
|
+
* const users = manager.getModel('users');
|
|
257
|
+
*
|
|
258
|
+
* // Get collection with specific database
|
|
259
|
+
* const users = manager.getModel('mydb.users');
|
|
260
|
+
*
|
|
261
|
+
* // With type parameter
|
|
262
|
+
* interface User {
|
|
263
|
+
* name: string;
|
|
264
|
+
* email: string;
|
|
265
|
+
* }
|
|
266
|
+
* const users = manager.getModel<User>('users');
|
|
267
|
+
* ```
|
|
268
|
+
*/
|
|
27
269
|
getModel<T extends Document = Document>(name: string): Collection<T>;
|
|
270
|
+
/**
|
|
271
|
+
* Checks if the MongoDB connection is currently active.
|
|
272
|
+
* Uses a simple ping command that doesn't require admin privileges.
|
|
273
|
+
*
|
|
274
|
+
* @returns A promise that resolves to true if connected, false otherwise
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* if (await manager.isConnected()) {
|
|
279
|
+
* console.log('MongoDB is connected');
|
|
280
|
+
* }
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
isConnected(): Promise<boolean>;
|
|
284
|
+
/**
|
|
285
|
+
* Performs a comprehensive health check on the MongoDB connection.
|
|
286
|
+
* Tests connectivity by sending a PING command and gathering connection metrics.
|
|
287
|
+
* This method works with restricted database access (non-admin users).
|
|
288
|
+
*
|
|
289
|
+
* @returns A promise that resolves to a detailed health check result including:
|
|
290
|
+
* - Connection status (open/ready)
|
|
291
|
+
* - Ping response
|
|
292
|
+
* - Response latency
|
|
293
|
+
* - Error details (if unhealthy)
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```typescript
|
|
297
|
+
* const health = await manager.healthCheck();
|
|
298
|
+
* if (health.healthy) {
|
|
299
|
+
* console.log(`MongoDB is healthy. Latency: ${health.details.latency}`);
|
|
300
|
+
* console.log(`Ping response:`, health.details.pingResponse);
|
|
301
|
+
* } else {
|
|
302
|
+
* console.error(`MongoDB is unhealthy: ${health.message}`);
|
|
303
|
+
* }
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
healthCheck(): Promise<MongoDbHealthCheckResult>;
|
|
28
307
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,72 +1,161 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var _MongoDbManager_instances, _MongoDbManager_registerConnectionEvents;
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
+
exports.MongoDbManager = void 0;
|
|
4
5
|
exports.getModel = getModel;
|
|
5
6
|
exports.getManager = getManager;
|
|
6
7
|
exports.getConnection = getConnection;
|
|
7
8
|
const tslib_1 = require("tslib");
|
|
9
|
+
const core_1 = require("@storehouse/core");
|
|
8
10
|
const mongodb_1 = require("mongodb");
|
|
9
11
|
const logger_1 = tslib_1.__importDefault(require("@novice1/logger"));
|
|
12
|
+
const node_crypto_1 = require("node:crypto");
|
|
10
13
|
const Log = logger_1.default.debugger('@storehouse/mongodb:manager');
|
|
11
|
-
/**
|
|
12
|
-
*
|
|
13
|
-
* @param registry
|
|
14
|
-
* @param manager Manager name or model name
|
|
15
|
-
* @param modelName Model name
|
|
16
|
-
* @returns
|
|
17
|
-
*/
|
|
18
14
|
function getModel(registry, managerName, modelName) {
|
|
19
15
|
const model = registry.getModel(managerName, modelName);
|
|
20
16
|
if (!model) {
|
|
21
|
-
throw new
|
|
17
|
+
throw new core_1.ModelNotFoundError(modelName || managerName, modelName ? managerName : undefined);
|
|
22
18
|
}
|
|
23
19
|
return model;
|
|
24
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Retrieves a MongoDbManager instance from the registry.
|
|
23
|
+
*
|
|
24
|
+
* @template M - The specific MongoDbManager type to return, defaults to MongoDbManager
|
|
25
|
+
*
|
|
26
|
+
* @param registry - The Storehouse registry containing registered managers
|
|
27
|
+
* @param managerName - Optional name of the manager to retrieve. If omitted, retrieves the default manager
|
|
28
|
+
*
|
|
29
|
+
* @returns The requested MongoDbManager instance
|
|
30
|
+
*
|
|
31
|
+
* @throws {ManagerNotFoundError} If the manager is not found in the registry
|
|
32
|
+
* @throws {InvalidManagerConfigError} If the manager exists but is not an instance of MongoDbManager
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const mongoManager = getManager(registry, 'mongodb');
|
|
37
|
+
* await mongoManager.connect();
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
25
40
|
function getManager(registry, managerName) {
|
|
26
41
|
const manager = registry.getManager(managerName);
|
|
27
42
|
if (!manager) {
|
|
28
|
-
throw new
|
|
43
|
+
throw new core_1.ManagerNotFoundError(managerName || registry.defaultManager);
|
|
29
44
|
}
|
|
30
|
-
if (!(manager instanceof
|
|
31
|
-
throw new
|
|
45
|
+
if (!(manager instanceof MongoDbManager)) {
|
|
46
|
+
throw new core_1.InvalidManagerConfigError(`Manager "${managerName || registry.defaultManager}" is not instance of MongoDbManager`);
|
|
32
47
|
}
|
|
33
48
|
return manager;
|
|
34
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Retrieves the underlying MongoDB client connection from a manager in the registry.
|
|
52
|
+
*
|
|
53
|
+
* @param registry - The Storehouse registry containing registered managers
|
|
54
|
+
* @param managerName - Optional name of the manager. If omitted, uses the default manager
|
|
55
|
+
*
|
|
56
|
+
* @returns The MongoDB client instance
|
|
57
|
+
*
|
|
58
|
+
* @throws {ManagerNotFoundError} If the manager is not found in the registry
|
|
59
|
+
* @throws {InvalidManagerConfigError} If the connection is not an instance of MongoClient
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const client = getConnection(registry, 'mongodb');
|
|
64
|
+
* const admin = client.db().admin();
|
|
65
|
+
* const dbs = await admin.listDatabases();
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
35
68
|
function getConnection(registry, managerName) {
|
|
36
69
|
const conn = registry.getConnection(managerName);
|
|
37
70
|
if (!conn) {
|
|
38
|
-
throw new
|
|
71
|
+
throw new core_1.ManagerNotFoundError(managerName || registry.defaultManager);
|
|
72
|
+
}
|
|
73
|
+
if (!(conn instanceof mongodb_1.MongoClient)) {
|
|
74
|
+
throw new core_1.InvalidManagerConfigError(`Connection "${managerName || registry.defaultManager}" is not instance of MongoClient`);
|
|
39
75
|
}
|
|
40
76
|
return conn;
|
|
41
77
|
}
|
|
42
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Manager class for MongoDB integration with Storehouse.
|
|
80
|
+
* Provides connection management, model registration, and health checking for MongoDB databases.
|
|
81
|
+
*
|
|
82
|
+
* This manager extends the MongoDB MongoClient, offering a unified interface
|
|
83
|
+
* for working with MongoDB databases through the Storehouse registry system.
|
|
84
|
+
*
|
|
85
|
+
* @extends MongoClient
|
|
86
|
+
* @implements {IManager}
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const manager = new MongoDbManager({
|
|
91
|
+
* name: 'mongodb-main',
|
|
92
|
+
* config: {
|
|
93
|
+
* url: 'mongodb://localhost:27017/mydb',
|
|
94
|
+
* options: {
|
|
95
|
+
* maxPoolSize: 10,
|
|
96
|
+
* minPoolSize: 5
|
|
97
|
+
* }
|
|
98
|
+
* }
|
|
99
|
+
* });
|
|
100
|
+
*
|
|
101
|
+
* await manager.connect();
|
|
102
|
+
*
|
|
103
|
+
* const usersCollection = manager.getModel('users');
|
|
104
|
+
* const users = await usersCollection.find({}).toArray();
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
class MongoDbManager extends mongodb_1.MongoClient {
|
|
108
|
+
/**
|
|
109
|
+
* Creates a new MongoDbManager instance.
|
|
110
|
+
*
|
|
111
|
+
* @param settings - Configuration settings for the manager
|
|
112
|
+
*
|
|
113
|
+
* @throws {InvalidManagerConfigError} If the connection URL is missing
|
|
114
|
+
*
|
|
115
|
+
* @remarks
|
|
116
|
+
* The connection is created but not opened. You must call `connect()` to establish the connection.
|
|
117
|
+
* Connection events (topologyOpening, serverOpening, serverClosed, topologyClosed, error) are automatically registered and logged.
|
|
118
|
+
*/
|
|
43
119
|
constructor(settings) {
|
|
44
120
|
var _a;
|
|
45
121
|
if (!((_a = settings.config) === null || _a === void 0 ? void 0 : _a.url)) {
|
|
46
|
-
throw new
|
|
122
|
+
throw new core_1.InvalidManagerConfigError('Missing connection url');
|
|
47
123
|
}
|
|
48
124
|
super(settings.config.url, settings.config.options);
|
|
49
|
-
|
|
50
|
-
this.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
_registerConnectionEvents() {
|
|
54
|
-
this.on('topologyOpening', () => {
|
|
55
|
-
Log.info('[%s] connecting ...', this.name);
|
|
56
|
-
});
|
|
57
|
-
this.on('serverOpening', () => {
|
|
58
|
-
Log.info('[%s] connected!', this.name);
|
|
59
|
-
});
|
|
60
|
-
this.on('serverClosed', () => {
|
|
61
|
-
Log.info('[%s] disconnected!', this.name);
|
|
62
|
-
});
|
|
63
|
-
this.on('topologyClosed', () => {
|
|
64
|
-
Log.info('[%s] connection closed!', this.name);
|
|
65
|
-
});
|
|
125
|
+
_MongoDbManager_instances.add(this);
|
|
126
|
+
this.name = settings.name || `MongoDB ${Date.now()}_${(0, node_crypto_1.randomBytes)(3).toString('hex')}`;
|
|
127
|
+
tslib_1.__classPrivateFieldGet(this, _MongoDbManager_instances, "m", _MongoDbManager_registerConnectionEvents).call(this);
|
|
128
|
+
Log.info(`[${this.name}] MongoClient created. Must call "MongoClient.connect()".`);
|
|
66
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Gets the underlying MongoDB client connection.
|
|
132
|
+
*
|
|
133
|
+
* @returns The MongoDB client instance (this instance)
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const client = manager.getConnection();
|
|
138
|
+
* const db = client.db('mydb');
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
67
141
|
getConnection() {
|
|
68
142
|
return this;
|
|
69
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Closes the MongoDB connection.
|
|
146
|
+
*
|
|
147
|
+
* @param force - Optional flag to force close the connection, bypassing any connection pool cleanup
|
|
148
|
+
* @returns A promise that resolves when the connection is closed
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```typescript
|
|
152
|
+
* // Graceful close
|
|
153
|
+
* await manager.closeConnection();
|
|
154
|
+
*
|
|
155
|
+
* // Force close
|
|
156
|
+
* await manager.closeConnection(true);
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
70
159
|
closeConnection(force) {
|
|
71
160
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
72
161
|
if (force) {
|
|
@@ -77,6 +166,31 @@ class MongoDBManager extends mongodb_1.MongoClient {
|
|
|
77
166
|
}
|
|
78
167
|
});
|
|
79
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Retrieves a MongoDB collection by name.
|
|
171
|
+
* Supports dot notation for database.collection format.
|
|
172
|
+
*
|
|
173
|
+
* @template T - The document type for the collection, defaults to Document
|
|
174
|
+
*
|
|
175
|
+
* @param name - The name of the collection, or database.collection format
|
|
176
|
+
* @returns The MongoDB Collection instance
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* // Get collection from default database
|
|
181
|
+
* const users = manager.getModel('users');
|
|
182
|
+
*
|
|
183
|
+
* // Get collection with specific database
|
|
184
|
+
* const users = manager.getModel('mydb.users');
|
|
185
|
+
*
|
|
186
|
+
* // With type parameter
|
|
187
|
+
* interface User {
|
|
188
|
+
* name: string;
|
|
189
|
+
* email: string;
|
|
190
|
+
* }
|
|
191
|
+
* const users = manager.getModel<User>('users');
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
80
194
|
getModel(name) {
|
|
81
195
|
const conn = this.getConnection();
|
|
82
196
|
let model;
|
|
@@ -89,7 +203,115 @@ class MongoDBManager extends mongodb_1.MongoClient {
|
|
|
89
203
|
}
|
|
90
204
|
return model;
|
|
91
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* Checks if the MongoDB connection is currently active.
|
|
208
|
+
* Uses a simple ping command that doesn't require admin privileges.
|
|
209
|
+
*
|
|
210
|
+
* @returns A promise that resolves to true if connected, false otherwise
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* if (await manager.isConnected()) {
|
|
215
|
+
* console.log('MongoDB is connected');
|
|
216
|
+
* }
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
isConnected() {
|
|
220
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
221
|
+
try {
|
|
222
|
+
// Use a simple ping command on the database
|
|
223
|
+
yield this.db().command({ ping: 1 });
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
catch (_a) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Performs a comprehensive health check on the MongoDB connection.
|
|
233
|
+
* Tests connectivity by sending a PING command and gathering connection metrics.
|
|
234
|
+
* This method works with restricted database access (non-admin users).
|
|
235
|
+
*
|
|
236
|
+
* @returns A promise that resolves to a detailed health check result including:
|
|
237
|
+
* - Connection status (open/ready)
|
|
238
|
+
* - Ping response
|
|
239
|
+
* - Response latency
|
|
240
|
+
* - Error details (if unhealthy)
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* const health = await manager.healthCheck();
|
|
245
|
+
* if (health.healthy) {
|
|
246
|
+
* console.log(`MongoDB is healthy. Latency: ${health.details.latency}`);
|
|
247
|
+
* console.log(`Ping response:`, health.details.pingResponse);
|
|
248
|
+
* } else {
|
|
249
|
+
* console.error(`MongoDB is unhealthy: ${health.message}`);
|
|
250
|
+
* }
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
healthCheck() {
|
|
254
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
255
|
+
const start = Date.now();
|
|
256
|
+
const timestamp = start;
|
|
257
|
+
try {
|
|
258
|
+
// Use ping command on the database
|
|
259
|
+
const db = this.db();
|
|
260
|
+
const pingResult = yield db.command({ ping: 1 });
|
|
261
|
+
const latency = Date.now() - start;
|
|
262
|
+
return {
|
|
263
|
+
healthy: true,
|
|
264
|
+
message: 'MongoDB connection is healthy',
|
|
265
|
+
details: {
|
|
266
|
+
name: this.name,
|
|
267
|
+
databaseName: db.databaseName,
|
|
268
|
+
isOpen: true,
|
|
269
|
+
isReady: pingResult.ok === 1,
|
|
270
|
+
pingResponse: pingResult,
|
|
271
|
+
latency: `${latency}ms`
|
|
272
|
+
},
|
|
273
|
+
latency,
|
|
274
|
+
timestamp
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
return {
|
|
279
|
+
healthy: false,
|
|
280
|
+
message: `MongoDB health check failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
281
|
+
details: {
|
|
282
|
+
name: this.name,
|
|
283
|
+
isOpen: false,
|
|
284
|
+
isReady: false,
|
|
285
|
+
error: error instanceof Error ? error.stack : String(error)
|
|
286
|
+
},
|
|
287
|
+
latency: Date.now() - start,
|
|
288
|
+
timestamp
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
92
293
|
}
|
|
93
|
-
exports.
|
|
94
|
-
|
|
294
|
+
exports.MongoDbManager = MongoDbManager;
|
|
295
|
+
_MongoDbManager_instances = new WeakSet(), _MongoDbManager_registerConnectionEvents = function _MongoDbManager_registerConnectionEvents() {
|
|
296
|
+
this.on('topologyOpening', () => {
|
|
297
|
+
Log.info(`[${this.name}] connecting ...`);
|
|
298
|
+
});
|
|
299
|
+
this.on('serverOpening', () => {
|
|
300
|
+
Log.info(`[${this.name}] connected!`);
|
|
301
|
+
});
|
|
302
|
+
this.on('serverClosed', () => {
|
|
303
|
+
Log.warn(`[${this.name}] disconnected!`);
|
|
304
|
+
});
|
|
305
|
+
this.on('topologyClosed', () => {
|
|
306
|
+
Log.info(`[${this.name}] connection closed!`);
|
|
307
|
+
});
|
|
308
|
+
this.on('error', (err) => {
|
|
309
|
+
Log.error(`[${this.name}] connection error: ${err.message}`);
|
|
310
|
+
});
|
|
311
|
+
};
|
|
312
|
+
/**
|
|
313
|
+
* Identifier for the manager type.
|
|
314
|
+
* @readonly
|
|
315
|
+
*/
|
|
316
|
+
MongoDbManager.type = '@storehouse/mongodb';
|
|
95
317
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storehouse/mongodb",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "MongoDB manager for @storehouse/core",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"lint": "eslint .",
|
|
10
10
|
"test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\", \"noUnusedParameters\": false}' kaukau --require ts-node/register --config kaukau-src.mjs",
|
|
11
|
-
"
|
|
11
|
+
"test:lib": "kaukau --config kaukau-lib.mjs",
|
|
12
12
|
"test:local": "dotenvx run -f .env.test -- kaukau --require ts-node/register --config kaukau-src.mjs",
|
|
13
|
-
"
|
|
13
|
+
"test:lib:local": "dotenvx run -f .env.test -- kaukau --config kaukau-lib.mjs"
|
|
14
14
|
},
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
|
@@ -27,28 +27,28 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://kisiwu.github.io/storehouse/mongodb/latest/",
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@dotenvx/dotenvx": "^1.
|
|
31
|
-
"@eslint/eslintrc": "^3.3.
|
|
32
|
-
"@eslint/js": "^9.
|
|
33
|
-
"@stylistic/eslint-plugin": "^5.
|
|
34
|
-
"@types/chai": "^5.2.
|
|
30
|
+
"@dotenvx/dotenvx": "^1.52.0",
|
|
31
|
+
"@eslint/eslintrc": "^3.3.3",
|
|
32
|
+
"@eslint/js": "^9.39.2",
|
|
33
|
+
"@stylistic/eslint-plugin": "^5.7.1",
|
|
34
|
+
"@types/chai": "^5.2.3",
|
|
35
35
|
"@types/mocha": "^10.0.10",
|
|
36
|
-
"@types/node": "^
|
|
37
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
38
|
-
"@typescript-eslint/parser": "^8.
|
|
39
|
-
"chai": "^6.2.
|
|
40
|
-
"eslint": "^9.
|
|
36
|
+
"@types/node": "^25.2.1",
|
|
37
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
38
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
39
|
+
"chai": "^6.2.2",
|
|
40
|
+
"eslint": "^9.39.2",
|
|
41
41
|
"eslint-plugin-mocha": "^11.2.0",
|
|
42
|
-
"kaukau": "^4.1
|
|
42
|
+
"kaukau": "^4.2.1",
|
|
43
43
|
"ts-node": "^10.9.2",
|
|
44
|
-
"typedoc": "^0.28.
|
|
44
|
+
"typedoc": "^0.28.16",
|
|
45
45
|
"typescript": "^5.9.3",
|
|
46
|
-
"typescript-eslint": "^8.
|
|
46
|
+
"typescript-eslint": "^8.54.0"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@novice1/logger": "^1.6.
|
|
50
|
-
"@storehouse/core": "^
|
|
51
|
-
"mongodb": "^
|
|
49
|
+
"@novice1/logger": "^1.6.1",
|
|
50
|
+
"@storehouse/core": "^2.1.0",
|
|
51
|
+
"mongodb": "^7.1.0",
|
|
52
52
|
"tslib": "^2.8.1"
|
|
53
53
|
}
|
|
54
54
|
}
|