@@ -16,21 +16,6 @@ public struct BSONDocument {
1616
1717 private var storage : BSONDocumentStorage
1818
19- internal var byteLength : Int {
20- get {
21- guard let byteLength = self . storage. buffer. getInteger ( at: 0 , endianness: . little, as: Int32 . self) else {
22- fatalError ( " Cannot read byteLength of BSON from buffer " )
23- }
24- return Int ( byteLength)
25- }
26- set {
27- guard newValue <= Int32 . max else {
28- fatalError ( " Cannot cast \( newValue) down to Int32 " )
29- }
30- self . storage. buffer. setInteger ( Int32 ( newValue) , at: 0 , endianness: . little, as: Int32 . self)
31- }
32- }
33-
3419 /// An unordered set containing the keys in this document.
3520 internal private( set) var keySet : Set < String >
3621
@@ -66,8 +51,8 @@ public struct BSONDocument {
6651 fatalError ( " Data is \( self . storage. buffer. writerIndex - start) bytes, "
6752 + " but maximum allowed BSON document size is \( Int32 . max) bytes " )
6853 }
69- // Set byteLength in reserved space
70- self . storage. buffer . setInteger ( byteLength , at : 0 , endianness : . little , as : Int32 . self )
54+ // Set encodedLength in reserved space
55+ self . storage. encodedLength = Int ( byteLength )
7156 }
7257
7358 /// Initializes a new, empty `BSONDocument`.
@@ -103,16 +88,13 @@ public struct BSONDocument {
10388 */
10489 public init ( fromBSON bson: ByteBuffer ) throws {
10590 let storage = BSONDocumentStorage ( bson)
106- try storage. validate ( )
107- self = BSONDocument ( fromUnsafeBSON: storage)
91+ let keys = try storage. validateAndRetrieveKeys ( )
92+ self = BSONDocument ( fromUnsafeBSON: storage, keys : keys )
10893 }
10994
110- private init ( fromUnsafeBSON storage: BSONDocumentStorage ) {
111- self . keySet = Set ( )
95+ private init ( fromUnsafeBSON storage: BSONDocumentStorage , keys: Set < String > ) {
11296 self . storage = storage
113- for (key, _) in self {
114- self . keySet. insert ( key)
115- }
97+ self . keySet = keys
11698 }
11799
118100 /**
@@ -240,6 +222,44 @@ public struct BSONDocument {
240222 set { self [ member] = newValue }
241223 }
242224
225+ /**
226+ * Returns a copy of this document with an `_id` element prepended. If the document already contains an `_id`,
227+ * returns the document as-is.
228+ * - Throws: `BSONError.DocumentTooLargeError` if adding the `_id` would make the document exceed the maximum
229+ * allowed size for a document.
230+ * - SeeAlso: https://docs.mongodb.com/manual/core/document/#the-id-field
231+ */
232+ public func withID( ) throws -> BSONDocument {
233+ guard !self . keySet. contains ( " _id " ) else {
234+ return self
235+ }
236+
237+ var newStorage = BSONDocumentStorage ( )
238+ // placeholder for length
239+ newStorage. buffer. writeInteger ( 0 , endianness: . little, as: Int32 . self)
240+ var newSize = self . storage. encodedLength
241+
242+ let _id = BSON . objectID ( )
243+ newSize += newStorage. append ( key: " _id " , value: _id)
244+
245+ guard newSize <= BSON_MAX_SIZE else {
246+ throw BSONError . DocumentTooLargeError ( value: _id. bsonValue, forKey: " _id " )
247+ }
248+
249+ guard let suffix = self . storage. buffer. getBytes ( at: 4 , length: self . storage. encodedLength - 4 ) else {
250+ throw BSONError . InternalError (
251+ message: " Failed to slice buffer from 4 to \( self . storage. encodedLength) : \( self . storage. buffer) "
252+ )
253+ }
254+ newStorage. buffer. writeBytes ( suffix)
255+
256+ var newKeys = self . keySet
257+ newKeys. insert ( " _id " )
258+ var document = BSONDocument ( fromUnsafeBSON: newStorage, keys: newKeys)
259+ document. storage. encodedLength = newSize
260+ return document
261+ }
262+
243263 /**
244264 * Sets a BSON element with the corresponding key
245265 * if element.value is nil the element is deleted from the BSON
@@ -252,10 +272,11 @@ public struct BSONDocument {
252272 }
253273 // appending new key
254274 self . keySet. insert ( key)
255- self . storage. buffer. moveWriterIndex ( to: self . byteLength - 1 ) // setup to overwrite null terminator
275+ // setup to overwrite null terminator
276+ self . storage. buffer. moveWriterIndex ( to: self . storage. encodedLength - 1 )
256277 let size = self . storage. append ( key: key, value: value)
257278 self . storage. buffer. writeInteger ( 0 , endianness: . little, as: UInt8 . self) // add back in our null terminator
258- self . byteLength += size
279+ self . storage . encodedLength += size
259280 return
260281 }
261282
@@ -265,21 +286,24 @@ public struct BSONDocument {
265286 throw BSONError . InternalError ( message: " Cannot find \( key) to delete " )
266287 }
267288
289+ let prefixLength = range. startIndex
290+ let suffixLength = self . storage. encodedLength - range. endIndex
291+
268292 guard
269- let prefix = self . storage. buffer. getBytes ( at: 0 , length: range . startIndex ) ,
270- let suffix = self . storage. buffer. getBytes ( at: range. endIndex, length: self . byteLength - range . endIndex )
293+ let prefix = self . storage. buffer. getBytes ( at: 0 , length: prefixLength ) ,
294+ let suffix = self . storage. buffer. getBytes ( at: range. endIndex, length: suffixLength )
271295 else {
272296 throw BSONError . InternalError (
273297 message: " Cannot slice buffer from " +
274298 " 0 to len \( range. startIndex) and from \( range. endIndex) " +
275- " to len \( self . byteLength - range . endIndex ) : \( self . storage. buffer) "
299+ " to len \( suffixLength ) : \( self . storage. buffer) "
276300 )
277301 }
278302
279303 var newStorage = BSONDocumentStorage ( )
280304 newStorage. buffer. writeBytes ( prefix)
281305
282- var newSize = self . byteLength - ( range. endIndex - range. startIndex)
306+ var newSize = self . storage . encodedLength - ( range. endIndex - range. startIndex)
283307 if let value = value {
284308 // Overwriting
285309 let size = newStorage. append ( key: key, value: value)
@@ -296,9 +320,9 @@ public struct BSONDocument {
296320 newStorage. buffer. writeBytes ( suffix)
297321
298322 self . storage = newStorage
299- self . byteLength = newSize
300- guard self . byteLength == self . storage. buffer. readableBytes else {
301- fatalError ( " BSONDocument's encoded byte length is \( self . byteLength ) , however the " +
323+ self . storage . encodedLength = newSize
324+ guard self . storage . encodedLength == self . storage. buffer. readableBytes else {
325+ fatalError ( " BSONDocument's encoded byte length is \( self . storage . encodedLength ) , however the " +
302326 " buffer has \( self . storage. buffer. readableBytes) readable bytes " )
303327 }
304328 }
@@ -314,6 +338,21 @@ public struct BSONDocument {
314338 /// Create BSONDocumentStorage with a 0 capacity buffer.
315339 internal init ( ) { self . buffer = BSON_ALLOCATOR . buffer ( capacity: 0 ) }
316340
341+ internal var encodedLength : Int {
342+ get {
343+ guard let encodedLength = self . buffer. getInteger ( at: 0 , endianness: . little, as: Int32 . self) else {
344+ fatalError ( " Cannot read encoded Length of BSON from buffer " )
345+ }
346+ return Int ( encodedLength)
347+ }
348+ set {
349+ guard newValue <= Int32 . max else {
350+ fatalError ( " Cannot cast \( newValue) down to Int32 " )
351+ }
352+ self . buffer. setInteger ( Int32 ( newValue) , at: 0 , endianness: . little, as: Int32 . self)
353+ }
354+ }
355+
317356 /// Appends element to underlying BSON bytes, returns the size of the element appended: type + key + value
318357 @discardableResult internal mutating func append( key: String , value: BSON ) -> Int {
319358 let writer = self . buffer. writerIndex
@@ -323,36 +362,44 @@ public struct BSONDocument {
323362 return self . buffer. writerIndex - writer
324363 }
325364
326- internal func validate( ) throws {
365+ @discardableResult
366+ internal func validateAndRetrieveKeys( ) throws -> Set < String > {
327367 // Pull apart the underlying binary into [KeyValuePair], should reveal issues
328- guard let byteLength = self . buffer. getInteger ( at: 0 , endianness: . little, as: Int32 . self) else {
329- throw BSONError . InvalidArgumentError ( message: " Validation Failed: Cannot read byteLength " )
368+ guard let encodedLength = self . buffer. getInteger ( at: 0 , endianness: . little, as: Int32 . self) else {
369+ throw BSONError . InvalidArgumentError ( message: " Validation Failed: Cannot read encoded length " )
330370 }
331371
332- guard byteLength >= BSON_MIN_SIZE && byteLength <= BSON_MAX_SIZE else {
372+ guard encodedLength >= BSON_MIN_SIZE && encodedLength <= BSON_MAX_SIZE else {
333373 throw BSONError . InvalidArgumentError (
334- message: " Validation Failed: BSON cannot be \( byteLength ) bytes long "
374+ message: " Validation Failed: BSON cannot be \( encodedLength ) bytes long "
335375 )
336376 }
337377
338- guard byteLength == self . buffer. readableBytes else {
378+ guard encodedLength == self . buffer. readableBytes else {
339379 throw BSONError . InvalidArgumentError (
340- message: " BSONDocument's encoded byte length is \( byteLength ) , however the " +
380+ message: " BSONDocument's encoded byte length is \( encodedLength ) , however the " +
341381 " buffer has \( self . buffer. readableBytes) readable bytes "
342382 )
343383 }
344384
385+ var keySet = Set < String > ( )
345386 let iter = BSONDocumentIterator ( over: self . buffer)
346387 // Implicitly validate with iterator
347388 do {
348- while let ( _, value) = try iter. nextThrowing ( ) {
389+ while let ( key, value) = try iter. nextThrowing ( ) {
390+ let ( inserted, _) = keySet. insert ( key)
391+ guard inserted else {
392+ throw BSONError . InvalidArgumentError (
393+ message: " Validation Failed: BSON contains multiple values for key \( key) "
394+ )
395+ }
349396 switch value {
350397 case let . document( doc) :
351- try doc. storage. validate ( )
398+ try doc. storage. validateAndRetrieveKeys ( )
352399 case let . array( array) :
353400 for item in array {
354401 if let doc = item. documentValue {
355- try doc. storage. validate ( )
402+ try doc. storage. validateAndRetrieveKeys ( )
356403 }
357404 }
358405 default :
@@ -364,6 +411,8 @@ public struct BSONDocument {
364411 message: " Validation Failed: \( error. message) "
365412 )
366413 }
414+
415+ return keySet
367416 }
368417 }
369418}
@@ -449,11 +498,11 @@ extension BSONDocument: BSONValue {
449498
450499 internal static func read( from buffer: inout ByteBuffer ) throws -> BSON {
451500 let reader = buffer. readerIndex
452- guard let byteLength = buffer. readInteger ( endianness: . little, as: Int32 . self) else {
501+ guard let encodedLength = buffer. readInteger ( endianness: . little, as: Int32 . self) else {
453502 throw BSONError . InternalError ( message: " Cannot read document byte length " )
454503 }
455504 buffer. moveReaderIndex ( to: reader)
456- guard let bytes = buffer. readBytes ( length: Int ( byteLength ) ) else {
505+ guard let bytes = buffer. readBytes ( length: Int ( encodedLength ) ) else {
457506 throw BSONError . InternalError ( message: " Cannot read document contents " )
458507 }
459508 return . document( try BSONDocument ( fromBSON: Data ( bytes) ) )
0 commit comments