@@ -62,6 +62,10 @@ final class MongoDBConnection: @unchecked Sendable {
6262 private let authSource : String ?
6363 private let readPreference : String ?
6464 private let writeConcern : String ?
65+ private let useSrv : Bool
66+ private let authMechanism : String ?
67+ private let replicaSet : String ?
68+ private let extraUriParams : [ String : String ]
6569
6670 private let stateLock = NSLock ( )
6771 private var _isConnected : Bool = false
@@ -114,7 +118,11 @@ final class MongoDBConnection: @unchecked Sendable {
114118 sslClientCertPath: String = " " ,
115119 authSource: String ? = nil ,
116120 readPreference: String ? = nil ,
117- writeConcern: String ? = nil
121+ writeConcern: String ? = nil ,
122+ useSrv: Bool = false ,
123+ authMechanism: String ? = nil ,
124+ replicaSet: String ? = nil ,
125+ extraUriParams: [ String : String ] = [ : ]
118126 ) {
119127 self . host = host
120128 self . port = port
@@ -127,6 +135,10 @@ final class MongoDBConnection: @unchecked Sendable {
127135 self . authSource = authSource
128136 self . readPreference = readPreference
129137 self . writeConcern = writeConcern
138+ self . useSrv = useSrv
139+ self . authMechanism = authMechanism
140+ self . replicaSet = replicaSet
141+ self . extraUriParams = extraUriParams
130142 }
131143
132144 deinit {
@@ -150,7 +162,8 @@ final class MongoDBConnection: @unchecked Sendable {
150162 // MARK: - URI Construction
151163
152164 private func buildUri( ) -> String {
153- var uri = " mongodb:// "
165+ let scheme = useSrv ? " mongodb+srv " : " mongodb "
166+ var uri = " \( scheme) :// "
154167
155168 if !user. isEmpty {
156169 let encodedUser = user. addingPercentEncoding ( withAllowedCharacters: . urlUserAllowed) ?? user
@@ -167,10 +180,21 @@ final class MongoDBConnection: @unchecked Sendable {
167180 let encodedHost = host. addingPercentEncoding ( withAllowedCharacters: . urlHostAllowed) ?? host
168181 let encodedDb = database. addingPercentEncoding ( withAllowedCharacters: . urlPathAllowed) ?? database
169182
170- uri += " \( encodedHost) : \( port) "
183+ if useSrv {
184+ uri += encodedHost
185+ } else {
186+ uri += " \( encodedHost) : \( port) "
187+ }
171188 uri += database. isEmpty ? " / " : " / \( encodedDb) "
172189
173- let effectiveAuthSource = authSource. flatMap { $0. isEmpty ? nil : $0 } ?? " admin "
190+ let effectiveAuthSource : String
191+ if let source = authSource, !source. isEmpty {
192+ effectiveAuthSource = source
193+ } else if !database. isEmpty {
194+ effectiveAuthSource = database
195+ } else {
196+ effectiveAuthSource = " admin "
197+ }
174198 let encodedAuthSource = effectiveAuthSource
175199 . addingPercentEncoding ( withAllowedCharacters: . urlQueryAllowed) ?? effectiveAuthSource
176200 var params : [ String ] = [
@@ -206,6 +230,24 @@ final class MongoDBConnection: @unchecked Sendable {
206230 if let wc = writeConcern, !wc. isEmpty {
207231 params. append ( " w= \( wc) " )
208232 }
233+ if let mechanism = authMechanism, !mechanism. isEmpty {
234+ params. append ( " authMechanism= \( mechanism) " )
235+ }
236+ if let rs = replicaSet, !rs. isEmpty {
237+ params. append ( " replicaSet= \( rs) " )
238+ }
239+
240+ var explicitKeys : Set < String > = [
241+ " connectTimeoutMS " , " serverSelectionTimeoutMS " ,
242+ " authSource " , " authMechanism " , " replicaSet " ,
243+ " tls " , " tlsAllowInvalidCertificates " , " tlsCAFile " , " tlsCertificateKeyFile "
244+ ]
245+ if readPreference != nil , !readPreference!. isEmpty { explicitKeys. insert ( " readPreference " ) }
246+ if writeConcern != nil , !writeConcern!. isEmpty { explicitKeys. insert ( " w " ) }
247+ for (key, value) in extraUriParams where !explicitKeys. contains ( key) {
248+ let encodedValue = value. addingPercentEncoding ( withAllowedCharacters: . urlQueryAllowed) ?? value
249+ params. append ( " \( key) = \( encodedValue) " )
250+ }
209251
210252 uri += " ? " + params. joined ( separator: " & " )
211253 return uri
@@ -248,14 +290,12 @@ final class MongoDBConnection: @unchecked Sendable {
248290 }
249291
250292 self . client = newClient
251- let versionString = self . fetchServerVersionSync ( )
252293
253294 self . stateLock. lock ( )
254- self . _cachedServerVersion = versionString
255295 self . _isConnected = true
256296 self . stateLock. unlock ( )
257297
258- logger. info ( " Connected to MongoDB \( versionString ?? " unknown " ) " )
298+ logger. info ( " Connected to MongoDB at \( self . host ) : \( self . port ) " )
259299 }
260300 #else
261301 throw MongoDBError . libmongocUnavailable
@@ -341,8 +381,21 @@ final class MongoDBConnection: @unchecked Sendable {
341381
342382 func serverVersion( ) -> String ? {
343383 stateLock. lock ( )
344- defer { stateLock. unlock ( ) }
345- return _cachedServerVersion
384+ if let cached = _cachedServerVersion {
385+ stateLock. unlock ( )
386+ return cached
387+ }
388+ stateLock. unlock ( )
389+
390+ #if canImport(CLibMongoc)
391+ let version = queue. sync { fetchServerVersionSync ( ) }
392+ stateLock. lock ( )
393+ _cachedServerVersion = version
394+ stateLock. unlock ( )
395+ return version
396+ #else
397+ return nil
398+ #endif
346399 }
347400 func currentDatabase( ) -> String { database }
348401
@@ -429,6 +482,29 @@ final class MongoDBConnection: @unchecked Sendable {
429482 #endif
430483 }
431484
485+ func estimatedDocumentCount( database: String , collection: String ) async throws -> Int64 {
486+ #if canImport(CLibMongoc)
487+ resetCancellation ( )
488+ return try await pluginDispatchAsync ( on: queue) { [ self ] in
489+ guard !isShuttingDown, let client = self . client else {
490+ throw MongoDBError . notConnected
491+ }
492+ try checkCancelled ( )
493+ let col = try getCollection ( client, database: database, collection: collection)
494+ defer { mongoc_collection_destroy ( col) }
495+
496+ var error = bson_error_t ( )
497+ let count = mongoc_collection_estimated_document_count ( col, nil , nil , nil , & error)
498+ if count < 0 {
499+ throw makeError ( error)
500+ }
501+ return count
502+ }
503+ #else
504+ throw MongoDBError . libmongocUnavailable
505+ #endif
506+ }
507+
432508 func insertOne( database: String , collection: String , document: String ) async throws -> String ? {
433509 #if canImport(CLibMongoc)
434510 resetCancellation ( )
0 commit comments