Skip to content

Commit 24de514

Browse files
authored
SWIFT-851 Namespace error types (#491)
1 parent ba1825d commit 24de514

File tree

75 files changed

+945
-899
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+945
-899
lines changed

Guides/BSON.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func foo(x: BSON, y: BSON) throws {
6464
print("got something else")
6565
}
6666
guard case let .double(d) = y else {
67-
throw InvalidArgumentError(message: "y must be a double")
67+
throw MongoError.InvalidArgumentError(message: "y must be a double")
6868
}
6969
print(d * d)
7070
}

Guides/Error-Handling.md

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,55 +15,55 @@
1515
* [See Also](#see-also)
1616

1717
## Error Types
18-
The driver uses errors to communicate that an operation failed, an assumption wasn't met, or that the user did something incorrectly. Applications that use the driver can in turn catch these errors and respond appropriately without crashing or resulting in an otherwise inconsistent state. To correctly model the different sources of errors, the driver defines three separate caregories of errors (`ServerError`, `UserError`, `RuntimeError`), each of which are protocols that inherit from the `MongoError` protocol. These protocols are defined in `MongoError.swift`, and the structs that conform to them are outlined here. The documentation for every public function that throws lists some of the errors that could possibly be thrown and the reasons they might be. The errors listed there are not comprehensive but will generally cover the most common cases.
18+
The driver uses errors to communicate that an operation failed, an assumption wasn't met, or that the user did something incorrectly. Applications that use the driver can in turn catch these errors and respond appropriately without crashing or resulting in an otherwise inconsistent state. To correctly model the different sources of errors, the driver defines three separate caregories of errors (`MongoServerError`, `MongoUserError`, `MongoRuntimeError`), each of which are protocols that inherit from the `MongoErrorProtocol` protocol. These protocols are defined in `MongoError.swift`, and the structs that conform to them are outlined here. The documentation for every public function that throws lists some of the errors that could possibly be thrown and the reasons they might be. The errors listed there are not comprehensive but will generally cover the most common cases.
1919

2020

2121
### Server Errors
2222
Server errors correspond to failures that occur in the database itself and are returned to the driver via some response to a command. Each error that conforms to `ServerError` contains at least one error code representing what went wrong on the server.
2323

2424
For an enumeration of the possible server error codes, [see this list](https://github.com/mongodb/mongo/blob/master/src/mongo/base/error_codes.yml).
2525

26-
The possible errors that conform to `ServerError` are as follows:
27-
- `CommandError`:
26+
The possible errors that conform to `MongoServerError` are as follows:
27+
- `MongoError.CommandError`:
2828
- Thrown when commands experience errors server side that prevent execution.
2929
- Example command failures include failure to parse, operation aborted by the user, and unexpected errors during execution.
30-
- `WriteError`
30+
- `MongoError.WriteError`
3131
- Thrown when a single write command fails on the server (e.g. insertOne, updateOne, updateMany).
32-
- `BulkWriteError`
32+
- `MongoError.BulkWriteError`
3333
- Thrown when the server returns errors as part of an executed bulk write.
3434
- If WriteConcernFailure is populated, writeErrors may not be.
35-
- **Note:** `InsertMany` throws a `BulkWriteError`, _not_ a `WriteError`.
35+
- **Note:** `InsertMany` throws a `MongoError.BulkWriteError`, _not_ a `MongoError.WriteError`.
3636

3737

3838
### User Errors
3939
User applications can sometimes cause errors by using the driver incorrectly (e.g. by passing invalid argument combinations). This category of error covers those cases.
4040

41-
The possible errors that conform to `UserError` are as follows:
42-
- `LogicError`
41+
The possible errors that conform to `MongoUserError` are as follows:
42+
- `MongoError.LogicError`
4343
- Thrown when the user uses the driver incorrectly (e.g. advancing a dead cursor).
44-
- `InvalidArgumentError`
44+
- `MongoError.InvalidArgumentError`
4545
- Thrown when user passes invalid arguments to some driver function.
4646

4747

4848
### Runtime Errors
4949
The driver may experience errors that happen at runtime unexpectedly. These errors don't fit neatly into the categories of occurring only server-side or only as part of the user's fault, so they are represented by their own set of cases.
5050

51-
The `RuntimeError` cases are as follows:
52-
- `InternalError`
51+
The `MongoRuntimeError` cases are as follows:
52+
- `MongoError.InternalError`
5353
- Thrown when something is null when it shouldn't be, the driver has an internal failure, or MongoSwift cannot understand a server response.
5454
- This is generally indicative of a bug somewhere in the driver stack or a system related failure (e.g. a memory allocation failure). If you experience an error that you think is the result of a bug, please file a bug report on GitHub or our Jira project.
55-
- `ConnectionError`
55+
- `MongoError.ConnectionError`
5656
- Thrown during any connection establishment / socket related errors.
5757
- This error also conforms to `LabeledError`.
58-
- `AuthenticationError`
58+
- `MongoError.AuthenticationError`
5959
- Thrown when the driver is not authorized to perform a requested command (e.g. due to invalid credentials)
60-
- `ServerSelectionError`
60+
- `MongoError.ServerSelectionError`
6161
- Thrown when the driver was unable to select a server for an operation (e.g. due to a timeout or unsatisfiable read preference)
6262
- See [the official MongoDB documentation](https://docs.mongodb.com/manual/core/read-preference-mechanics/) for more information.
6363

6464

6565
### Error Labels
66-
Some types of errors may contain more specific information describing the context in which they occured. Such errors conform to the `LabeledError` protocol, and the extra information is conveyed through the `errorLabels` property. Specifically, any server error or connection related error may contain labels.
66+
Some types of errors may contain more specific information describing the context in which they occured. Such errors conform to the `MongoLabeledError` protocol, and the extra information is conveyed through the `errorLabels` property. Specifically, any server error or connection related error may contain labels.
6767

6868
The following error labels are currently defined. Future versions of MongoDB may introduce new labels:
6969
- `TransientTransactionError`:
@@ -73,7 +73,7 @@ The following error labels are currently defined. Future versions of MongoDB may
7373

7474

7575
### Encoding/Decoding Errors
76-
As part of the driver, `BSONEncoder` and `BSONDecoder` are implemented according to the `Encoder` and `Decoder` protocols [defined in Apple's Foundation](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types). User applications can use them to seamlessly convert between their Swift data structures and the BSON documents stored in the database. While this functionality is part of the public API, the driver itself also makes heavy use of it internally. During any encoding or decoding operations, errors can occur that prevent the data from being written to or read from BSON. In these cases, the driver throws an `EncodingError` or `DecodingError` as appropriate. These error types are not unique to MongoSwift and are commonly used by other encoder implementations, such as Foundation's `JSONEncoder`, so they do not conform to the `MongoError` protocol or any of the other error protocols defined in the driver.
76+
As part of the driver, `BSONEncoder` and `BSONDecoder` are implemented according to the `Encoder` and `Decoder` protocols [defined in Apple's Foundation](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types). User applications can use them to seamlessly convert between their Swift data structures and the BSON documents stored in the database. While this functionality is part of the public API, the driver itself also makes heavy use of it internally. During any encoding or decoding operations, errors can occur that prevent the data from being written to or read from BSON. In these cases, the driver throws an `EncodingError` or `DecodingError` as appropriate. These error types are not unique to MongoSwift and are commonly used by other encoder implementations, such as Foundation's `JSONEncoder`, so they do not conform to the `MongoErrorProtocol` protocol or any of the other error protocols defined in the driver.
7777

7878
See the official documentation for both [`EncodingErrors`](https://developer.apple.com/documentation/swift/encodingerror) and [`DecodingErrors`](https://developer.apple.com/documentation/swift/decodingerror) for more information.
7979

@@ -83,14 +83,14 @@ See the official documentation for both [`EncodingErrors`](https://developer.app
8383
```swift
8484
do {
8585
// something involving the driver
86-
} catch let error as MongoError {
86+
} catch let error as MongoErrorProtocol {
8787
print("Driver error!")
8888
switch error.self {
89-
case let runtimeError as RuntimeError:
89+
case let runtimeError as MongoRuntimeError:
9090
// handle RuntimeError
91-
case let serverError as ServerError:
91+
case let serverError as MongoServerError:
9292
// handle ServerError
93-
case let userError as UserError:
93+
case let userError as MongoUserError:
9494
// handle UserError
9595
default:
9696
// should never get here
@@ -106,7 +106,7 @@ do {
106106
```swift
107107
do {
108108
try db.runCommand(["asdfasdf": "sadfsadfasdf"])
109-
} catch let commandError as CommandError {
109+
} catch let commandError as MongoError.CommandError {
110110
print("Command failed: code: \(commandError.code) message: \(commandError.message)")
111111
} catch { ... }
112112
```
@@ -121,7 +121,7 @@ Command failed: code: 59 message: no such command: 'asdfasdf'
121121
do {
122122
try coll.insertOne(["_id": 1])
123123
try coll.insertOne(["_id": 1])
124-
} catch let writeError as WriteError where writeError.writeFailure?.code == 11000 {
124+
} catch let writeError as MongoError.WriteError where writeError.writeFailure?.code == 11000 {
125125
print("duplicate key error: \(1) \(writeError.writeFailure?.message ?? "")")
126126
}
127127
```
@@ -136,7 +136,7 @@ let docs: [Document] = [["_id": 2], ["_id": 1]]
136136
do {
137137
try coll.insertOne(["_id": 1])
138138
try coll.insertMany(docs)
139-
} catch let bwe as BulkWriteError {
139+
} catch let bwe as MongoError.BulkWriteError {
140140
if let writeErrors = bwe.writeFailures {
141141
writeErrors.forEach { err in print("Write Error inserting \(docs[err.index]), code: \(err.code), message: \(err.message)") }
142142
}

Sources/MongoSwift/APM.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,8 @@ public struct CommandFailedEvent: MongoSwiftEvent, CommandEventProtocol {
222222
/// The command name.
223223
public let commandName: String
224224

225-
/// The failure, represented as a MongoError.
226-
public let failure: MongoError
225+
/// The failure, represented as a MongoErrorProtocol.
226+
public let failure: MongoErrorProtocol
227227

228228
/// The client generated request id.
229229
public let requestID: Int64
@@ -588,7 +588,7 @@ public struct ServerHeartbeatFailedEvent: MongoSwiftEvent {
588588
public let duration: Int
589589

590590
/// The failure.
591-
public let failure: MongoError
591+
public let failure: MongoErrorProtocol
592592

593593
/// The address of the server.
594594
public let serverAddress: ServerAddress

Sources/MongoSwift/BSON/BSONDecoder.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,12 @@ extension _BSONDecoder {
360360
case .binary:
361361
let binary = try self.unboxCustom(value) { $0.binaryValue }
362362
guard let data = binary.data.getBytes(at: 0, length: binary.data.writerIndex) else {
363-
throw InternalError(message: "Cannot read \(binary.data.writerIndex) bytes from Binary.data")
363+
throw DecodingError.dataCorrupted(
364+
DecodingError.Context(
365+
codingPath: self.codingPath,
366+
debugDescription: "Cannot read \(binary.data.writerIndex) bytes from Binary.data"
367+
)
368+
)
364369
}
365370
return Data(data)
366371
case .base64:

Sources/MongoSwift/BSON/BSONDocument.swift

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ internal typealias MutableBSONPointer = UnsafeMutablePointer<bson_t>
99
public struct BSONDocument {
1010
/// Error thrown when BSON buffer is too small.
1111
internal static let BSONBufferTooSmallError =
12-
InternalError(message: "BSON buffer is unexpectedly too small (< 5 bytes)")
12+
MongoError.InternalError(message: "BSON buffer is unexpectedly too small (< 5 bytes)")
1313

1414
/// The storage backing a `BSONDocument`.
1515
private class Storage {
@@ -145,10 +145,10 @@ extension BSONDocument {
145145
* presence first.
146146
*
147147
* - Throws:
148-
* - `InternalError` if the new value is an `Int` and cannot be written to BSON.
149-
* - `LogicError` if the new value is a `BSONDecimal128` or `BSONObjectID` and is improperly formatted.
150-
* - `LogicError` if the new value is an `Array` and it contains a non-`BSONValue` element.
151-
* - `InternalError` if the underlying `bson_t` would exceed the maximum size by encoding this
148+
* - `MongoError.InternalError` if the new value is an `Int` and cannot be written to BSON.
149+
* - `MongoError.LogicError` if the new value is a `BSONDecimal128` or `BSONObjectID` and is improperly formatted.
150+
* - `MongoError.LogicError` if the new value is an `Array` and it contains a non-`BSONValue` element.
151+
* - `MongoError.InternalError` if the underlying `bson_t` would exceed the maximum size by encoding this
152152
* key-value pair.
153153
*/
154154
internal mutating func setValue(for key: String, to newValue: BSON, checkForKey: Bool = true) throws {
@@ -210,7 +210,7 @@ extension BSONDocument {
210210
/// Retrieves the value associated with `for` as a `BSON?`, which can be nil if the key does not exist in the
211211
/// `BSONDocument`.
212212
///
213-
/// - Throws: `InternalError` if the BSON buffer is too small (< 5 bytes).
213+
/// - Throws: `MongoError.InternalError` if the BSON buffer is too small (< 5 bytes).
214214
internal func getValue(for key: String) throws -> BSON? {
215215
guard let iter = BSONDocumentIterator(over: self) else {
216216
throw BSONDocument.BSONBufferTooSmallError
@@ -232,7 +232,7 @@ extension BSONDocument {
232232
}
233233
}
234234
guard success else {
235-
throw InternalError(
235+
throw MongoError.InternalError(
236236
message: "Failed to merge \(doc) with \(self). This is likely due to " +
237237
"the merged document being too large."
238238
)
@@ -255,15 +255,15 @@ extension BSONDocument {
255255
/// excluding a non-zero number of keys
256256
internal func copyElements(to otherDoc: inout BSONDocument, excluding keys: [String]) throws {
257257
guard !keys.isEmpty else {
258-
throw InternalError(message: "No keys to exclude, use 'bson_copy' instead")
258+
throw MongoError.InternalError(message: "No keys to exclude, use 'bson_copy' instead")
259259
}
260260

261261
let cStrings: [ContiguousArray<CChar>] = keys.map { $0.utf8CString }
262262

263263
var cPtrs: [UnsafePointer<CChar>] = try cStrings.map { cString in
264264
let bufferPtr: UnsafeBufferPointer<CChar> = cString.withUnsafeBufferPointer { $0 }
265265
guard let cPtr = bufferPtr.baseAddress else {
266-
throw InternalError(message: "Failed to copy strings")
266+
throw MongoError.InternalError(message: "Failed to copy strings")
267267
}
268268
return cPtr
269269
}
@@ -373,16 +373,16 @@ extension BSONDocument {
373373
* - Returns: the parsed `BSONDocument`
374374
*
375375
* - Throws:
376-
* - A `InvalidArgumentError` if the data passed in is invalid JSON.
376+
* - A `MongoError.InvalidArgumentError` if the data passed in is invalid JSON.
377377
*/
378378
public init(fromJSON: Data) throws {
379379
self._storage = Storage(stealing: try fromJSON.withUnsafeBytePointer { bytes in
380380
var error = bson_error_t()
381381
guard let bson = bson_new_from_json(bytes, fromJSON.count, &error) else {
382382
if error.domain == BSON_ERROR_JSON {
383-
throw InvalidArgumentError(message: "Invalid JSON: \(toErrorString(error))")
383+
throw MongoError.InvalidArgumentError(message: "Invalid JSON: \(toErrorString(error))")
384384
}
385-
throw InternalError(message: toErrorString(error))
385+
throw MongoError.InternalError(message: toErrorString(error))
386386
}
387387

388388
return bson
@@ -391,7 +391,7 @@ extension BSONDocument {
391391

392392
/// Convenience initializer for constructing a `BSONDocument` from a `String`.
393393
/// - Throws:
394-
/// - A `InvalidArgumentError` if the string passed in is invalid JSON.
394+
/// - A `MongoError.InvalidArgumentError` if the string passed in is invalid JSON.
395395
public init(fromJSON json: String) throws {
396396
// `String`s are Unicode under the hood so force unwrap always succeeds.
397397
// see https://www.objc.io/blog/2018/02/13/string-to-data-and-back/
@@ -401,15 +401,15 @@ extension BSONDocument {
401401
/**
402402
* Constructs a `BSONDocument` from raw BSON `Data`.
403403
* - Throws:
404-
* - A `InvalidArgumentError` if `bson` is too short or too long to be valid BSON.
405-
* - A `InvalidArgumentError` if the first four bytes of `bson` do not contain `bson.count`.
406-
* - A `InvalidArgumentError` if the final byte of `bson` is not a null byte.
404+
* - A `MongoError.InvalidArgumentError` if `bson` is too short or too long to be valid BSON.
405+
* - A `MongoError.InvalidArgumentError` if the first four bytes of `bson` do not contain `bson.count`.
406+
* - A `MongoError.InvalidArgumentError` if the final byte of `bson` is not a null byte.
407407
* - SeeAlso: http://bsonspec.org/
408408
*/
409409
public init(fromBSON bson: Data) throws {
410410
self._storage = Storage(stealing: try bson.withUnsafeBytePointer { bytes in
411411
guard let data = bson_new_from_data(bytes, bson.count) else {
412-
throw InvalidArgumentError(message: "Invalid BSON data")
412+
throw MongoError.InvalidArgumentError(message: "Invalid BSON data")
413413
}
414414
return data
415415
})
@@ -520,7 +520,7 @@ extension BSONDocument: BSONValue {
520520
bson_iter_document(iterPtr, &length, document)
521521

522522
guard let docData = bson_new_from_data(document.pointee, Int(length)) else {
523-
throw InternalError(message: "Failed to create a Document from iterator")
523+
throw MongoError.InternalError(message: "Failed to create a Document from iterator")
524524
}
525525

526526
return self.init(stealing: docData)

Sources/MongoSwift/BSON/BSONDocumentIterator.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,10 @@ public class BSONDocumentIterator: IteratorProtocol {
102102
/// Returns the current value (equivalent to the `currentValue` property) or throws on error.
103103
///
104104
/// - Throws:
105-
/// - `InternalError` if the current value of this `BSONDocumentIterator` cannot be decoded to BSON.
105+
/// - `MongoError.InternalError` if the current value of this `BSONDocumentIterator` cannot be decoded to BSON.
106106
internal func safeCurrentValue() throws -> BSON {
107107
guard let bsonType = BSONDocumentIterator.bsonTypeMap[currentType] else {
108-
throw InternalError(
108+
throw MongoError.InternalError(
109109
message: "Unknown BSONType for iterator's current value with type: \(self.currentType)"
110110
)
111111
}
@@ -177,8 +177,8 @@ public class BSONDocumentIterator: IteratorProtocol {
177177
* Overwrites the current value of this `BSONDocumentIterator` with the supplied value.
178178
*
179179
* - Throws:
180-
* - `InternalError` if the new value is an `Int` and cannot be written to BSON.
181-
* - `LogicError` if the new value is a `BSONDecimal128` or `BSONObjectID` and is improperly formatted.
180+
* - `MongoError.InternalError` if the new value is an `Int` and cannot be written to BSON.
181+
* - `MongoError.LogicError` if the new value is a `BSONDecimal128` or `BSONObjectID` and is improperly formatted.
182182
*/
183183
internal func overwriteCurrentValue(with newValue: Overwritable) throws {
184184
let newValueType = type(of: newValue).bsonType

0 commit comments

Comments
 (0)