@@ -332,13 +332,11 @@ MongoDB.prototype.connect = function(callback) {
332332 if ( callback ) callback ( err ) ;
333333 }
334334
335- const urlObj = new URL ( self . settings . url ) ;
336-
337- if ( ( urlObj . pathname === '' ||
338- urlObj . pathname . split ( '/' ) [ 1 ] === '' ) &&
339- typeof self . settings . database === 'string' ) {
340- urlObj . pathname = self . settings . database ;
341- self . settings . url = urlObj . toString ( ) ;
335+ // This is special processing if database is not part of url, but is in settings
336+ if ( self . settings . url && self . settings . database ) {
337+ if ( self . settings . url . indexOf ( '/' + self . settings . database ) === - 1 ) {
338+ self . settings . url = processMongoDBURL ( self . settings . database , self . settings . url ) ;
339+ }
342340 }
343341
344342 new mongodb . MongoClient ( self . settings . url , validOptions ) . connect ( function (
@@ -2118,6 +2116,105 @@ MongoDB.prototype.rollback = function(tx, cb) {
21182116 } ) ;
21192117} ;
21202118
2119+ exports . processMongoDBURL = processMongoDBURL ;
2120+ /**
2121+ * This method parses a Mongo connection url string and refers the formats
2122+ * specified at: https://www.mongodb.com/docs/manual/reference/connection-string/.
2123+ * Since there are cases where database is not specified in the url, but as a settings property,
2124+ * the code has to reflect that in the url otherwise the MongoDB driver defaults to 'admin' db.
2125+ * @param {string } settingsDatabase - the database that will be added if url doesn't have a db specified
2126+ * @param {string } mongoUrl - the url to be processed for database manipulation
2127+ */
2128+ function processMongoDBURL ( settingsDatabase , mongoUrl ) {
2129+ // Reference: https://www.mongodb.com/docs/manual/reference/connection-string/
2130+ // Standard format::: mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]
2131+ // DNS SeedList format::: mongodb+srv://server.example.com/?connectTimeoutMS=300000&authSource=aDifferentAuthDB
2132+ // Actual replicaset example::: mongodb://mongodb1.example.com:27317,mongodb2.example.com:27017/?connectTimeoutMS=300000&replicaSet=mySet&authSource=aDifferentAuthDB
2133+
2134+ if ( mongoUrl ) {
2135+ // 1. Know the protocol
2136+ let baseUrl = '' ;
2137+ if ( mongoUrl . startsWith ( 'mongodb:' ) )
2138+ baseUrl = 'mongodb://' ;
2139+ else if ( mongoUrl . startsWith ( 'mongodb+srv:' ) )
2140+ baseUrl = 'mongodb+srv://' ;
2141+ else if ( mongoUrl . startsWith ( 'loopback-connector-mongodb:' ) )
2142+ baseUrl = 'loopback-connector-mongodb://' ;
2143+ else if ( mongoUrl . startsWith ( 'loopback-connector-mongodb+srv:' ) )
2144+ baseUrl = 'loopback-connector-mongodb+srv://' ;
2145+ else
2146+ return mongoUrl ; // Not a MongoURL that we can process
2147+
2148+ let remainderUrl = mongoUrl . substring ( baseUrl . length ) ;
2149+ // 2. Check if userId/password is present
2150+ let uidPassword = '' ;
2151+ if ( remainderUrl . indexOf ( '@' ) !== - 1 ) {
2152+ const parts = remainderUrl . split ( '@' ) ;
2153+ uidPassword = parts [ 0 ] ;
2154+ if ( parts . length === 2 )
2155+ remainderUrl = parts [ 1 ] ;
2156+ else
2157+ remainderUrl = '' ;
2158+ }
2159+ let hosts = '' ;
2160+ let dbName = '' ;
2161+ let options = '' ;
2162+ let hostsArray = [ ] ;
2163+ // 3. Check if comma separated replicas are specified
2164+ if ( remainderUrl . indexOf ( ',' ) !== - 1 ) {
2165+ hostsArray = remainderUrl . split ( ',' ) ;
2166+ remainderUrl = hostsArray [ hostsArray . length - 1 ] ;
2167+ }
2168+
2169+ // 4. Check if authDB is specified in the URL
2170+ const slashIndex = remainderUrl . indexOf ( '/' ) ;
2171+ if ( ( slashIndex !== - 1 ) ) {
2172+ if ( slashIndex !== ( remainderUrl . length - 1 ) ) {
2173+ const optionsIndex = remainderUrl . indexOf ( '?' ) ;
2174+ if ( optionsIndex !== - 1 ) {
2175+ options = remainderUrl . substring ( optionsIndex + 1 ) ;
2176+ dbName = remainderUrl . substring ( slashIndex + 1 , optionsIndex ) ;
2177+ } else {
2178+ // No DB options specified
2179+ dbName = remainderUrl . substring ( slashIndex + 1 ) ;
2180+ }
2181+ }
2182+
2183+ if ( hostsArray . length > 1 ) {
2184+ const newHosts = hostsArray ;
2185+ newHosts . pop ( ) ;
2186+ newHosts . push ( remainderUrl . substring ( 0 , slashIndex ) ) ;
2187+ hosts = newHosts . join ( ',' ) ;
2188+ } else {
2189+ hosts = remainderUrl . substring ( 0 , slashIndex ) ;
2190+ }
2191+ } else {
2192+ // No database specified
2193+ if ( hostsArray . length > 1 )
2194+ hosts = hostsArray . join ( ',' ) ;
2195+ else
2196+ hosts = remainderUrl ;
2197+ }
2198+
2199+ // 5. Reconstruct url, but this time add database from settings if URL didn't have it
2200+ // The below code has an overlap with generateMongoDBURL()
2201+ let modifiedUrl = baseUrl ;
2202+
2203+ if ( uidPassword )
2204+ modifiedUrl += uidPassword + '@' ;
2205+ if ( hosts )
2206+ modifiedUrl += hosts ;
2207+
2208+ modifiedUrl += '/' + ( dbName ? dbName : settingsDatabase ) ;
2209+
2210+ if ( options )
2211+ modifiedUrl += '?' + options ;
2212+
2213+ return modifiedUrl ;
2214+ }
2215+ return mongoUrl ;
2216+ }
2217+
21212218function isInTransation ( options ) {
21222219 const ops = { } ;
21232220 if ( options && options . transaction && options . transaction . isInTransation )
0 commit comments