@@ -9,6 +9,7 @@ import type { AnyBulkWriteOperation } from 'mongodb'
99import {
1010 FindOneOptions ,
1111 FindOptions ,
12+ MongoCursor ,
1213 MongoReadOnlyCollection ,
1314 ObserveCallbacks ,
1415 ObserveChangesCallbacks ,
@@ -44,6 +45,7 @@ export namespace MongoMock {
4445 const mockCollections : MockCollections < any > = { }
4546 export class Collection < T extends CollectionObject > implements Omit < MinimalMeteorMongoCollection < T > , 'find' > {
4647 public _name : string
48+ private _isTemporaryCollection : boolean
4749 private _options : any = { }
4850 // @ts -expect-error used in test to check that it's a mock
4951 private _isMock = true as const
@@ -54,11 +56,15 @@ export namespace MongoMock {
5456 constructor ( name : string | null , options ?: { transform ?: never } ) {
5557 this . _options = options || { }
5658 this . _name = name || getRandomString ( ) // If `null`, then its an in memory unique collection
59+ this . _isTemporaryCollection = name === null
5760
5861 if ( this . _options . transform ) throw new Error ( 'document transform is no longer supported' )
5962 }
6063
61- find ( query : any , options ?: FindOptions < T > ) : MinimalMongoCursor < T > & { _fetchRaw : ( ) => T [ ] } {
64+ find (
65+ query : any ,
66+ options ?: FindOptions < T >
67+ ) : MinimalMongoCursor < T > & { _fetchRaw : ( ) => T [ ] } & Pick < MongoCursor < T > , 'fetch' | 'forEach' > {
6268 if ( _ . isString ( query ) ) query = { _id : query }
6369 query = query || { }
6470
@@ -97,6 +103,12 @@ export namespace MongoMock {
97103
98104 return clone ( docs )
99105 } ,
106+ fetch : ( ) => {
107+ if ( ! this . _isTemporaryCollection )
108+ throw new Meteor . Error ( 500 , 'sync methods can only be used for unnamed collections' )
109+
110+ return clone ( docs )
111+ } ,
100112 countAsync : async ( ) => {
101113 // Force this to be performed async
102114 await MeteorMock . sleepNoFakeTimers ( 0 )
@@ -140,9 +152,12 @@ export namespace MongoMock {
140152 } ,
141153 }
142154 } ,
143- // async forEachAsync(f: any) {
144- // docs.forEach(f)
145- // },
155+ forEach : ( f : any ) => {
156+ if ( ! this . _isTemporaryCollection )
157+ throw new Meteor . Error ( 500 , 'sync methods can only be used for unnamed collections' )
158+
159+ docs . forEach ( f )
160+ } ,
146161 // async mapAsync(f: any) {
147162 // return docs.map(f)
148163 // },
@@ -152,10 +167,28 @@ export namespace MongoMock {
152167 const docs = await this . find ( query , options ) . fetchAsync ( )
153168 return docs [ 0 ]
154169 }
170+ findOne ( query : MongoQuery < T > , options ?: FindOneOptions < T > ) {
171+ if ( ! this . _isTemporaryCollection )
172+ throw new Meteor . Error ( 500 , 'sync methods can only be used for unnamed collections' )
173+
174+ const docs = this . find ( query , options ) . fetch ( )
175+ return docs [ 0 ]
176+ }
177+
155178 async updateAsync ( query : any , modifier : any , options ?: UpdateOptions ) : Promise < number > {
156179 // Force this to be performed async
157180 await MeteorMock . sleepNoFakeTimers ( 0 )
158181
182+ return this . updateRaw ( query , modifier , options )
183+ }
184+ update ( query : any , modifier : any , options ?: UpdateOptions ) : number {
185+ if ( ! this . _isTemporaryCollection )
186+ throw new Meteor . Error ( 500 , 'sync methods can only be used for unnamed collections' )
187+
188+ return this . updateRaw ( query , modifier , options )
189+ }
190+
191+ private updateRaw ( query : any , modifier : any , options ?: UpdateOptions ) : number {
159192 const unimplementedUsedOptions = _ . without ( _ . keys ( options ) , 'multi' )
160193 if ( unimplementedUsedOptions . length > 0 ) {
161194 throw new Error ( `update being performed using unimplemented options: ${ unimplementedUsedOptions } ` )
@@ -189,10 +222,20 @@ export namespace MongoMock {
189222
190223 return docs . length
191224 }
225+
192226 async insertAsync ( doc : any ) : Promise < string > {
193227 // Force this to be performed async
194228 await MeteorMock . sleepNoFakeTimers ( 0 )
195229
230+ return this . insertRaw ( doc )
231+ }
232+ insert ( doc : any ) : string {
233+ if ( ! this . _isTemporaryCollection )
234+ throw new Meteor . Error ( 500 , 'sync methods can only be used for unnamed collections' )
235+
236+ return this . insertRaw ( doc )
237+ }
238+ private insertRaw ( doc : any ) : string {
196239 const d = _ . clone ( doc )
197240 if ( ! d . _id ) d . _id = protectString ( RandomMock . id ( ) )
198241
@@ -221,6 +264,7 @@ export namespace MongoMock {
221264
222265 return d . _id
223266 }
267+
224268 async upsertAsync (
225269 query : any ,
226270 modifier : any ,
@@ -229,23 +273,50 @@ export namespace MongoMock {
229273 // Force this to be performed async
230274 await MeteorMock . sleepNoFakeTimers ( 0 )
231275
276+ return this . upsertRaw ( query , modifier , options )
277+ }
278+ upsert (
279+ query : any ,
280+ modifier : any ,
281+ options ?: UpsertOptions
282+ ) : { numberAffected : number | undefined ; insertedId : string | undefined } {
283+ if ( ! this . _isTemporaryCollection )
284+ throw new Meteor . Error ( 500 , 'sync methods can only be used for unnamed collections' )
285+
286+ return this . upsertRaw ( query , modifier , options )
287+ }
288+ private upsertRaw (
289+ query : any ,
290+ modifier : any ,
291+ options ?: UpsertOptions
292+ ) : { numberAffected : number | undefined ; insertedId : string | undefined } {
232293 const id = _ . isString ( query ) ? query : query . _id
233294
234295 const docs = this . find ( id ) . _fetchRaw ( )
235296
236297 if ( docs . length ) {
237- const count = await this . updateAsync ( docs [ 0 ] . _id , modifier , options )
298+ const count = this . updateRaw ( docs [ 0 ] . _id , modifier , options )
238299 return { insertedId : undefined , numberAffected : count }
239300 } else {
240301 const doc = mongoModify < T > ( query , { _id : id } as any , modifier )
241- const insertedId = await this . insertAsync ( doc )
302+ const insertedId = this . insertRaw ( doc )
242303 return { insertedId : insertedId , numberAffected : undefined }
243304 }
244305 }
306+
245307 async removeAsync ( query : any ) : Promise < number > {
246308 // Force this to be performed async
247309 await MeteorMock . sleepNoFakeTimers ( 0 )
248310
311+ return this . removeRaw ( query )
312+ }
313+ remove ( query : any ) : number {
314+ if ( ! this . _isTemporaryCollection )
315+ throw new Meteor . Error ( 500 , 'sync methods can only be used for unnamed collections' )
316+
317+ return this . removeRaw ( query )
318+ }
319+ private removeRaw ( query : any ) : number {
249320 const docs = this . find ( query ) . _fetchRaw ( )
250321
251322 _ . each ( docs , ( doc ) => {
0 commit comments