@@ -7,8 +7,11 @@ import {
7
7
applyWriteConcern ,
8
8
applyRetryableWrites ,
9
9
executeLegacyOperation ,
10
- isPromiseLike
10
+ isPromiseLike ,
11
+ hasAtomicOperators ,
12
+ maxWireVersion
11
13
} from '../utils' ;
14
+
12
15
// Error codes
13
16
const WRITE_CONCERN_ERROR = 64 ;
14
17
@@ -663,6 +666,10 @@ class FindOperators {
663
666
document . hint = updateDocument . hint ;
664
667
}
665
668
669
+ if ( ! hasAtomicOperators ( updateDocument ) ) {
670
+ throw new TypeError ( 'Update document requires atomic operators' ) ;
671
+ }
672
+
666
673
// Clear out current Op
667
674
this . s . currentOp = null ;
668
675
return this . s . options . addToOperationsList ( this , UPDATE , document ) ;
@@ -671,13 +678,33 @@ class FindOperators {
671
678
/**
672
679
* Add a replace one operation to the bulk operation
673
680
*
674
- * @function
675
- * @param {object } updateDocument the new document to replace the existing one with
681
+ * @param {object } replacement the new document to replace the existing one with
676
682
* @throws {MongoError } If operation cannot be added to bulk write
677
683
* @returns {void } A reference to the parent BulkOperation
678
684
*/
679
- replaceOne ( updateDocument : object ) : void {
680
- this . updateOne ( updateDocument ) ;
685
+ replaceOne ( replacement : any ) {
686
+ // Perform upsert
687
+ const upsert = typeof this . s . currentOp . upsert === 'boolean' ? this . s . currentOp . upsert : false ;
688
+
689
+ // Establish the update command
690
+ const document = {
691
+ q : this . s . currentOp . selector ,
692
+ u : replacement ,
693
+ multi : false ,
694
+ upsert : upsert
695
+ } as any ;
696
+
697
+ if ( replacement . hint ) {
698
+ document . hint = replacement . hint ;
699
+ }
700
+
701
+ if ( hasAtomicOperators ( replacement ) ) {
702
+ throw new TypeError ( 'Replacement document must not use atomic operators' ) ;
703
+ }
704
+
705
+ // Clear out current Op
706
+ this . s . currentOp = null ;
707
+ return this . s . options . addToOperationsList ( this , UPDATE , document ) ;
681
708
}
682
709
683
710
/**
@@ -965,6 +992,12 @@ class BulkOperationBase {
965
992
966
993
// Crud spec update format
967
994
if ( op . updateOne || op . updateMany || op . replaceOne ) {
995
+ if ( op . replaceOne && hasAtomicOperators ( op [ key ] . replacement ) ) {
996
+ throw new TypeError ( 'Replacement document must not use atomic operators' ) ;
997
+ } else if ( ( op . updateOne || op . updateMany ) && ! hasAtomicOperators ( op [ key ] . update ) ) {
998
+ throw new TypeError ( 'Update document requires atomic operators' ) ;
999
+ }
1000
+
968
1001
const multi = op . updateOne || op . replaceOne ? false : true ;
969
1002
const operation = {
970
1003
q : op [ key ] . filter ,
@@ -982,7 +1015,15 @@ class BulkOperationBase {
982
1015
} else {
983
1016
if ( op [ key ] . upsert ) operation . upsert = true ;
984
1017
}
985
- if ( op [ key ] . arrayFilters ) operation . arrayFilters = op [ key ] . arrayFilters ;
1018
+ if ( op [ key ] . arrayFilters ) {
1019
+ // TODO: this check should be done at command construction against a connection, not a topology
1020
+ if ( maxWireVersion ( this . s . topology ) < 6 ) {
1021
+ throw new TypeError ( 'arrayFilters are only supported on MongoDB 3.6+' ) ;
1022
+ }
1023
+
1024
+ operation . arrayFilters = op [ key ] . arrayFilters ;
1025
+ }
1026
+
986
1027
return this . s . options . addToOperationsList ( this , UPDATE , operation ) ;
987
1028
}
988
1029
0 commit comments