@@ -170,11 +170,6 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
170
170
lastHelloMS ?: number ;
171
171
serverApi ?: ServerApi ;
172
172
helloOk ?: boolean ;
173
- commandAsync : (
174
- ns : MongoDBNamespace ,
175
- cmd : Document ,
176
- options : CommandOptions | undefined
177
- ) => Promise < Document > ;
178
173
/** @internal */
179
174
authContext ?: AuthContext ;
180
175
@@ -217,15 +212,6 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
217
212
constructor ( stream : Stream , options : ConnectionOptions ) {
218
213
super ( ) ;
219
214
220
- this . commandAsync = promisify (
221
- (
222
- ns : MongoDBNamespace ,
223
- cmd : Document ,
224
- options : CommandOptions | undefined ,
225
- callback : Callback
226
- ) => this . command ( ns , cmd , options , callback as any )
227
- ) ;
228
-
229
215
this . id = options . id ;
230
216
this . address = streamIdentifier ( stream , options ) ;
231
217
this . socketTimeoutMS = options . socketTimeoutMS ?? 0 ;
@@ -262,6 +248,12 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
262
248
this [ kMessageStream ] . pipe ( this [ kStream ] ) ;
263
249
}
264
250
251
+ // This whole class is temporary,
252
+ // Need to move this to be defined on the prototype for spying.
253
+ async commandAsync ( ns : MongoDBNamespace , cmd : Document , opt ?: CommandOptions ) {
254
+ return promisify ( this . command . bind ( this ) ) ( ns , cmd , opt ) ;
255
+ }
256
+
265
257
get description ( ) : StreamDescription {
266
258
return this [ kDescription ] ;
267
259
}
@@ -791,7 +783,6 @@ export class ModernConnection extends TypedEventEmitter<ConnectionEvents> {
791
783
lastHelloMS ?: number ;
792
784
serverApi ?: ServerApi ;
793
785
helloOk ?: boolean ;
794
- commandAsync : ModernConnection [ 'command' ] ;
795
786
/** @internal */
796
787
authContext ?: AuthContext ;
797
788
@@ -831,8 +822,6 @@ export class ModernConnection extends TypedEventEmitter<ConnectionEvents> {
831
822
constructor ( stream : Stream , options : ConnectionOptions ) {
832
823
super ( ) ;
833
824
834
- this . commandAsync = this . command . bind ( this ) ;
835
-
836
825
this . id = options . id ;
837
826
this . address = streamIdentifier ( stream , options ) ;
838
827
this . socketTimeoutMS = options . socketTimeoutMS ?? 0 ;
@@ -852,6 +841,10 @@ export class ModernConnection extends TypedEventEmitter<ConnectionEvents> {
852
841
this . socket . on ( 'timeout' , this . onTimeout . bind ( this ) ) ;
853
842
}
854
843
844
+ async commandAsync ( ...args : Parameters < typeof this . command > ) {
845
+ return this . command ( ...args ) ;
846
+ }
847
+
855
848
/** Indicates that the connection (including underlying TCP socket) has been closed. */
856
849
get closed ( ) : boolean {
857
850
return this . controller . signal . aborted ;
@@ -1036,62 +1029,68 @@ export class ModernConnection extends TypedEventEmitter<ConnectionEvents> {
1036
1029
return message ;
1037
1030
}
1038
1031
1039
- private async sendCommand (
1040
- message : WriteProtocolMessageType ,
1041
- options : CommandOptions
1042
- ) : Promise < Document > {
1043
- const { signal } = this . controller ;
1044
-
1045
- signal . throwIfAborted ( ) ;
1032
+ private async * sendWire ( message : WriteProtocolMessageType , options : CommandOptions ) {
1033
+ this . controller . signal . throwIfAborted ( ) ;
1046
1034
1047
1035
if ( typeof options . socketTimeoutMS === 'number' ) {
1048
1036
this . socket . setTimeout ( options . socketTimeoutMS ) ;
1049
1037
} else if ( this . socketTimeoutMS !== 0 ) {
1050
1038
this . socket . setTimeout ( this . socketTimeoutMS ) ;
1051
1039
}
1052
1040
1053
- let response ;
1054
1041
try {
1055
1042
await writeCommand ( this , message , {
1056
1043
agreedCompressor : this . description . compressor ?? 'none' ,
1057
1044
zlibCompressionLevel : this . description . zlibCompressionLevel ,
1058
- signal
1045
+ signal : this . controller . signal
1059
1046
} ) ;
1060
1047
1061
- if ( options . noResponse ) return { ok : 1 } ;
1048
+ // TODO(NODE-5770): Replace controller to avoid boundless 'abort' listeners
1049
+ this . controller = new AbortController ( ) ;
1062
1050
1063
- signal . throwIfAborted ( ) ;
1051
+ if ( options . noResponse ) {
1052
+ yield { ok : 1 } ;
1053
+ return ;
1054
+ }
1064
1055
1065
- response = await read ( this , { signal } ) ;
1066
- } finally {
1067
- // TODO(NODE-5770): Replace controller to avoid boundless 'abort' listeners
1068
- if ( ! signal . aborted ) this . controller = new AbortController ( ) ;
1069
- }
1056
+ this . controller . signal . throwIfAborted ( ) ;
1070
1057
1071
- response . parse ( options ) ;
1058
+ for await ( const response of readMany ( this , { signal : this . controller . signal } ) ) {
1059
+ this . socket . setTimeout ( 0 ) ;
1060
+ response . parse ( options ) ;
1072
1061
1073
- const [ document ] = response . documents ;
1062
+ const [ document ] = response . documents ;
1074
1063
1075
- if ( ! Buffer . isBuffer ( document ) ) {
1076
- const { session } = options ;
1077
- if ( session ) {
1078
- updateSessionFromResponse ( session , document ) ;
1079
- }
1064
+ if ( ! Buffer . isBuffer ( document ) ) {
1065
+ const { session } = options ;
1066
+ if ( session ) {
1067
+ updateSessionFromResponse ( session , document ) ;
1068
+ }
1080
1069
1081
- if ( document . $clusterTime ) {
1082
- this [ kClusterTime ] = document . $clusterTime ;
1083
- this . emit ( Connection . CLUSTER_TIME_RECEIVED , document . $clusterTime ) ;
1070
+ if ( document . $clusterTime ) {
1071
+ this [ kClusterTime ] = document . $clusterTime ;
1072
+ this . emit ( Connection . CLUSTER_TIME_RECEIVED , document . $clusterTime ) ;
1073
+ }
1074
+ }
1075
+
1076
+ // TODO(NODE-5770): Replace controller to avoid boundless 'abort' listeners
1077
+ this . controller = new AbortController ( ) ;
1078
+
1079
+ yield document ;
1080
+ this . controller . signal . throwIfAborted ( ) ;
1081
+
1082
+ if ( typeof options . socketTimeoutMS === 'number' ) {
1083
+ this . socket . setTimeout ( options . socketTimeoutMS ) ;
1084
+ } else if ( this . socketTimeoutMS !== 0 ) {
1085
+ this . socket . setTimeout ( this . socketTimeoutMS ) ;
1086
+ }
1084
1087
}
1088
+ } finally {
1089
+ this . socket . setTimeout ( 0 ) ;
1085
1090
}
1086
-
1087
- return document ;
1088
1091
}
1089
1092
1090
- async command (
1091
- ns : MongoDBNamespace ,
1092
- command : Document ,
1093
- options : CommandOptions = { }
1094
- ) : Promise < Document > {
1093
+ async * sendCommand ( ns : MongoDBNamespace , command : Document , options : CommandOptions = { } ) {
1095
1094
const message = this . prepareCommand ( ns . db , command , options ) ;
1096
1095
1097
1096
let started = 0 ;
@@ -1103,76 +1102,84 @@ export class ModernConnection extends TypedEventEmitter<ConnectionEvents> {
1103
1102
) ;
1104
1103
}
1105
1104
1106
- let document = null ;
1105
+ let document ;
1107
1106
try {
1108
- document = await this . sendCommand ( message , options ) ;
1109
- } catch ( ioError ) {
1110
- if ( this . monitorCommands ) {
1111
- this . emit (
1112
- ModernConnection . COMMAND_FAILED ,
1113
- new CommandFailedEvent ( this as unknown as Connection , message , ioError , started )
1114
- ) ;
1115
- }
1116
- throw ioError ;
1117
- }
1107
+ this . controller . signal . throwIfAborted ( ) ;
1108
+ for await ( document of this . sendWire ( message , options ) ) {
1109
+ if ( ! Buffer . isBuffer ( document ) && document . writeConcernError ) {
1110
+ throw new MongoWriteConcernError ( document . writeConcernError , document ) ;
1111
+ }
1118
1112
1119
- if ( document == null ) {
1120
- const unexpected = new MongoUnexpectedServerResponseError (
1121
- 'sendCommand did not throw and did not return a document'
1122
- ) ;
1123
- if ( this . monitorCommands ) {
1124
- this . emit (
1125
- ModernConnection . COMMAND_FAILED ,
1126
- new CommandFailedEvent ( this as unknown as Connection , message , unexpected , started )
1127
- ) ;
1128
- }
1129
- throw unexpected ;
1130
- }
1113
+ if (
1114
+ ! Buffer . isBuffer ( document ) &&
1115
+ ( document . ok === 0 || document . $err || document . errmsg || document . code )
1116
+ ) {
1117
+ throw new MongoServerError ( document ) ;
1118
+ }
1131
1119
1132
- if ( document . writeConcernError ) {
1133
- const writeConcernError = new MongoWriteConcernError ( document . writeConcernError , document ) ;
1134
- if ( this . monitorCommands ) {
1135
- this . emit (
1136
- ModernConnection . COMMAND_SUCCEEDED ,
1137
- new CommandSucceededEvent ( this as unknown as Connection , message , document , started )
1138
- ) ;
1139
- }
1140
- throw writeConcernError ;
1141
- }
1120
+ if ( this . monitorCommands ) {
1121
+ this . emit (
1122
+ ModernConnection . COMMAND_SUCCEEDED ,
1123
+ new CommandSucceededEvent (
1124
+ this as unknown as Connection ,
1125
+ message ,
1126
+ options . noResponse ? undefined : document ,
1127
+ started
1128
+ )
1129
+ ) ;
1130
+ }
1142
1131
1143
- if ( document . ok === 0 || document . $err || document . errmsg || document . code ) {
1144
- const serverError = new MongoServerError ( document ) ;
1132
+ yield document ;
1133
+ this . controller . signal . throwIfAborted ( ) ;
1134
+ }
1135
+ } catch ( error ) {
1145
1136
if ( this . monitorCommands ) {
1146
- this . emit (
1147
- ModernConnection . COMMAND_FAILED ,
1148
- new CommandFailedEvent ( this as unknown as Connection , message , serverError , started )
1149
- ) ;
1137
+ error . name === 'MongoWriteConcernError'
1138
+ ? this . emit (
1139
+ ModernConnection . COMMAND_SUCCEEDED ,
1140
+ new CommandSucceededEvent (
1141
+ this as unknown as Connection ,
1142
+ message ,
1143
+ options . noResponse ? undefined : document ,
1144
+ started
1145
+ )
1146
+ )
1147
+ : this . emit (
1148
+ ModernConnection . COMMAND_FAILED ,
1149
+ new CommandFailedEvent ( this as unknown as Connection , message , error , started )
1150
+ ) ;
1150
1151
}
1151
- throw serverError ;
1152
+ throw error ;
1152
1153
}
1154
+ }
1153
1155
1154
- if ( this . monitorCommands ) {
1155
- this . emit (
1156
- ModernConnection . COMMAND_SUCCEEDED ,
1157
- new CommandSucceededEvent (
1158
- this as unknown as Connection ,
1159
- message ,
1160
- options . noResponse ? undefined : document ,
1161
- started
1162
- )
1163
- ) ;
1156
+ async command (
1157
+ ns : MongoDBNamespace ,
1158
+ command : Document ,
1159
+ options : CommandOptions = { }
1160
+ ) : Promise < Document > {
1161
+ this . controller . signal . throwIfAborted ( ) ;
1162
+ for await ( const document of this . sendCommand ( ns , command , options ) ) {
1163
+ return document ;
1164
1164
}
1165
-
1166
- return document ;
1165
+ throw new MongoUnexpectedServerResponseError ( 'Unable to get response from server' ) ;
1167
1166
}
1168
1167
1169
1168
exhaustCommand (
1170
- _ns : MongoDBNamespace ,
1171
- _command : Document ,
1172
- _options : CommandOptions ,
1173
- _replyListener : Callback
1169
+ ns : MongoDBNamespace ,
1170
+ command : Document ,
1171
+ options : CommandOptions ,
1172
+ replyListener : Callback
1174
1173
) {
1175
- throw new Error ( 'NODE-5742: not implemented.' ) ;
1174
+ const exhaustLoop = async ( ) => {
1175
+ this . controller . signal . throwIfAborted ( ) ;
1176
+ for await ( const reply of this . sendCommand ( ns , command , options ) ) {
1177
+ replyListener ( undefined , reply ) ;
1178
+ this . controller . signal . throwIfAborted ( ) ;
1179
+ }
1180
+ throw new MongoUnexpectedServerResponseError ( 'Server ended moreToCome unexpectedly' ) ;
1181
+ } ;
1182
+ exhaustLoop ( ) . catch ( replyListener ) ;
1176
1183
}
1177
1184
}
1178
1185
0 commit comments