@@ -412,29 +412,57 @@ public struct BulkWriteResult: Codable {
412412 * - `MongoError.InternalError` if an unexpected error occurs reading the reply from the server.
413413 */
414414 fileprivate init ? ( reply: BSONDocument , insertedIDs: [ Int : BSON ] ) throws {
415- guard reply. keys. contains ( where: { MongocKeys ( rawValue: $0) != nil } ) else {
416- return nil
417- }
418-
419- self . deletedCount = reply [ MongocKeys . deletedCount. rawValue] ? . toInt ( ) ?? 0
420-
421- self . insertedCount = reply [ MongocKeys . insertedCount. rawValue] ? . toInt ( ) ?? 0
422- self . insertedIDs = insertedIDs
423- self . matchedCount = reply [ MongocKeys . matchedCount. rawValue] ? . toInt ( ) ?? 0
424- self . modifiedCount = reply [ MongocKeys . modifiedCount. rawValue] ? . toInt ( ) ?? 0
425- self . upsertedCount = reply [ MongocKeys . upsertedCount. rawValue] ? . toInt ( ) ?? 0
426-
415+ var deletedCount : Int ?
416+ var insertedCount : Int ?
417+ var matchedCount : Int ?
418+ var modifiedCount : Int ?
419+ var upsertedCount : Int ?
427420 var upsertedIDs = [ Int: BSON] ( )
428421
429- if let upserted = reply [ MongocKeys . upserted. rawValue] ? . arrayValue {
430- for upsert in upserted. compactMap ( { $0. documentValue } ) {
431- guard let index = upsert [ " index " ] ? . toInt ( ) else {
432- throw MongoError . InternalError ( message: " Could not cast upserted index to `Int` " )
422+ // To improve the performance of this initializer, we perform only a single walk over the entire document and
423+ // record the values as they are encountered instead of doing repeated random lookups, since each lookup
424+ // would result in a traversal of the document.
425+ var seenKey = false
426+ for (k, v) in reply {
427+ guard let key = MongocKeys ( rawValue: k) else {
428+ continue
429+ }
430+
431+ seenKey = true
432+
433+ switch key {
434+ case . deletedCount:
435+ deletedCount = v. toInt ( )
436+ case . insertedCount:
437+ insertedCount = v. toInt ( )
438+ case . matchedCount:
439+ matchedCount = v. toInt ( )
440+ case . modifiedCount:
441+ modifiedCount = v. toInt ( )
442+ case . upsertedCount:
443+ upsertedCount = v. toInt ( )
444+ case . upserted:
445+ if let upserted = reply [ MongocKeys . upserted. rawValue] ? . arrayValue? . compactMap ( { $0. documentValue } ) {
446+ for upsert in upserted {
447+ guard let index = upsert [ " index " ] ? . toInt ( ) else {
448+ throw MongoError . InternalError ( message: " Could not cast upserted index to `Int` " )
449+ }
450+ upsertedIDs [ index] = upsert [ " _id " ]
451+ }
433452 }
434- upsertedIDs [ index] = upsert [ " _id " ]
435453 }
436454 }
437455
456+ guard seenKey else {
457+ return nil
458+ }
459+
460+ self . deletedCount = deletedCount ?? 0
461+ self . insertedCount = insertedCount ?? 0
462+ self . insertedIDs = insertedIDs
463+ self . matchedCount = matchedCount ?? 0
464+ self . modifiedCount = modifiedCount ?? 0
465+ self . upsertedCount = upsertedCount ?? 0
438466 self . upsertedIDs = upsertedIDs
439467 }
440468
0 commit comments