@@ -12,6 +12,7 @@ const ArraySubdocument = require('../lib/types/arraySubdocument');
1212const Query = require ( '../lib/query' ) ;
1313const assert = require ( 'assert' ) ;
1414const idGetter = require ( '../lib/helpers/schema/idGetter' ) ;
15+ const sinon = require ( 'sinon' ) ;
1516const util = require ( './util' ) ;
1617const utils = require ( '../lib/utils' ) ;
1718
@@ -14383,6 +14384,47 @@ describe('document', function() {
1438314384 __v : 0
1438414385 } ) ;
1438514386 } ) ;
14387+
14388+ it ( 'handles undoReset() on deep recursive subdocuments (gh-15255)' , async function ( ) {
14389+ const RecursiveSchema = new mongoose . Schema ( { } ) ;
14390+
14391+ const s = [ RecursiveSchema ] ;
14392+ RecursiveSchema . path ( 'nested' , s ) ;
14393+
14394+ const generateRecursiveDocument = ( depth , curr = 0 ) => {
14395+ return {
14396+ name : `Document of depth ${ curr } ` ,
14397+ nested : depth > 0 ? new Array ( 2 ) . fill ( ) . map ( ( ) => generateRecursiveDocument ( depth - 1 , curr + 1 ) ) : [ ] ,
14398+ __v : 5
14399+ } ;
14400+ } ;
14401+ const TestModel = db . model ( 'Test' , RecursiveSchema ) ;
14402+ const data = generateRecursiveDocument ( 10 ) ;
14403+ const doc = new TestModel ( data ) ;
14404+ await doc . save ( ) ;
14405+
14406+ sinon . spy ( Document . prototype , '$__undoReset' ) ;
14407+
14408+ try {
14409+ const d = await TestModel . findById ( doc . _id ) ;
14410+ d . increment ( ) ;
14411+ d . data = 'asd' ;
14412+ // Force a version error by updating the document directly
14413+ await TestModel . collection . updateOne ( { _id : doc . _id } , { $inc : { __v : 1 } } ) ;
14414+ const err = await d . save ( ) . then ( ( ) => null , err => err ) ;
14415+ assert . ok ( err ) ;
14416+ assert . equal ( err . name , 'VersionError' ) ;
14417+ // `$__undoReset()` should be called 1x per subdoc, plus 1x for top-level doc. Without fix for gh-15255,
14418+ // this would fail because `$__undoReset()` is called nearly 700k times for only 2046 subdocs
14419+ assert . strictEqual ( Document . prototype . $__undoReset . getCalls ( ) . length , d . $getAllSubdocs ( ) . length + 1 ) ;
14420+ assert . ok ( Document . prototype . $__undoReset . getCalls ( ) . find ( call => call . thisValue === d ) , 'top level doc was not reset' ) ;
14421+ for ( const subdoc of d . $getAllSubdocs ( ) ) {
14422+ assert . ok ( Document . prototype . $__undoReset . getCalls ( ) . find ( call => call . thisValue === subdoc ) , `${ subdoc . name } was not reset` ) ;
14423+ }
14424+ } finally {
14425+ sinon . restore ( ) ;
14426+ }
14427+ } ) ;
1438614428} ) ;
1438714429
1438814430describe ( 'Check if instance function that is supplied in schema option is available' , function ( ) {
0 commit comments