|
1 | 1 | import ExtrasBase64
|
| 2 | +import ExtrasJSON |
2 | 3 | import Foundation
|
3 | 4 | import NIO
|
4 | 5 |
|
@@ -146,6 +147,7 @@ public struct BSONBinary: Equatable, Hashable {
|
146 | 147 |
|
147 | 148 | extension BSONBinary: BSONValue {
|
148 | 149 | internal static let extJSONTypeWrapperKeys: [String] = ["$binary", "$uuid"]
|
| 150 | + internal static let extJSONLegacyTypeWrapperKeys: [String] = ["$type"] |
149 | 151 |
|
150 | 152 | /*
|
151 | 153 | * Initializes a `Binary` from ExtendedJSON.
|
@@ -188,38 +190,104 @@ extension BSONBinary: BSONValue {
|
188 | 190 | }
|
189 | 191 | }
|
190 | 192 |
|
191 |
| - // canonical and relaxed extended JSON |
192 |
| - guard let binary = try json.value.unwrapObject(withKey: "$binary", keyPath: keyPath) else { |
| 193 | + guard case let .object(obj) = json.value, let binary = obj["$binary"] else { |
193 | 194 | return nil
|
194 | 195 | }
|
195 |
| - guard |
196 |
| - let (base64, subTypeInput) = try binary.unwrapObject(withKeys: "base64", "subType", keyPath: keyPath) |
197 |
| - else { |
198 |
| - throw Swift.DecodingError._extendedJSONError( |
199 |
| - keyPath: keyPath, |
200 |
| - debugDescription: "Missing \"base64\" or \"subType\" in \(binary)" |
201 |
| - ) |
202 |
| - } |
203 |
| - guard let base64Str = base64.stringValue else { |
204 |
| - throw Swift.DecodingError._extendedJSONError( |
205 |
| - keyPath: keyPath, |
206 |
| - debugDescription: "Could not parse `base64` from \"\(base64)\", " + |
207 |
| - "input must be a base64-encoded (with padding as =) payload as a string" |
208 |
| - ) |
209 |
| - } |
210 |
| - guard |
211 |
| - let subTypeStr = subTypeInput.stringValue, |
212 |
| - let subTypeInt = UInt8(subTypeStr, radix: 16), |
213 |
| - let subType = Subtype(rawValue: subTypeInt) |
214 |
| - else { |
| 196 | + |
| 197 | + let subtype: Subtype |
| 198 | + let base64Str: String |
| 199 | + |
| 200 | + switch binary { |
| 201 | + // extended JSON v2 |
| 202 | + case .object: |
| 203 | + guard obj.count == 1 else { |
| 204 | + throw Swift.DecodingError._extraKeysError( |
| 205 | + keyPath: keyPath, |
| 206 | + expectedKeys: ["$binary"], |
| 207 | + allKeys: Set(obj.keys) |
| 208 | + ) |
| 209 | + } |
| 210 | + guard |
| 211 | + let (base64, subTypeInput) = try binary.unwrapObject(withKeys: "base64", "subType", keyPath: keyPath) |
| 212 | + else { |
| 213 | + throw Swift.DecodingError._extendedJSONError( |
| 214 | + keyPath: keyPath, |
| 215 | + debugDescription: "Missing \"base64\" or \"subType\" in \(binary)" |
| 216 | + ) |
| 217 | + } |
| 218 | + guard let b64Str = base64.stringValue else { |
| 219 | + throw Swift.DecodingError._extendedJSONError( |
| 220 | + keyPath: keyPath, |
| 221 | + debugDescription: "Could not parse `base64` from \"\(base64)\", " + |
| 222 | + "input must be a base64-encoded (with padding as =) payload as a string" |
| 223 | + ) |
| 224 | + } |
| 225 | + |
| 226 | + guard |
| 227 | + let subtypeString = subTypeInput.stringValue, |
| 228 | + let subtypeInt = UInt8(subtypeString, radix: 16), |
| 229 | + let s = Subtype(rawValue: subtypeInt) |
| 230 | + else { |
| 231 | + throw Swift.DecodingError._extendedJSONError( |
| 232 | + keyPath: keyPath, |
| 233 | + debugDescription: "Could not parse `SubType` from \"\(json)\", subtype must" |
| 234 | + + "be a BSON binary type as a one- or two-character hex string" |
| 235 | + ) |
| 236 | + } |
| 237 | + |
| 238 | + base64Str = b64Str |
| 239 | + subtype = s |
| 240 | + case let .string(base64): |
| 241 | + guard obj.count == 2 else { |
| 242 | + throw Swift.DecodingError._extraKeysError( |
| 243 | + keyPath: keyPath, |
| 244 | + expectedKeys: ["$binary"], |
| 245 | + allKeys: Set(obj.keys) |
| 246 | + ) |
| 247 | + } |
| 248 | + |
| 249 | + // extended JSON v1 (legacy) |
| 250 | + guard let subtypeInput = obj["$type"] else { |
| 251 | + throw Swift.DecodingError._extendedJSONError( |
| 252 | + keyPath: keyPath, |
| 253 | + debugDescription: "missing \"$type\" key in BSON binary legacy extended JSON representation" |
| 254 | + ) |
| 255 | + } |
| 256 | + |
| 257 | + let subtypeString: String |
| 258 | + if let str = subtypeInput.stringValue { |
| 259 | + subtypeString = str |
| 260 | + } else if case let .number(n) = subtypeInput { |
| 261 | + subtypeString = n |
| 262 | + } else { |
| 263 | + throw Swift.DecodingError._extendedJSONError( |
| 264 | + keyPath: keyPath, |
| 265 | + debugDescription: "expected \"$type\" to be a string or number, got \(subtypeInput) instead" |
| 266 | + ) |
| 267 | + } |
| 268 | + |
| 269 | + guard |
| 270 | + let subtypeInt = UInt8(subtypeString, radix: 16), |
| 271 | + let s = Subtype(rawValue: subtypeInt) |
| 272 | + else { |
| 273 | + throw Swift.DecodingError._extendedJSONError( |
| 274 | + keyPath: keyPath, |
| 275 | + debugDescription: "Could not parse `SubType` from \"\(json)\", subtype must be a BSON binary" |
| 276 | + + "type as a one-or-two character hex string or a number" |
| 277 | + ) |
| 278 | + } |
| 279 | + |
| 280 | + base64Str = base64 |
| 281 | + subtype = s |
| 282 | + default: |
215 | 283 | throw Swift.DecodingError._extendedJSONError(
|
216 | 284 | keyPath: keyPath,
|
217 |
| - debugDescription: "Could not parse `SubType` from \"\(subTypeInput)\", " + |
218 |
| - "input must be a BSON binary type as a one- or two-character hex string" |
| 285 | + debugDescription: "expected extended JSON object for \"$binary\", got \(binary) instead" |
219 | 286 | )
|
220 | 287 | }
|
| 288 | + |
221 | 289 | do {
|
222 |
| - self = try BSONBinary(base64: base64Str, subtype: subType) |
| 290 | + self = try BSONBinary(base64: base64Str, subtype: subtype) |
223 | 291 | } catch {
|
224 | 292 | throw Swift.DecodingError._extendedJSONError(
|
225 | 293 | keyPath: keyPath,
|
|
0 commit comments