@@ -15,28 +15,15 @@ public struct BSONDocument {
15
15
/// The element type of a document: a tuple containing an individual key-value pair.
16
16
public typealias KeyValuePair = ( key: String , value: BSON )
17
17
18
- private var storage : BSONDocumentStorage
19
-
20
- /// An unordered set containing the keys in this document.
21
- internal private( set) var keySet : Set < String >
18
+ internal var storage : BSONDocumentStorage
22
19
23
20
internal init ( _ elements: [ BSON ] ) {
24
21
self = BSONDocument ( keyValuePairs: elements. enumerated ( ) . map { i, element in ( String ( i) , element) } )
25
22
}
26
23
27
24
internal init ( keyValuePairs: [ ( String , BSON ) ] ) {
28
- self . keySet = Set ( keyValuePairs. map { $0. 0 } )
29
- guard self . keySet. count == keyValuePairs. count else {
30
- fatalError ( " Dictionary \( keyValuePairs) contains duplicate keys " )
31
- }
32
-
33
25
self . storage = BSONDocumentStorage ( )
34
26
35
- guard !self . keySet. isEmpty else {
36
- self = BSONDocument ( )
37
- return
38
- }
39
-
40
27
let start = self . storage. buffer. writerIndex
41
28
42
29
// reserve space for our byteLength that will be calculated
@@ -58,7 +45,6 @@ public struct BSONDocument {
58
45
59
46
/// Initializes a new, empty `BSONDocument`.
60
47
public init ( ) {
61
- self . keySet = Set ( )
62
48
self . storage = BSONDocumentStorage ( )
63
49
self . storage. buffer. writeInteger ( 5 , endianness: . little, as: Int32 . self)
64
50
self . storage. buffer. writeBytes ( [ 0 ] )
@@ -89,13 +75,12 @@ public struct BSONDocument {
89
75
*/
90
76
public init ( fromBSON bson: ByteBuffer ) throws {
91
77
let storage = BSONDocumentStorage ( bson)
92
- let keys = try storage. validateAndRetrieveKeys ( )
93
- self = BSONDocument ( fromUnsafeBSON: storage, keys : keys )
78
+ try storage. validate ( )
79
+ self = BSONDocument ( fromUnsafeBSON: storage)
94
80
}
95
81
96
- internal init ( fromUnsafeBSON storage: BSONDocumentStorage , keys : Set < String > ) {
82
+ internal init ( fromUnsafeBSON storage: BSONDocumentStorage ) {
97
83
self . storage = storage
98
- self . keySet = keys
99
84
}
100
85
101
86
/**
@@ -155,7 +140,13 @@ public struct BSONDocument {
155
140
public var values : [ BSON ] { self . map { _, val in val } }
156
141
157
142
/// The number of (key, value) pairs stored at the top level of this document.
158
- public var count : Int { self . keySet. count }
143
+ public var count : Int {
144
+ do {
145
+ return try BSONDocumentIterator . getKeys ( from: self . storage. buffer) . count
146
+ } catch {
147
+ return 0
148
+ }
149
+ }
159
150
160
151
/// A copy of the `ByteBuffer` backing this document, containing raw BSON data. As `ByteBuffer`s implement
161
152
/// copy-on-write, this copy will share byte storage with this document until either the document or the returned
@@ -166,7 +157,9 @@ public struct BSONDocument {
166
157
public func toData( ) -> Data { Data ( self . storage. buffer. readableBytesView) }
167
158
168
159
/// Returns a `Boolean` indicating whether this `BSONDocument` contains the provided key.
169
- public func hasKey( _ key: String ) -> Bool { self . keySet. contains ( key) }
160
+ public func hasKey( _ key: String ) -> Bool {
161
+ ( try ? BSONDocumentIterator . find ( key: key, in: self ) ) != nil
162
+ }
170
163
171
164
/**
172
165
* Allows getting and setting values on the document via subscript syntax.
@@ -236,7 +229,7 @@ public struct BSONDocument {
236
229
* - SeeAlso: https://docs.mongodb.com/manual/core/document/#the-id-field
237
230
*/
238
231
public func withID( ) throws -> BSONDocument {
239
- guard !self . keySet . contains ( " _id " ) else {
232
+ guard !self . hasKey ( " _id " ) else {
240
233
return self
241
234
}
242
235
@@ -259,37 +252,35 @@ public struct BSONDocument {
259
252
}
260
253
newStorage. buffer. writeBytes ( suffix)
261
254
262
- var newKeys = self . keySet
263
- newKeys. insert ( " _id " )
264
- var document = BSONDocument ( fromUnsafeBSON: newStorage, keys: newKeys)
255
+ var document = BSONDocument ( fromUnsafeBSON: newStorage)
265
256
document. storage. encodedLength = newSize
266
257
return document
267
258
}
268
259
260
+ /// Appends the provided key value pair without checking to see if the key already exists.
261
+ /// Warning: appending two of the same key may result in errors or undefined behavior.
262
+ internal mutating func append( key: String , value: BSON ) {
263
+ // setup to overwrite null terminator
264
+ self . storage. buffer. moveWriterIndex ( to: self . storage. encodedLength - 1 )
265
+ let size = self . storage. append ( key: key, value: value)
266
+ self . storage. buffer. writeInteger ( 0 , endianness: . little, as: UInt8 . self) // add back in our null terminator
267
+ self . storage. encodedLength += size
268
+ }
269
+
269
270
/**
270
271
* Sets a BSON element with the corresponding key
271
272
* if element.value is nil the element is deleted from the BSON
272
273
*/
273
274
internal mutating func set( key: String , to value: BSON ? ) throws {
274
- if ! self . keySet . contains ( key) {
275
+ guard let range = try BSONDocumentIterator . findByteRange ( for : key, in : self ) else {
275
276
guard let value = value else {
276
277
// no-op: key does not exist and the value is nil
277
278
return
278
279
}
279
- // appending new key
280
- self . keySet. insert ( key)
281
- // setup to overwrite null terminator
282
- self . storage. buffer. moveWriterIndex ( to: self . storage. encodedLength - 1 )
283
- let size = self . storage. append ( key: key, value: value)
284
- self . storage. buffer. writeInteger ( 0 , endianness: . little, as: UInt8 . self) // add back in our null terminator
285
- self . storage. encodedLength += size
280
+ self . append ( key: key, value: value)
286
281
return
287
282
}
288
283
289
- guard let range = try BSONDocumentIterator . findByteRange ( for: key, in: self ) else {
290
- throw BSONError . InternalError ( message: " Cannot find \( key) to delete " )
291
- }
292
-
293
284
let prefixLength = range. startIndex
294
285
let suffixLength = self . storage. encodedLength - range. endIndex
295
286
@@ -316,9 +307,6 @@ public struct BSONDocument {
316
307
guard newSize <= BSON_MAX_SIZE else {
317
308
throw BSONError . DocumentTooLargeError ( value: value. bsonValue, forKey: key)
318
309
}
319
- } else {
320
- // Deleting
321
- self . keySet. remove ( key)
322
310
}
323
311
324
312
newStorage. buffer. writeBytes ( suffix)
@@ -401,8 +389,7 @@ public struct BSONDocument {
401
389
return totalBytes
402
390
}
403
391
404
- @discardableResult
405
- internal func validateAndRetrieveKeys( ) throws -> Set < String > {
392
+ internal func validate( ) throws {
406
393
// Pull apart the underlying binary into [KeyValuePair], should reveal issues
407
394
guard let encodedLength = self . buffer. getInteger ( at: 0 , endianness: . little, as: Int32 . self) else {
408
395
throw BSONError . InvalidArgumentError ( message: " Validation Failed: Cannot read encoded length " )
@@ -423,7 +410,6 @@ public struct BSONDocument {
423
410
424
411
var keySet = Set < String > ( )
425
412
let iter = BSONDocumentIterator ( over: self . buffer)
426
- // Implicitly validate with iterator
427
413
do {
428
414
while let ( key, value) = try iter. nextThrowing ( ) {
429
415
let ( inserted, _) = keySet. insert ( key)
@@ -432,26 +418,13 @@ public struct BSONDocument {
432
418
message: " Validation Failed: BSON contains multiple values for key \( key) "
433
419
)
434
420
}
435
- switch value {
436
- case let . document( doc) :
437
- try doc. storage. validateAndRetrieveKeys ( )
438
- case let . array( array) :
439
- for item in array {
440
- if let doc = item. documentValue {
441
- try doc. storage. validateAndRetrieveKeys ( )
442
- }
443
- }
444
- default :
445
- continue
446
- }
421
+ try value. bsonValue. validate ( )
447
422
}
448
423
} catch let error as BSONError . InternalError {
449
424
throw BSONError . InvalidArgumentError (
450
425
message: " Validation Failed: \( error. message) "
451
426
)
452
427
}
453
-
454
- return keySet
455
428
}
456
429
}
457
430
}
@@ -469,6 +442,13 @@ extension BSONDocument: ExpressibleByDictionaryLiteral {
469
442
* - Returns: a new `BSONDocument`
470
443
*/
471
444
public init ( dictionaryLiteral keyValuePairs: ( String , BSON ) ... ) {
445
+ self . init ( dictionaryLiteral: Array ( keyValuePairs) )
446
+ }
447
+
448
+ internal init ( dictionaryLiteral keyValuePairs: [ ( String , BSON ) ] ) {
449
+ guard Set ( keyValuePairs. map { $0. 0 } ) . count == keyValuePairs. count else {
450
+ fatalError ( " Dictionary \( keyValuePairs) contains duplicate keys " )
451
+ }
472
452
self . init ( keyValuePairs: keyValuePairs)
473
453
}
474
454
}
@@ -548,13 +528,16 @@ extension BSONDocument: BSONValue {
548
528
throw BSONError . InternalError ( message: " Cannot read document contents " )
549
529
}
550
530
551
- let keys = try BSONDocumentIterator . getKeySet ( from: bytes)
552
- return . document( BSONDocument ( fromUnsafeBSON: BSONDocument . BSONDocumentStorage ( bytes) , keys: keys) )
531
+ return . document( BSONDocument ( fromUnsafeBSON: BSONDocument . BSONDocumentStorage ( bytes) ) )
553
532
}
554
533
555
534
internal func write( to buffer: inout ByteBuffer ) {
556
535
buffer. writeBytes ( self . storage. buffer. readableBytesView)
557
536
}
537
+
538
+ internal func validate( ) throws {
539
+ try self . storage. validate ( )
540
+ }
558
541
}
559
542
560
543
extension BSONDocument : CustomStringConvertible {
@@ -575,7 +558,7 @@ extension BSONDocument {
575
558
* - Returns: a `Bool` indicating whether the two documents are equal.
576
559
*/
577
560
public func equalsIgnoreKeyOrder( _ other: BSONDocument ) -> Bool {
578
- guard self . count == other. count else {
561
+ guard self . storage . encodedLength == other. storage . encodedLength else {
579
562
return false
580
563
}
581
564
0 commit comments