@@ -105,6 +105,13 @@ exports.initialize = function initializeDataSource(dataSource, callback) {
105105
106106  s . safe  =  s . safe  !==  false ; 
107107  s . w  =  s . w  ||  1 ; 
108+   s . writeConcern  =  s . writeConcern  ||  { 
109+     w : s . w , 
110+     wtimeout : s . wtimeout  ||  null , 
111+     j : s . j  ||  null , 
112+     journal : s . journal  ||  null , 
113+     fsync : s . fsync  ||  null , 
114+   } ; 
108115  s . url  =  s . url  ||  generateMongoDBURL ( s ) ; 
109116  s . useNewUrlParser  =  s . useNewUrlParser  !==  false ; 
110117  s . useUnifiedTopology  =  s . useUnifiedTopology  !==  false ; 
@@ -251,9 +258,6 @@ MongoDB.prototype.connect = function(callback) {
251258      'acceptableLatencyMS' , 
252259      'connectWithNoPrimary' , 
253260      'authSource' , 
254-       'w' , 
255-       'wtimeout' , 
256-       'j' , 
257261      'forceServerObjectId' , 
258262      'serializeFunctions' , 
259263      'ignoreUndefined' , 
@@ -278,13 +282,13 @@ MongoDB.prototype.connect = function(callback) {
278282      'password' , 
279283      'authMechanism' , 
280284      'compression' , 
281-       'fsync' , 
282285      'readPreferenceTags' , 
283286      'numberOfRetries' , 
284287      'auto_reconnect' , 
285288      'minSize' , 
286289      'useNewUrlParser' , 
287290      'useUnifiedTopology' , 
291+       'writeConcern' , 
288292      // Ignored options 
289293      'native_parser' , 
290294      // Legacy options 
@@ -293,6 +297,11 @@ MongoDB.prototype.connect = function(callback) {
293297      'replSet' , 
294298      'mongos' , 
295299      'db' , 
300+       'w' , 
301+       'wtimeout' , 
302+       'j' , 
303+       'journal' , 
304+       'fsync' , 
296305    ] ; 
297306
298307    const  lbOptions  =  Object . keys ( self . settings ) ; 
@@ -683,7 +692,7 @@ MongoDB.prototype.exists = function(modelName, id, options, callback) {
683692    debug ( 'exists' ,  modelName ,  id ) ; 
684693  } 
685694  id  =  self . coerceId ( modelName ,  id ,  options ) ; 
686-   this . execute ( modelName ,  'findOne' ,  { _id : id } ,  function ( err ,  data )  { 
695+   this . execute ( modelName ,  'findOne' ,  { _id : id } ,  buildOptions ( { } ,   options ) ,   function ( err ,  data )  { 
687696    if  ( self . debug )  { 
688697      debug ( 'exists.callback' ,  modelName ,  id ,  err ,  data ) ; 
689698    } 
@@ -704,7 +713,7 @@ MongoDB.prototype.find = function find(modelName, id, options, callback) {
704713  } 
705714  const  idName  =  self . idName ( modelName ) ; 
706715  const  oid  =  self . coerceId ( modelName ,  id ,  options ) ; 
707-   this . execute ( modelName ,  'findOne' ,  { _id : oid } ,  function ( err ,  data )  { 
716+   this . execute ( modelName ,  'findOne' ,  { _id : oid } ,  buildOptions ( { } ,   options ) ,   function ( err ,  data )  { 
708717    if  ( self . debug )  { 
709718      debug ( 'find.callback' ,  modelName ,  id ,  err ,  data ) ; 
710719    } 
@@ -893,7 +902,7 @@ MongoDB.prototype.destroy = function destroy(modelName, id, options, callback) {
893902    debug ( 'delete' ,  modelName ,  id ) ; 
894903  } 
895904  id  =  self . coerceId ( modelName ,  id ,  options ) ; 
896-   this . execute ( modelName ,  'deleteOne' ,  { _id : id } ,  function ( err ,  result )  { 
905+   this . execute ( modelName ,  'deleteOne' ,  { _id : id } ,  buildOptions ( { } ,   options ) ,   function ( err ,  result )  { 
897906    if  ( self . debug )  { 
898907      debug ( 'delete.callback' ,  modelName ,  id ,  err ,  result ) ; 
899908    } 
@@ -1034,6 +1043,16 @@ MongoDB.prototype.buildWhere = function(modelName, where, options) {
10341043
10351044        query [ k ]  =  { $regex : cond } ; 
10361045      }  else  { 
1046+         if  ( isObjectIDProperty ( modelCtor ,  propDef ,  cond ,  options ) )  { 
1047+           if  ( Array . isArray ( cond ) )  { 
1048+             cond  =  cond . map ( function ( c )  { 
1049+               return  ObjectID ( c ) ; 
1050+             } ) ; 
1051+           }  else  { 
1052+             cond  =  ObjectID ( cond ) ; 
1053+           } 
1054+         } 
1055+ 
10371056        query [ k ]  =  { } ; 
10381057        query [ k ] [ '$'  +  spec ]  =  cond ; 
10391058      } 
@@ -1044,8 +1063,15 @@ MongoDB.prototype.buildWhere = function(modelName, where, options) {
10441063        query [ k ]  =  { $type : 10 } ; 
10451064      }  else  { 
10461065        if  ( isObjectIDProperty ( modelCtor ,  propDef ,  cond ,  options ) )  { 
1047-           cond  =  ObjectID ( cond ) ; 
1066+           if  ( Array . isArray ( cond ) )  { 
1067+             cond  =  cond . map ( function ( c )  { 
1068+               return  ObjectID ( c ) ; 
1069+             } ) ; 
1070+           }  else  { 
1071+             cond  =  ObjectID ( cond ) ; 
1072+           } 
10481073        } 
1074+ 
10491075        query [ k ]  =  cond ; 
10501076      } 
10511077    } 
@@ -1312,8 +1338,17 @@ MongoDB.prototype.convertColumnNames = function(model, data, direction) {
13121338    } 
13131339
13141340    if  ( direction  ===  'database' )  { 
1315-       data [ columnName ]  =  data [ propName ] ; 
1316-       delete  data [ propName ] ; 
1341+       // Handle data is Array object - in case of fields filter 
1342+       if  ( Array . isArray ( data ) )  { 
1343+         const  idx  =  data . indexOf ( propName ) ; 
1344+         if  ( idx  !==  - 1 )  { 
1345+           data . push ( columnName ) ; 
1346+           delete  data [ idx ] ; 
1347+         } 
1348+       }  else  {  // Handle data as Object - in case to create / update 
1349+         data [ columnName ]  =  data [ propName ] ; 
1350+         delete  data [ propName ] ; 
1351+       } 
13171352    } 
13181353
13191354    if  ( direction  ===  'property' )  { 
@@ -1351,17 +1386,23 @@ MongoDB.prototype.all = function all(modelName, filter, options, callback) {
13511386  if  ( filter . where )  { 
13521387    query  =  self . buildWhere ( modelName ,  filter . where ,  options ) ; 
13531388  } 
1354-   let  fields  =  filter . fields ; 
1389+   // Use Object.assign to avoid change filter.fields 
1390+   // which will cause error when create model from data 
1391+   let  fields  =  undefined ; 
1392+   if  ( typeof  filter . fields  !==  'undefined' )  { 
1393+     fields  =  [ ] ; 
1394+     Object . assign ( fields ,  filter . fields ) ; 
1395+   } 
13551396
13561397  // Convert custom column names 
13571398  fields  =  self . fromPropertyToDatabaseNames ( modelName ,  fields ) ; 
13581399
1400+   options  =  buildOptions ( { } ,  options ) ; 
1401+ 
13591402  if  ( fields )  { 
1360-     const  findOpts  =  { projection : fieldsArrayToObj ( fields ) } ; 
1361-     this . execute ( modelName ,  'find' ,  query ,  findOpts ,  processResponse ) ; 
1362-   }  else  { 
1363-     this . execute ( modelName ,  'find' ,  query ,  processResponse ) ; 
1403+     options . projection  =  fieldsArrayToObj ( fields ) ; 
13641404  } 
1405+   this . execute ( modelName ,  'find' ,  query ,  options ,  processResponse ) ; 
13651406
13661407  function  processResponse ( err ,  cursor )  { 
13671408    if  ( err )  { 
@@ -1461,7 +1502,7 @@ MongoDB.prototype.destroyAll = function destroyAll(
14611502  where  =  self . buildWhere ( modelName ,  where ,  options ) ; 
14621503  if  ( debug . enabled )  debug ( 'destroyAll where %s' ,  util . inspect ( where ) ) ; 
14631504
1464-   this . execute ( modelName ,  'deleteMany' ,  where  ||  { } ,  function ( err ,  info )  { 
1505+   this . execute ( modelName ,  'deleteMany' ,  where  ||  { } ,  buildOptions ( { } ,   options ) ,   function ( err ,  info )  { 
14651506    if  ( err )  return  callback  &&  callback ( err ) ; 
14661507
14671508    if  ( self . debug )  debug ( 'destroyAll.callback' ,  modelName ,  where ,  err ,  info ) ; 
@@ -1488,15 +1529,26 @@ MongoDB.prototype.count = function count(modelName, where, options, callback) {
14881529    debug ( 'count' ,  modelName ,  where ) ; 
14891530  } 
14901531  where  =  self . buildWhere ( modelName ,  where ,  options )  ||  { } ; 
1491-   const  method  =  Object . keys ( where ) . length  ===  0  ? 'estimatedDocumentCount'  : 'countDocuments' ; 
1492-   this . execute ( modelName ,  method ,  where ,  function ( err ,  count )  { 
1493-     if  ( self . debug )  { 
1494-       debug ( 'count.callback' ,  modelName ,  err ,  count ) ; 
1495-     } 
1496-     if  ( callback )  { 
1497-       callback ( err ,  count ) ; 
1498-     } 
1499-   } ) ; 
1532+   options  =  buildOptions ( { } ,  options ) ; 
1533+   if  ( Object . keys ( where ) . length  ===  0  &&  ! options . session )  { 
1534+     this . execute ( modelName ,  'estimatedDocumentCount' ,  function ( err ,  count )  { 
1535+       if  ( self . debug )  { 
1536+         debug ( 'count.callback' ,  modelName ,  err ,  count ) ; 
1537+       } 
1538+       if  ( callback )  { 
1539+         callback ( err ,  count ) ; 
1540+       } 
1541+     } ) ; 
1542+   }  else  { 
1543+     this . execute ( modelName ,  'countDocuments' ,  where ,  options ,  function ( err ,  count )  { 
1544+       if  ( self . debug )  { 
1545+         debug ( 'count.callback' ,  modelName ,  err ,  count ) ; 
1546+       } 
1547+       if  ( callback )  { 
1548+         callback ( err ,  count ) ; 
1549+       } 
1550+     } ) ; 
1551+   } 
15001552} ; 
15011553
15021554/** 
@@ -1538,7 +1590,7 @@ MongoDB.prototype.replaceWithOptions = function(modelName, id, data, options, cb
15381590  const  idName  =  self . idName ( modelName ) ; 
15391591  delete  data [ idName ] ; 
15401592  data  =  self . toDatabase ( modelName ,  data ) ; 
1541-   this . execute ( modelName ,  'replaceOne' ,  { _id : id } ,  data ,  options ,  function ( 
1593+   this . execute ( modelName ,  'replaceOne' ,  { _id : id } ,  data ,  buildOptions ( { } ,   options ) ,  function ( 
15421594    err , 
15431595    info , 
15441596  )  { 
@@ -1735,11 +1787,11 @@ MongoDB.prototype.upsertWithWhere = function upsertWithWhere(
17351787    'findOneAndUpdate' , 
17361788    where , 
17371789    updateData , 
1738-     { 
1790+     buildOptions ( { 
17391791      upsert : true , 
17401792      returnOriginal : false , 
17411793      sort : [ [ '_id' ,  'asc' ] ] , 
1742-     } , 
1794+     } ,   options ) , 
17431795    function ( err ,  result )  { 
17441796      if  ( err )  return  cb  &&  cb ( err ) ; 
17451797
@@ -2015,6 +2067,48 @@ MongoDB.prototype.ping = function(cb) {
20152067  } 
20162068} ; 
20172069
2070+ MongoDB . prototype . beginTransaction  =  function ( isolationLevel ,  cb )  { 
2071+   // TODO: think about how to convert READ_COMMITED, etc. to transactionOptions 
2072+   const  transactionOptions  =  { 
2073+     readPreference : 'primary' , 
2074+     readConcern : { level : 'local' } , 
2075+     writeConcern : { w : 'majority' } , 
2076+   } ; 
2077+   if  ( isolationLevel  instanceof  Object )  { 
2078+     Object . assign ( transactionOptions ,  isolationLevel  ||  { } ) ; 
2079+   } 
2080+   const  session  =  this . client . startSession ( ) ; 
2081+   session . startTransaction ( transactionOptions ) ; 
2082+   cb ( null ,  session ) ; 
2083+ } ; 
2084+ 
2085+ MongoDB . prototype . commit  =  function ( tx ,  cb )  { 
2086+   tx . commitTransaction ( function ( err )  { 
2087+     tx . endSession ( null ,  function ( error )  { 
2088+       if  ( err )  return  cb ( err ) ; 
2089+       if  ( error )  return  cb ( error ) ; 
2090+       cb ( ) ; 
2091+     } ) ; 
2092+   } ) ; 
2093+ } ; 
2094+ 
2095+ MongoDB . prototype . rollback  =  function ( tx ,  cb )  { 
2096+   tx . abortTransaction ( function ( err )  { 
2097+     tx . endSession ( null ,  function ( error )  { 
2098+       if  ( err )  return  cb ( err ) ; 
2099+       if  ( error )  return  cb ( error ) ; 
2100+       cb ( ) ; 
2101+     } ) ; 
2102+   } ) ; 
2103+ } ; 
2104+ 
2105+ function  isInTransation ( options )  { 
2106+   const  ops  =  { } ; 
2107+   if  ( options  &&  options . transaction  &&  options . transaction . isInTransation ) 
2108+     ops . session  =  options . transaction . session ; 
2109+   return  ops ; 
2110+ } 
2111+ 
20182112// Case insensitive check if a string looks like "ObjectID" 
20192113function  typeIsObjectId ( input )  { 
20202114  if  ( ! input )  return  false ; 
@@ -2072,7 +2166,8 @@ function coerceToObjectId(modelCtor, propDef, propValue) {
20722166function  isObjectIDProperty ( modelCtor ,  propDef ,  value ,  options )  { 
20732167  if  ( ! propDef )  return  false ; 
20742168
2075-   if  ( typeof  value  ===  'string'  &&  value . match ( ObjectIdValueRegex ) )  { 
2169+   if  ( ( typeof  value  ===  'string'  &&  value . match ( ObjectIdValueRegex ) )  || 
2170+     ( Array . isArray ( value )  &&  value . every ( ( v )  =>  v . match ( ObjectIdValueRegex ) ) ) )  { 
20762171    if  ( isStoredAsObjectID ( propDef ) )  return  true ; 
20772172    else  return  ! isStrictObjectIDCoercionEnabled ( modelCtor ,  options ) ; 
20782173  }  else  if  ( value  instanceof  mongodb . ObjectID )  { 
@@ -2306,5 +2401,9 @@ function hasDataType(dataType, propertyDef) {
23062401* @param  {* } connectorOptions User specified Options 
23072402*/ 
23082403function  buildOptions ( requiredOptions ,  connectorOptions )  { 
2309-   return  Object . assign ( { } ,  connectorOptions ,  requiredOptions ) ; 
2404+   if  ( connectorOptions  &&  connectorOptions . transaction  &&  connectorOptions . transaction . isActive ( ) )  { 
2405+     return  Object . assign ( { session : connectorOptions . transaction . connection } ,  connectorOptions ,  requiredOptions ) ; 
2406+   }  else  { 
2407+     return  Object . assign ( { } ,  connectorOptions ,  requiredOptions ) ; 
2408+   } 
23102409} 
0 commit comments