88/*!
99 * Module dependencies
1010 */
11- const bson = require ( 'bson' ) ;
1211const g = require ( 'strong-globalize' ) ( ) ;
1312const mongodb = require ( 'mongodb' ) ;
14- const urlParser = require ( 'mongodb/lib/url_parser' ) ;
13+ const urlParser = require ( 'mongodb/lib/connection_string' ) . parseOptions ;
1514const util = require ( 'util' ) ;
1615const async = require ( 'async' ) ;
1716const Connector = require ( 'loopback-connector' ) . Connector ;
@@ -29,7 +28,7 @@ exports.ObjectID = ObjectID;
2928 * @returns {ObjectID }
3029 */
3130function ObjectID ( id ) {
32- if ( id instanceof mongodb . ObjectID ) {
31+ if ( id instanceof mongodb . ObjectId ) {
3332 return id ;
3433 }
3534 if ( typeof id !== 'string' ) {
@@ -40,7 +39,7 @@ function ObjectID(id) {
4039 // hex string. For LoopBack, we only allow 24-byte hex string, but 12-byte
4140 // string such as 'line-by-line' should be kept as string
4241 if ( ObjectIdValueRegex . test ( id ) ) {
43- return new bson . ObjectID ( id ) ;
42+ return new mongodb . ObjectId ( id ) ;
4443 } else {
4544 return id ;
4645 }
@@ -113,10 +112,9 @@ exports.initialize = function initializeDataSource(dataSource, callback) {
113112 fsync : s . fsync || null ,
114113 } ;
115114 s . url = s . url || generateMongoDBURL ( s ) ;
116- s . useNewUrlParser = s . useNewUrlParser !== false ;
117- s . useUnifiedTopology = s . useUnifiedTopology !== false ;
115+ // useNewUrlParser and useUnifiedTopology are default now
118116 dataSource . connector = new MongoDB ( s , dataSource ) ;
119- dataSource . ObjectID = mongodb . ObjectID ;
117+ dataSource . ObjectID = mongodb . ObjectId ;
120118
121119 if ( callback ) {
122120 if ( s . lazyConnect ) {
@@ -285,8 +283,6 @@ MongoDB.prototype.connect = function(callback) {
285283 'validateOptions' ,
286284 'appname' ,
287285 'auth' ,
288- 'user' ,
289- 'password' ,
290286 'authMechanism' ,
291287 'compression' ,
292288 'readPreferenceTags' ,
@@ -354,17 +350,45 @@ MongoDB.prototype.connect = function(callback) {
354350 }
355351 self . client = client ;
356352 // The database name might be in the url
357- return urlParser ( self . settings . url , self . settings , function ( err , url ) {
358- if ( err ) {
359- onError ( err ) ;
360- return ;
361- }
353+ try {
354+ const url = urlParser ( self . settings . url , validOptions ) ; // only supports the validURL options now
355+ // See https://github.com/mongodb/mongodb/blob/6.0.1/lib/mongodb.d.ts#L3854
356+ const validDbOptionNames = [
357+ 'authSource' ,
358+ 'forceServerObjectId' ,
359+ 'readPreference' ,
360+ 'pkFactory' ,
361+ 'readConcern' ,
362+ 'retryWrites' ,
363+ 'checkKeys' ,
364+ 'serializeFunctions' ,
365+ 'ignoreUndefined' ,
366+ 'promoteLongs' ,
367+ 'promoteBuffers' ,
368+ 'promoteValues' ,
369+ 'fieldsAsRaw' ,
370+ 'bsonRegExp' ,
371+ 'raw' ,
372+ 'writeConcern' ,
373+ 'logger' ,
374+ 'loggerLevel' ,
375+ ] ;
376+ const dbOptions = url . db_options || self . settings ;
377+ const dbOptionKeys = Object . keys ( dbOptions ) ;
378+ const validDbOptions = { } ;
379+ dbOptionKeys . forEach ( function ( option ) {
380+ if ( validDbOptionNames . indexOf ( option ) > - 1 ) {
381+ validDbOptions [ option ] = dbOptions [ option ] ;
382+ }
383+ } ) ;
362384 self . db = client . db (
363385 url . dbName || self . settings . database ,
364- url . db_options || self . settings ,
386+ validDbOptions ,
365387 ) ;
366388 if ( callback ) callback ( err , self . db ) ;
367- } ) ;
389+ } catch ( e ) {
390+ onError ( e ) ;
391+ }
368392 } ) ;
369393 }
370394} ;
@@ -498,7 +522,13 @@ MongoDB.prototype.execute = function(modelName, command) {
498522
499523 // Topology is destroyed when the server is disconnected
500524 // Execute if DB is connected and functional otherwise connect/reconnect first
501- if ( self . db && self . db . topology && ! self . db . topology . isDestroyed ( ) ) {
525+ if (
526+ self . db && (
527+ ! self . db . topology || ( self . db . topology && ! self . db . topology . isDestroyed ( ) )
528+ )
529+ ) {
530+ doExecute ( ) ;
531+ } else if ( self . db && ! self . db . topology ) {
502532 doExecute ( ) ;
503533 } else {
504534 if ( self . db ) {
@@ -545,7 +575,7 @@ MongoDB.prototype.execute = function(modelName, command) {
545575 'execute' ,
546576 context ,
547577 function ( context , done ) {
548- args [ args . length - 1 ] = function ( err , result ) {
578+ const observerCallback = function ( err , result ) {
549579 if ( err ) {
550580 debug ( 'Error: ' , err ) ;
551581 } else {
@@ -554,8 +584,23 @@ MongoDB.prototype.execute = function(modelName, command) {
554584 }
555585 done ( err , result ) ;
556586 } ;
557- debug ( 'MongoDB: model=%s command=%s' , modelName , command , args ) ;
558- return collection [ command ] . apply ( collection , args ) ;
587+
588+ // args had callback removed
589+ if ( command === 'find' ) {
590+ // find does not support callback, remove and use a toArray with this callback
591+ args . pop ( ) ;
592+ debug ( 'MongoDB: model=%s command=%s' , modelName , command , args ) ;
593+ try {
594+ const cursor = collection [ command ] . apply ( collection , args ) ;
595+ return observerCallback ( null , cursor ) ;
596+ } catch ( err ) {
597+ return observerCallback ( err , null ) ;
598+ }
599+ } else {
600+ args [ args . length - 1 ] = observerCallback ;
601+ debug ( 'MongoDB: model=%s command=%s' , modelName , command , args ) ;
602+ return collection [ command ] . apply ( collection , args ) ;
603+ }
559604 } ,
560605 callback ,
561606 ) ;
@@ -620,7 +665,7 @@ MongoDB.prototype.create = function(modelName, data, options, callback) {
620665 if ( err ) {
621666 return callback ( err ) ;
622667 }
623- idValue = result . ops [ 0 ] . _id ;
668+ idValue = result . insertedId ;
624669
625670 try {
626671 idValue = self . coerceId ( modelName , idValue , options ) ;
@@ -674,18 +719,13 @@ MongoDB.prototype.save = function(modelName, data, options, callback) {
674719 }
675720
676721 const info = { } ;
677- if ( result && result . result ) {
678- // create result formats:
679- // { ok: 1, n: 1, upserted: [ [Object] ] }
680- // { ok: 1, nModified: 0, n: 1, upserted: [ [Object] ] }
681- //
682- // update result formats:
683- // { ok: 1, n: 1 }
684- // { ok: 1, nModified: 1, n: 1 }
685- if ( result . result . ok === 1 && result . result . n === 1 ) {
686- info . isNewInstance = ! ! result . result . upserted ;
722+ if ( result ) {
723+ // new 4.0 result formats:
724+ // { acknowledged: true, modifiedCount: 1, upsertedCount: 1, : modifiedCount: 1}
725+ if ( result . acknowledged === true && ( result . matchedCount === 1 || result . upsertedCount === 1 ) ) {
726+ info . isNewInstance = result . upsertedCount === 1 ;
687727 } else {
688- debug ( 'save result format not recognized: %j' , result . result ) ;
728+ debug ( 'save result format not recognized: %j' , result ) ;
689729 }
690730 }
691731
@@ -854,7 +894,8 @@ MongoDB.prototype.updateOrCreate = function updateOrCreate(
854894 data ,
855895 buildOptions ( {
856896 upsert : true ,
857- returnOriginal : false ,
897+ returnNewDocument : true ,
898+ returnDocument : 'after' , // ensures new document gets returned
858899 sort : [ [ '_id' , 'asc' ] ] ,
859900 } , options ) ,
860901 function ( err , result ) {
@@ -922,9 +963,9 @@ MongoDB.prototype.destroy = function destroy(modelName, id, options, callback) {
922963 if ( self . debug ) {
923964 debug ( 'delete.callback' , modelName , id , err , result ) ;
924965 }
925- let res = result && result . result ;
966+ let res = result ;
926967 if ( res ) {
927- res = { count : res . n } ;
968+ res = { count : res . deletedCount } ;
928969 }
929970 if ( callback ) {
930971 callback ( err , res ) ;
@@ -1523,7 +1564,7 @@ MongoDB.prototype.destroyAll = function destroyAll(
15231564
15241565 if ( self . debug ) debug ( 'destroyAll.callback' , modelName , where , err , info ) ;
15251566
1526- const affectedCount = info . result ? info . result . n : undefined ;
1567+ const affectedCount = info ? info . deletedCount : undefined ;
15271568
15281569 if ( callback ) {
15291570 callback ( err , { count : affectedCount } ) ;
@@ -1614,7 +1655,7 @@ MongoDB.prototype.replaceWithOptions = function(modelName, id, data, options, cb
16141655 if ( err ) return cb && cb ( err ) ;
16151656 let result ;
16161657 const cbInfo = { } ;
1617- if ( info . result && info . result . n == 1 ) {
1658+ if ( info && ( info . matchedCount === 1 || info . upsertedCount === 1 ) ) {
16181659 result = self . fromDatabase ( modelName , data ) ;
16191660 delete result . _id ;
16201661 result [ idName ] = id ;
@@ -1625,8 +1666,8 @@ MongoDB.prototype.replaceWithOptions = function(modelName, id, data, options, cb
16251666 // replace result formats:
16261667 // 2.4.x: { ok: 1, n: 1 }
16271668 // { ok: 1, nModified: 1, n: 1 }
1628- if ( info . result . nModified !== undefined ) {
1629- cbInfo . isNewInstance = info . result . nModified === 0 ;
1669+ if ( info . modifiedCount !== undefined ) {
1670+ cbInfo . isNewInstance = info . modifiedCount === 0 ;
16301671 }
16311672 } else {
16321673 result = undefined ;
@@ -1754,7 +1795,7 @@ MongoDB.prototype.update = MongoDB.prototype.updateAll = function updateAll(
17541795 if ( self . debug )
17551796 debug ( 'updateAll.callback' , modelName , where , updateData , err , info ) ;
17561797
1757- const affectedCount = info . result ? info . result . n : undefined ;
1798+ const affectedCount = info ? info . matchedCount : undefined ;
17581799
17591800 if ( cb ) {
17601801 cb ( err , { count : affectedCount } ) ;
@@ -1805,7 +1846,8 @@ MongoDB.prototype.upsertWithWhere = function upsertWithWhere(
18051846 updateData ,
18061847 buildOptions ( {
18071848 upsert : true ,
1808- returnOriginal : false ,
1849+ returnNewDocument : true ,
1850+ returnDocument : 'after' , // ensures new documents get returned
18091851 sort : [ [ '_id' , 'asc' ] ] ,
18101852 } , options ) ,
18111853 function ( err , result ) {
@@ -2040,7 +2082,7 @@ MongoDB.prototype.automigrate = function(models, cb) {
20402082 ) ;
20412083 if (
20422084 ! (
2043- err . name === 'MongoError ' &&
2085+ err . name === 'MongoServerError ' &&
20442086 err . ok === 0 &&
20452087 err . errmsg === 'ns not found'
20462088 )
@@ -2188,7 +2230,7 @@ function isObjectIDProperty(modelCtor, propDef, value, options) {
21882230 ( Array . isArray ( value ) && value . every ( ( v ) => typeof v === 'string' && v . match ( ObjectIdValueRegex ) ) ) ) {
21892231 if ( isStoredAsObjectID ( propDef ) ) return true ;
21902232 else return ! isStrictObjectIDCoercionEnabled ( modelCtor , options ) ;
2191- } else if ( value instanceof mongodb . ObjectID ) {
2233+ } else if ( value instanceof mongodb . ObjectId ) {
21922234 return true ;
21932235 } else {
21942236 return false ;
@@ -2285,7 +2327,7 @@ function optimizedFindOrCreate(modelName, filter, data, options, callback) {
22852327 let value = result . value ;
22862328 const created = ! ! result . lastErrorObject . upserted ;
22872329
2288- if ( created && ( value == null || Object . keys ( value ) . length == 0 ) ) {
2330+ if ( created && ( value == null || Object . keys ( value ) . length === 0 ) ) {
22892331 value = data ;
22902332 self . setIdValue ( modelName , value , result . lastErrorObject . upserted ) ;
22912333 } else {
@@ -2336,7 +2378,6 @@ function visitAllProperties(data, modelCtor, visitor) {
23362378 } else {
23372379 visitor ( modelCtor , value , def , ( newValue ) => { data [ p ] = newValue ; } ) ;
23382380 }
2339- continue ;
23402381 }
23412382}
23422383
0 commit comments