@@ -21,39 +21,15 @@ import { iterate, validateExplainableVerbosity, markAsExplainOutput } from './he
21
21
export abstract class AbstractCursor < CursorType extends ServiceProviderAggregationCursor | ServiceProviderCursor > extends ShellApiWithMongoClass {
22
22
_mongo : Mongo ;
23
23
_cursor : CursorType ;
24
+ _transform : ( ( doc : any ) => any ) | null ;
24
25
25
26
_currentIterationResult : CursorIterationResult | null = null ;
26
- _mapError : Error | null = null ;
27
27
28
28
constructor ( mongo : Mongo , cursor : CursorType ) {
29
29
super ( ) ;
30
30
this . _mongo = mongo ;
31
31
this . _cursor = cursor ;
32
- }
33
-
34
- // Wrap a function with checks before and after that verify whether a .map()
35
- // callback has resulted in an exception. Such an error would otherwise result
36
- // in an uncaught exception, bringing the whole process down.
37
- // The downside to this is that errors will not actually be visible until
38
- // the caller tries to interact with this cursor in a way that triggers
39
- // these checks. Since that is also the behavior for errors coming from the
40
- // database server, it makes sense to match that.
41
- // Ideally, this kind of code could be lifted into the driver (NODE-3231 and
42
- // NODE-3232 are the tickets for that).
43
- async _withCheckMapError < Ret > ( fn : ( ) => Ret ) : Promise < Ret > {
44
- if ( this . _mapError ) {
45
- // If an error has already occurred, we don't want to call the function
46
- // at all.
47
- throw this . _mapError ;
48
- }
49
- // eslint-disable-next-line @typescript-eslint/await-thenable
50
- const ret = await fn ( ) ;
51
- if ( this . _mapError ) {
52
- // If an error occurred during the function, we don't want to forward its
53
- // results.
54
- throw this . _mapError ;
55
- }
56
- return ret ;
32
+ this . _transform = null ;
57
33
}
58
34
59
35
/**
@@ -82,32 +58,27 @@ export abstract class AbstractCursor<CursorType extends ServiceProviderAggregati
82
58
}
83
59
84
60
@returnsPromise
85
- async forEach ( f : ( doc : Document ) => void ) : Promise < void > {
86
- // Work around https://jira.mongodb.org/browse/NODE-3231
87
- let exception ;
88
- const wrapped = ( doc : Document ) : boolean | undefined => {
89
- try {
90
- f ( doc ) ;
91
- return undefined ;
92
- } catch ( err ) {
93
- exception = err ;
94
- return false ; // Stop iteration.
61
+ async forEach ( f : ( doc : Document ) => void | boolean | Promise < void > | Promise < boolean > ) : Promise < void > {
62
+ // Do not use the driver method because it does not have Promise support.
63
+ for await ( const doc of this ) {
64
+ if ( ( await f ( doc ) ) === false ) {
65
+ break ;
95
66
}
96
- } ;
97
- await this . _cursor . forEach ( wrapped ) ;
98
- if ( exception ) {
99
- throw exception ;
100
67
}
101
68
}
102
69
103
70
@returnsPromise
104
71
async hasNext ( ) : Promise < boolean > {
105
- return this . _withCheckMapError ( ( ) => this . _cursor . hasNext ( ) ) ;
72
+ return this . _cursor . hasNext ( ) ;
106
73
}
107
74
108
75
@returnsPromise
109
76
async tryNext ( ) : Promise < Document | null > {
110
- return this . _withCheckMapError ( ( ) => this . _cursor . tryNext ( ) ) ;
77
+ let result = await this . _cursor . tryNext ( ) ;
78
+ if ( result !== null && this . _transform !== null ) {
79
+ result = await this . _transform ( result ) ;
80
+ }
81
+ return result ;
111
82
}
112
83
113
84
async * [ Symbol . asyncIterator ] ( ) {
@@ -136,7 +107,11 @@ export abstract class AbstractCursor<CursorType extends ServiceProviderAggregati
136
107
137
108
@returnsPromise
138
109
async toArray ( ) : Promise < Document [ ] > {
139
- return this . _withCheckMapError ( ( ) => this . _cursor . toArray ( ) ) ;
110
+ const result = [ ] ;
111
+ for await ( const doc of this ) {
112
+ result . push ( doc ) ;
113
+ }
114
+ return result ;
140
115
}
141
116
142
117
@returnType ( 'this' )
@@ -146,20 +121,12 @@ export abstract class AbstractCursor<CursorType extends ServiceProviderAggregati
146
121
147
122
@returnType ( 'this' )
148
123
map ( f : ( doc : Document ) => Document ) : this {
149
- // Work around https://jira.mongodb.org/browse/NODE-3232
150
- const wrapped = ( doc : Document ) : Document => {
151
- if ( this . _mapError ) {
152
- // These errors should never become visible to the user.
153
- return { __errored : true } ;
154
- }
155
- try {
156
- return f ( doc ) ;
157
- } catch ( err ) {
158
- this . _mapError = err ;
159
- return { __errored : true } ;
160
- }
161
- } ;
162
- this . _cursor . map ( wrapped ) ;
124
+ if ( this . _transform === null ) {
125
+ this . _transform = f ;
126
+ } else {
127
+ const g = this . _transform ;
128
+ this . _transform = ( doc : any ) => f ( g ( doc ) ) ;
129
+ }
163
130
return this ;
164
131
}
165
132
@@ -171,7 +138,11 @@ export abstract class AbstractCursor<CursorType extends ServiceProviderAggregati
171
138
172
139
@returnsPromise
173
140
async next ( ) : Promise < Document | null > {
174
- return this . _withCheckMapError ( ( ) => this . _cursor . next ( ) ) ;
141
+ let result = await this . _cursor . next ( ) ;
142
+ if ( result !== null && this . _transform !== null ) {
143
+ result = await this . _transform ( result ) ;
144
+ }
145
+ return result ;
175
146
}
176
147
177
148
@returnType ( 'this' )
0 commit comments