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