@@ -38,7 +38,7 @@ export interface GridFSBucketWriteStreamOptions extends WriteConcernOptions {
38
38
* Do not instantiate this class directly. Use `openUploadStream()` instead.
39
39
* @public
40
40
*/
41
- export class GridFSBucketWriteStream extends Writable implements NodeJS . WritableStream {
41
+ export class GridFSBucketWriteStream extends Writable {
42
42
bucket : GridFSBucket ;
43
43
chunks : Collection < GridFSChunk > ;
44
44
filename : string ;
@@ -115,6 +115,14 @@ export class GridFSBucketWriteStream extends Writable implements NodeJS.Writable
115
115
}
116
116
}
117
117
118
+ /** The stream is considered constructed when the indexes are done being created */
119
+ override _construct ( callback : ( error ?: Error | null ) => void ) : void {
120
+ if ( this . bucket . s . checkedIndexes ) {
121
+ return process . nextTick ( callback ) ;
122
+ }
123
+ this . bucket . once ( 'index' , callback ) ;
124
+ }
125
+
118
126
/**
119
127
* Write a buffer to the stream.
120
128
*
@@ -123,22 +131,18 @@ export class GridFSBucketWriteStream extends Writable implements NodeJS.Writable
123
131
* @param callback - Function to call when the chunk was added to the buffer, or if the entire chunk was persisted to MongoDB if this chunk caused a flush.
124
132
* @returns False if this write required flushing a chunk to MongoDB. True otherwise.
125
133
*/
126
- override write ( chunk : Buffer | string ) : boolean ;
127
- override write ( chunk : Buffer | string , callback : Callback < void > ) : boolean ;
128
- override write ( chunk : Buffer | string , encoding : BufferEncoding | undefined ) : boolean ;
129
- override write (
134
+ override _write (
130
135
chunk : Buffer | string ,
131
- encoding : BufferEncoding | undefined ,
136
+ encoding : BufferEncoding ,
132
137
callback : Callback < void >
133
- ) : boolean ;
134
- override write (
135
- chunk : Buffer | string ,
136
- encodingOrCallback ?: Callback < void > | BufferEncoding ,
137
- callback ?: Callback < void >
138
- ) : boolean {
139
- const encoding = typeof encodingOrCallback === 'function' ? undefined : encodingOrCallback ;
140
- callback = typeof encodingOrCallback === 'function' ? encodingOrCallback : callback ;
141
- return waitForIndexes ( this , ( ) => doWrite ( this , chunk , encoding , callback ) ) ;
138
+ ) : void {
139
+ doWrite ( this , chunk , encoding , callback ) ;
140
+ }
141
+
142
+ override _final ( callback : ( error ?: Error | null ) => void ) : void {
143
+ if ( this . state . streamEnd ) process . nextTick ( callback ) ;
144
+ this . state . streamEnd = true ;
145
+ writeRemnant ( this , callback ) ;
142
146
}
143
147
144
148
/**
@@ -159,76 +163,14 @@ export class GridFSBucketWriteStream extends Writable implements NodeJS.Writable
159
163
this . state . aborted = true ;
160
164
await this . chunks . deleteMany ( { files_id : this . id } ) ;
161
165
}
162
-
163
- /**
164
- * Tells the stream that no more data will be coming in. The stream will
165
- * persist the remaining data to MongoDB, write the files document, and
166
- * then emit a 'finish' event.
167
- *
168
- * @param chunk - Buffer to write
169
- * @param encoding - Optional encoding for the buffer
170
- * @param callback - Function to call when all files and chunks have been persisted to MongoDB
171
- */
172
- override end ( ) : this;
173
- override end ( chunk : Buffer ) : this;
174
- override end ( callback : Callback < GridFSFile | void > ) : this;
175
- override end ( chunk : Buffer , callback : Callback < GridFSFile | void > ) : this;
176
- override end ( chunk : Buffer , encoding : BufferEncoding ) : this;
177
- override end (
178
- chunk : Buffer ,
179
- encoding : BufferEncoding | undefined ,
180
- callback : Callback < GridFSFile | void >
181
- ) : this;
182
- override end (
183
- chunkOrCallback ?: Buffer | Callback < GridFSFile | void > ,
184
- encodingOrCallback ?: BufferEncoding | Callback < GridFSFile | void > ,
185
- callback ?: Callback < GridFSFile | void >
186
- ) : this {
187
- const chunk = typeof chunkOrCallback === 'function' ? undefined : chunkOrCallback ;
188
- const encoding = typeof encodingOrCallback === 'function' ? undefined : encodingOrCallback ;
189
- callback =
190
- typeof chunkOrCallback === 'function'
191
- ? chunkOrCallback
192
- : typeof encodingOrCallback === 'function'
193
- ? encodingOrCallback
194
- : callback ;
195
-
196
- if ( this . state . streamEnd || checkAborted ( this , callback ) ) return this ;
197
-
198
- this . state . streamEnd = true ;
199
-
200
- if ( callback ) {
201
- this . once ( GridFSBucketWriteStream . FINISH , ( result : GridFSFile ) => {
202
- if ( callback ) callback ( undefined , result ) ;
203
- } ) ;
204
- }
205
-
206
- if ( ! chunk ) {
207
- waitForIndexes ( this , ( ) => ! ! writeRemnant ( this ) ) ;
208
- return this ;
209
- }
210
-
211
- this . write ( chunk , encoding , ( ) => {
212
- writeRemnant ( this ) ;
213
- } ) ;
214
-
215
- return this ;
216
- }
217
166
}
218
167
219
- function __handleError (
220
- stream : GridFSBucketWriteStream ,
221
- error : AnyError ,
222
- callback ?: Callback
223
- ) : void {
168
+ function handleError ( stream : GridFSBucketWriteStream , error : AnyError , callback : Callback ) : void {
224
169
if ( stream . state . errored ) {
225
170
return ;
226
171
}
227
172
stream . state . errored = true ;
228
- if ( callback ) {
229
- return callback ( error ) ;
230
- }
231
- stream . emit ( GridFSBucketWriteStream . ERROR , error ) ;
173
+ process . nextTick ( callback , error ) ;
232
174
}
233
175
234
176
function createChunkDoc ( filesId : ObjectId , n : number , data : Buffer ) : GridFSChunk {
@@ -271,8 +213,11 @@ async function checkChunksIndex(stream: GridFSBucketWriteStream): Promise<void>
271
213
}
272
214
}
273
215
274
- function checkDone ( stream : GridFSBucketWriteStream , callback ?: Callback ) : boolean {
275
- if ( stream . done ) return true ;
216
+ function checkDone ( stream : GridFSBucketWriteStream , callback : Callback ) : void {
217
+ if ( stream . done ) {
218
+ process . nextTick ( callback ) ;
219
+ return ;
220
+ }
276
221
if ( stream . state . streamEnd && stream . state . outstandingRequests === 0 && ! stream . state . errored ) {
277
222
// Set done so we do not trigger duplicate createFilesDoc
278
223
stream . done = true ;
@@ -287,24 +232,18 @@ function checkDone(stream: GridFSBucketWriteStream, callback?: Callback): boolea
287
232
stream . options . metadata
288
233
) ;
289
234
290
- if ( checkAborted ( stream , callback ) ) {
291
- return false ;
235
+ if ( isAborted ( stream , callback ) ) {
236
+ return ;
292
237
}
293
238
294
239
stream . files . insertOne ( filesDoc , { writeConcern : stream . writeConcern } ) . then (
295
- ( ) => {
296
- stream . emit ( GridFSBucketWriteStream . FINISH , filesDoc ) ;
297
- stream . emit ( GridFSBucketWriteStream . CLOSE ) ;
298
- } ,
240
+ ( ) => callback ( ) ,
299
241
error => {
300
- return __handleError ( stream , error , callback ) ;
242
+ return handleError ( stream , error , callback ) ;
301
243
}
302
244
) ;
303
-
304
- return true ;
305
245
}
306
-
307
- return false ;
246
+ process . nextTick ( callback ) ;
308
247
}
309
248
310
249
async function checkIndexes ( stream : GridFSBucketWriteStream ) : Promise < void > {
@@ -377,11 +316,11 @@ function createFilesDoc(
377
316
function doWrite (
378
317
stream : GridFSBucketWriteStream ,
379
318
chunk : Buffer | string ,
380
- encoding ? : BufferEncoding ,
381
- callback ? : Callback < void >
382
- ) : boolean {
383
- if ( checkAborted ( stream , callback ) ) {
384
- return false ;
319
+ encoding : BufferEncoding ,
320
+ callback : Callback < void >
321
+ ) : void {
322
+ if ( isAborted ( stream , callback ) ) {
323
+ return ;
385
324
}
386
325
387
326
const inputBuf = Buffer . isBuffer ( chunk ) ? chunk : Buffer . from ( chunk , encoding ) ;
@@ -392,13 +331,8 @@ function doWrite(
392
331
if ( stream . pos + inputBuf . length < stream . chunkSizeBytes ) {
393
332
inputBuf . copy ( stream . bufToStore , stream . pos ) ;
394
333
stream . pos += inputBuf . length ;
395
-
396
- callback && callback ( ) ;
397
-
398
- // Note that we reverse the typical semantics of write's return value
399
- // to be compatible with node's `.pipe()` function.
400
- // True means client can keep writing.
401
- return true ;
334
+ process . nextTick ( callback ) ;
335
+ return ;
402
336
}
403
337
404
338
// Otherwise, buffer is too big for current chunk, so we need to flush
@@ -418,8 +352,8 @@ function doWrite(
418
352
++ stream . state . outstandingRequests ;
419
353
++ outstandingRequests ;
420
354
421
- if ( checkAborted ( stream , callback ) ) {
422
- return false ;
355
+ if ( isAborted ( stream , callback ) ) {
356
+ return ;
423
357
}
424
358
425
359
stream . chunks . insertOne ( doc , { writeConcern : stream . writeConcern } ) . then (
@@ -429,12 +363,11 @@ function doWrite(
429
363
430
364
if ( ! outstandingRequests ) {
431
365
stream . emit ( 'drain' , doc ) ;
432
- callback && callback ( ) ;
433
- checkDone ( stream ) ;
366
+ checkDone ( stream , callback ) ;
434
367
}
435
368
} ,
436
369
error => {
437
- return __handleError ( stream , error ) ;
370
+ return handleError ( stream , error , callback ) ;
438
371
}
439
372
) ;
440
373
@@ -445,29 +378,9 @@ function doWrite(
445
378
inputBufRemaining -= numToCopy ;
446
379
numToCopy = Math . min ( spaceRemaining , inputBufRemaining ) ;
447
380
}
448
-
449
- // Note that we reverse the typical semantics of write's return value
450
- // to be compatible with node's `.pipe()` function.
451
- // False means the client should wait for the 'drain' event.
452
- return false ;
453
- }
454
-
455
- function waitForIndexes (
456
- stream : GridFSBucketWriteStream ,
457
- callback : ( res : boolean ) => boolean
458
- ) : boolean {
459
- if ( stream . bucket . s . checkedIndexes ) {
460
- return callback ( false ) ;
461
- }
462
-
463
- stream . bucket . once ( 'index' , ( ) => {
464
- callback ( true ) ;
465
- } ) ;
466
-
467
- return true ;
468
381
}
469
382
470
- function writeRemnant ( stream : GridFSBucketWriteStream , callback ? : Callback ) : boolean {
383
+ function writeRemnant ( stream : GridFSBucketWriteStream , callback : Callback ) : void {
471
384
// Buffer is empty, so don't bother to insert
472
385
if ( stream . pos === 0 ) {
473
386
return checkDone ( stream , callback ) ;
@@ -482,28 +395,25 @@ function writeRemnant(stream: GridFSBucketWriteStream, callback?: Callback): boo
482
395
const doc = createChunkDoc ( stream . id , stream . n , remnant ) ;
483
396
484
397
// If the stream was aborted, do not write remnant
485
- if ( checkAborted ( stream , callback ) ) {
486
- return false ;
398
+ if ( isAborted ( stream , callback ) ) {
399
+ return ;
487
400
}
488
401
489
402
stream . chunks . insertOne ( doc , { writeConcern : stream . writeConcern } ) . then (
490
403
( ) => {
491
404
-- stream . state . outstandingRequests ;
492
- checkDone ( stream ) ;
405
+ checkDone ( stream , callback ) ;
493
406
} ,
494
407
error => {
495
- return __handleError ( stream , error ) ;
408
+ return handleError ( stream , error , callback ) ;
496
409
}
497
410
) ;
498
- return true ;
411
+ return ;
499
412
}
500
413
501
- function checkAborted ( stream : GridFSBucketWriteStream , callback ? : Callback < void > ) : boolean {
414
+ function isAborted ( stream : GridFSBucketWriteStream , callback : Callback < void > ) : boolean {
502
415
if ( stream . state . aborted ) {
503
- if ( typeof callback === 'function' ) {
504
- // TODO(NODE-3485): Replace with MongoGridFSStreamClosedError
505
- callback ( new MongoAPIError ( 'Stream has been aborted' ) ) ;
506
- }
416
+ process . nextTick ( callback , new MongoAPIError ( 'Stream has been aborted' ) ) ;
507
417
return true ;
508
418
}
509
419
return false ;
0 commit comments