@@ -38,6 +38,8 @@ export class ClientBulkWriteCommandBuilder {
38
38
models : AnyClientBulkWriteModel [ ] ;
39
39
options : ClientBulkWriteOptions ;
40
40
pkFactory : PkFactory ;
41
+ currentModelIndex : number ;
42
+ lastOperations : Document [ ] ;
41
43
42
44
/**
43
45
* Create the command builder.
@@ -51,6 +53,8 @@ export class ClientBulkWriteCommandBuilder {
51
53
this . models = models ;
52
54
this . options = options ;
53
55
this . pkFactory = pkFactory ?? DEFAULT_PK_FACTORY ;
56
+ this . currentModelIndex = 0 ;
57
+ this . lastOperations = [ ] ;
54
58
}
55
59
56
60
/**
@@ -65,68 +69,55 @@ export class ClientBulkWriteCommandBuilder {
65
69
}
66
70
67
71
/**
68
- * Build the bulk write commands from the models.
72
+ * Determines if there is another batch to process.
73
+ * @returns True if not all batches have been built.
69
74
*/
70
- buildCommands ( maxMessageSizeBytes : number , maxWriteBatchSize : number ) : ClientBulkWriteCommand [ ] {
71
- // Iterate the models to build the ops and nsInfo fields.
72
- // We need to do this in a loop which creates one command each up
73
- // to the max bson size or max message size.
74
- const commands : ClientBulkWriteCommand [ ] = [ ] ;
75
- let currentCommandLength = 0 ;
75
+ hasNextBatch ( ) : boolean {
76
+ return this . currentModelIndex < this . models . length ;
77
+ }
78
+
79
+ /**
80
+ * Build a single batch of a client bulk write command.
81
+ * @param maxMessageSizeBytes - The max message size in bytes.
82
+ * @param maxWriteBatchSize - The max write batch size.
83
+ * @returns The client bulk write command.
84
+ */
85
+ buildBatch ( maxMessageSizeBytes : number , maxWriteBatchSize : number ) : ClientBulkWriteCommand {
86
+ let commandLength = 0 ;
76
87
let currentNamespaceIndex = 0 ;
77
- let currentCommand : ClientBulkWriteCommand = this . baseCommand ( ) ;
88
+ const command : ClientBulkWriteCommand = this . baseCommand ( ) ;
78
89
const namespaces = new Map < string , number > ( ) ;
79
90
80
- for ( const model of this . models ) {
91
+ while ( this . currentModelIndex < this . models . length ) {
92
+ const model = this . models [ this . currentModelIndex ] ;
81
93
const ns = model . namespace ;
82
- const index = namespaces . get ( ns ) ;
83
-
84
- /**
85
- * Convenience function for resetting everything when a new batch
86
- * is started.
87
- */
88
- const reset = ( ) => {
89
- commands . push ( currentCommand ) ;
90
- namespaces . clear ( ) ;
91
- currentNamespaceIndex = 0 ;
92
- currentCommand = this . baseCommand ( ) ;
93
- namespaces . set ( ns , currentNamespaceIndex ) ;
94
- } ;
94
+ const nsIndex = namespaces . get ( ns ) ;
95
95
96
- if ( index != null ) {
97
- // Pushing to the ops document sequence returns the bytes length added .
98
- const operation = buildOperation ( model , index , this . pkFactory ) ;
96
+ if ( nsIndex != null ) {
97
+ // Build the operation and serialize it to get the bytes buffer .
98
+ const operation = buildOperation ( model , nsIndex , this . pkFactory ) ;
99
99
const operationBuffer = BSON . serialize ( operation ) ;
100
100
101
- // Check if the operation buffer can fit in the current command. If it can,
101
+ // Check if the operation buffer can fit in the command. If it can,
102
102
// then add the operation to the document sequence and increment the
103
103
// current length as long as the ops don't exceed the maxWriteBatchSize.
104
104
if (
105
- currentCommandLength + operationBuffer . length < maxMessageSizeBytes &&
106
- currentCommand . ops . documents . length < maxWriteBatchSize
105
+ commandLength + operationBuffer . length < maxMessageSizeBytes &&
106
+ command . ops . documents . length < maxWriteBatchSize
107
107
) {
108
108
// Pushing to the ops document sequence returns the total byte length of the document sequence.
109
- currentCommandLength =
110
- MESSAGE_OVERHEAD_BYTES + this . addOperation ( currentCommand , operation , operationBuffer ) ;
109
+ commandLength = MESSAGE_OVERHEAD_BYTES + command . ops . push ( operation , operationBuffer ) ;
110
+ // Increment the builder's current model index.
111
+ this . currentModelIndex ++ ;
111
112
} else {
112
- // We need to batch. Push the current command to the commands
113
- // array and create a new current command. We aslo need to clear the namespaces
114
- // map for the new command.
115
- reset ( ) ;
116
-
117
- const nsInfo = { ns : ns } ;
118
- const nsInfoBuffer = BSON . serialize ( nsInfo ) ;
119
- currentCommandLength =
120
- MESSAGE_OVERHEAD_BYTES +
121
- this . addOperationAndNsInfo (
122
- currentCommand ,
123
- operation ,
124
- operationBuffer ,
125
- nsInfo ,
126
- nsInfoBuffer
127
- ) ;
113
+ // The operation cannot fit in the current command and will need to
114
+ // go in the next batch. Exit the loop and set the last ops.
115
+ this . lastOperations = command . ops . documents ;
116
+ break ;
128
117
}
129
118
} else {
119
+ // The namespace is not already in the nsInfo so we will set it in the map, and
120
+ // construct our nsInfo and ops documents and buffers.
130
121
namespaces . set ( ns , currentNamespaceIndex ) ;
131
122
const nsInfo = { ns : ns } ;
132
123
const nsInfoBuffer = BSON . serialize ( nsInfo ) ;
@@ -138,68 +129,27 @@ export class ClientBulkWriteCommandBuilder {
138
129
// sequences and increment the current length as long as the ops don't exceed
139
130
// the maxWriteBatchSize.
140
131
if (
141
- currentCommandLength + nsInfoBuffer . length + operationBuffer . length <
142
- maxMessageSizeBytes &&
143
- currentCommand . ops . documents . length < maxWriteBatchSize
132
+ commandLength + nsInfoBuffer . length + operationBuffer . length < maxMessageSizeBytes &&
133
+ command . ops . documents . length < maxWriteBatchSize
144
134
) {
145
- currentCommandLength =
135
+ // Pushing to the ops document sequence returns the total byte length of the document sequence.
136
+ commandLength =
146
137
MESSAGE_OVERHEAD_BYTES +
147
- this . addOperationAndNsInfo (
148
- currentCommand ,
149
- operation ,
150
- operationBuffer ,
151
- nsInfo ,
152
- nsInfoBuffer
153
- ) ;
138
+ command . nsInfo . push ( nsInfo , nsInfoBuffer ) +
139
+ command . ops . push ( operation , operationBuffer ) ;
140
+ // We've added a new namespace, increment the namespace index.
141
+ currentNamespaceIndex ++ ;
142
+ // Increment the builder's current model index.
143
+ this . currentModelIndex ++ ;
154
144
} else {
155
- // We need to batch. Push the current command to the commands
156
- // array and create a new current command. Aslo clear the namespaces map.
157
- reset ( ) ;
158
-
159
- currentCommandLength =
160
- MESSAGE_OVERHEAD_BYTES +
161
- this . addOperationAndNsInfo (
162
- currentCommand ,
163
- operation ,
164
- operationBuffer ,
165
- nsInfo ,
166
- nsInfoBuffer
167
- ) ;
145
+ // The operation cannot fit in the current command and will need to
146
+ // go in the next batch. Exit the loop and set the last ops.
147
+ this . lastOperations = command . ops . documents ;
148
+ break ;
168
149
}
169
- // We've added a new namespace, increment the namespace index.
170
- currentNamespaceIndex ++ ;
171
150
}
172
151
}
173
-
174
- // After we've finisihed iterating all the models put the last current command
175
- // only if there are operations in it.
176
- if ( currentCommand . ops . documents . length > 0 ) {
177
- commands . push ( currentCommand ) ;
178
- }
179
-
180
- return commands ;
181
- }
182
-
183
- private addOperation (
184
- command : ClientBulkWriteCommand ,
185
- operation : Document ,
186
- operationBuffer : Uint8Array
187
- ) : number {
188
- // Pushing to the ops document sequence returns the total byte length of the document sequence.
189
- return command . ops . push ( operation , operationBuffer ) ;
190
- }
191
-
192
- private addOperationAndNsInfo (
193
- command : ClientBulkWriteCommand ,
194
- operation : Document ,
195
- operationBuffer : Uint8Array ,
196
- nsInfo : Document ,
197
- nsInfoBuffer : Uint8Array
198
- ) : number {
199
- // Pushing to the nsInfo document sequence returns the total byte length of the document sequence.
200
- const nsInfoLength = command . nsInfo . push ( nsInfo , nsInfoBuffer ) ;
201
- const opsLength = this . addOperation ( command , operation , operationBuffer ) ;
202
- return nsInfoLength + opsLength ;
152
+ return command ;
203
153
}
204
154
205
155
private baseCommand ( ) : ClientBulkWriteCommand {
0 commit comments