Skip to content

Commit 101ec2b

Browse files
authored
SWIFT-923 Encoding to BSON in BSONEncoder (#30)
1 parent 487c03f commit 101ec2b

File tree

2 files changed

+47
-34
lines changed

2 files changed

+47
-34
lines changed

Sources/BSON/BSONEncoder.swift

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -139,43 +139,16 @@ public class BSONEncoder {
139139
* - Throws: `EncodingError` if any value throws an error during encoding.
140140
*/
141141
public func encode<T: Encodable>(_ value: T) throws -> BSONDocument {
142-
// if the value being encoded is already a `BSONDocument` we're done
143-
if let doc = value as? BSONDocument {
142+
let encodedBSON: BSON = try self.encode(value)
143+
switch encodedBSON {
144+
case let .document(doc):
144145
return doc
145-
} else if let bson = value as? BSON, let doc = bson.documentValue {
146-
return doc
147-
}
148-
149-
let encoder = _BSONEncoder(options: self.options)
150-
151-
do {
152-
guard let boxedValue = try encoder.box_(value) else {
153-
throw EncodingError.invalidValue(
154-
value,
155-
EncodingError.Context(
156-
codingPath: [],
157-
debugDescription: "Top-level \(T.self) did not encode any values."
158-
)
159-
)
160-
}
161-
162-
guard let dict = boxedValue as? MutableDictionary else {
163-
throw EncodingError.invalidValue(
164-
value,
165-
EncodingError.Context(
166-
codingPath: [],
167-
debugDescription: "Top-level \(T.self) was not encoded as a complete document."
168-
)
169-
)
170-
}
171-
172-
return try dict.toDocument()
173-
} catch let error as BSONErrorProtocol {
146+
default:
174147
throw EncodingError.invalidValue(
175148
value,
176149
EncodingError.Context(
177150
codingPath: [],
178-
debugDescription: error.errorDescription ?? "Unknown Error occurred while encoding BSON"
151+
debugDescription: "Top-level \(T.self) was not encoded as a complete document."
179152
)
180153
)
181154
}
@@ -193,7 +166,7 @@ public class BSONEncoder {
193166
guard let value = value else {
194167
return nil
195168
}
196-
let encoded = try self.encode(value)
169+
let encoded: BSONDocument = try self.encode(value)
197170
return encoded == [:] ? nil : encoded
198171
}
199172

@@ -220,6 +193,41 @@ public class BSONEncoder {
220193
public func encode<T: Encodable>(_ values: [T?]) throws -> [BSONDocument?] {
221194
try values.map { try self.encode($0) }
222195
}
196+
197+
/**
198+
* Encodes the given top-level value and returns its BSON representation.
199+
*
200+
* - Parameter value: The value to encode.
201+
* - Returns: A new `BSON` containing the encoded BSON data.
202+
* - Throws: `EncodingError` if any value throws an error during encoding.
203+
*/
204+
internal func encode<T: Encodable>(_ value: T) throws -> BSON {
205+
let encoder = _BSONEncoder(options: self.options)
206+
207+
do {
208+
guard let boxedValue = try encoder.box_(value) else {
209+
throw EncodingError.invalidValue(
210+
value,
211+
EncodingError.Context(
212+
codingPath: [],
213+
debugDescription: "Top-level \(T.self) did not encode any values."
214+
)
215+
)
216+
}
217+
if let mutableDict = boxedValue as? MutableDictionary {
218+
return .document(try mutableDict.toDocument())
219+
}
220+
return boxedValue.bson
221+
} catch let error as BSONErrorProtocol {
222+
throw EncodingError.invalidValue(
223+
value,
224+
EncodingError.Context(
225+
codingPath: [],
226+
debugDescription: error.errorDescription ?? "Unknown Error occurred while encoding BSON"
227+
)
228+
)
229+
}
230+
}
223231
}
224232

225233
/// :nodoc: An internal class to implement the `Encoder` protocol.

Tests/BSONTests/CodecTests.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,20 @@ final class CodecTests: BSONTestCase {
4141
let s: NestedStruct
4242
}
4343

44-
/// Test decoding non-document BSON
44+
/// Test encoding and decoding non-document BSON.
4545
func testAnyBSON() throws {
46+
let encoder = BSONEncoder()
4647
let decoder = BSONDecoder()
48+
4749
expect(try decoder.decode(Int32.self, fromBSON: BSON.int32(1))).to(equal(1))
4850
let oid = try BSONObjectID("507f1f77bcf86cd799439011")
4951
expect(try decoder.decode(BSONObjectID.self, fromBSON: BSON.objectID(oid)))
5052
.to(equal(oid))
5153
expect(try decoder.decode(Array.self, fromBSON: [BSON.int32(1), BSON.int32(2)]))
5254
.to(equal([1, 2]))
55+
56+
expect(try encoder.encode(oid)).to(equal(BSON.objectID(oid)))
57+
expect(try encoder.encode([Int32(1), Int32(2)])).to(equal([BSON.int32(1), BSON.int32(2)]))
5358
}
5459

5560
/// Test encoding/decoding a variety of structs containing simple types that have

0 commit comments

Comments
 (0)