Thin MongoDB ODM built for Standard Schema
mongodb
zod
deno
1import { type Db, MongoClient, type MongoClientOptions } from "mongodb";
2import { ConnectionError } from "../errors.ts";
3
4/**
5 * Connection management module
6 *
7 * Handles MongoDB connection lifecycle including connect, disconnect,
8 * and connection state management.
9 */
10
11export interface Connection {
12 client: MongoClient;
13 db: Db;
14}
15
16export interface ConnectOptions extends MongoClientOptions {}
17
18// Singleton connection state
19let connection: Connection | null = null;
20
21/**
22 * Connect to MongoDB with connection pooling, retry logic, and resilience options
23 *
24 * The MongoDB driver handles connection pooling and automatic retries.
25 * Retry logic is enabled by default for both reads and writes in MongoDB 4.2+.
26 *
27 * @param uri - MongoDB connection string
28 * @param dbName - Name of the database to connect to
29 * @param options - Connection options (pooling, retries, timeouts, etc.)
30 * @returns Connection object with client and db
31 *
32 * @example
33 * Basic connection with pooling:
34 * ```ts
35 * await connect("mongodb://localhost:27017", "mydb", {
36 * maxPoolSize: 10,
37 * minPoolSize: 2,
38 * maxIdleTimeMS: 30000,
39 * connectTimeoutMS: 10000,
40 * socketTimeoutMS: 45000,
41 * });
42 * ```
43 *
44 * @example
45 * Production-ready connection with retry logic and resilience:
46 * ```ts
47 * await connect("mongodb://localhost:27017", "mydb", {
48 * // Connection pooling
49 * maxPoolSize: 10,
50 * minPoolSize: 2,
51 *
52 * // Automatic retry logic (enabled by default)
53 * retryReads: true, // Retry failed read operations
54 * retryWrites: true, // Retry failed write operations
55 *
56 * // Timeouts
57 * connectTimeoutMS: 10000, // Initial connection timeout
58 * socketTimeoutMS: 45000, // Socket operation timeout
59 * serverSelectionTimeoutMS: 10000, // Server selection timeout
60 *
61 * // Connection resilience
62 * maxIdleTimeMS: 30000, // Close idle connections
63 * heartbeatFrequencyMS: 10000, // Server health check interval
64 *
65 * // Optional: Compression for reduced bandwidth
66 * compressors: ['snappy', 'zlib'],
67 * });
68 * ```
69 */
70export async function connect(
71 uri: string,
72 dbName: string,
73 options?: ConnectOptions,
74): Promise<Connection> {
75 if (connection) {
76 return connection;
77 }
78
79 try {
80 const client = new MongoClient(uri, options);
81 await client.connect();
82 const db = client.db(dbName);
83
84 connection = { client, db };
85 return connection;
86 } catch (error) {
87 throw new ConnectionError(
88 `Failed to connect to MongoDB: ${
89 error instanceof Error ? error.message : String(error)
90 }`,
91 uri,
92 );
93 }
94}
95
96/**
97 * Disconnect from MongoDB and clean up resources
98 */
99export async function disconnect(): Promise<void> {
100 if (connection) {
101 await connection.client.close();
102 connection = null;
103 }
104}
105
106/**
107 * Get the current database connection
108 *
109 * @returns MongoDB Db instance
110 * @throws {ConnectionError} If not connected
111 * @internal
112 */
113export function getDb(): Db {
114 if (!connection) {
115 throw new ConnectionError("MongoDB not connected. Call connect() first.");
116 }
117 return connection.db;
118}
119
120/**
121 * Get the current connection state
122 *
123 * @returns Connection object or null if not connected
124 * @internal
125 */
126export function getConnection(): Connection | null {
127 return connection;
128}