Skip to content

Commit 7e7cb1a

Browse files
committed
Better error descriptions
1 parent e326808 commit 7e7cb1a

File tree

3 files changed

+94
-8
lines changed

3 files changed

+94
-8
lines changed

Sources/PostgresConnectionPool/Extensions/PSQLError+Description.swift

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,85 @@
22
// Created by Thomas Rasch on 05.05.23.
33
//
44

5+
import OrderedCollections
56
import PostgresNIO
67

8+
// MARK: CustomStringConvertible
9+
710
extension PSQLError: CustomStringConvertible {
811

912
public var description: String {
1013
if let serverInfo = self.serverInfo,
1114
let severity = serverInfo[.severity],
1215
let message = serverInfo[.message]
1316
{
14-
return "\(severity): \(message)"
17+
return "<PSQLError: \(severity): \(message)>"
18+
}
19+
20+
return "<PSQLError: \(self.code.description)>"
21+
}
22+
23+
}
24+
25+
// MARK: - CustomDebugStringConvertible
26+
27+
extension PSQLError: CustomDebugStringConvertible {
28+
29+
public var debugDescription: String {
30+
var messageElements: [String] = [
31+
"code: \(self.code)"
32+
]
33+
34+
if let serverInfo = self.serverInfo {
35+
let fields: OrderedDictionary<PSQLError.ServerInfo.Field, String> = [
36+
.severity: "severity",
37+
.message: "message",
38+
.hint: "hint",
39+
.detail: "detail",
40+
.schemaName: "schemaName",
41+
.tableName: "tableName",
42+
.columnName: "columnName",
43+
.dataTypeName: "dataTypeName",
44+
.constraintName: "constraintName",
45+
.internalQuery: "internalQuery",
46+
.position: "position",
47+
.locationContext: "locationContext",
48+
.sqlState: "sqlState",
49+
]
50+
51+
let serverInfoELements = fields.compactMap({ field -> String? in
52+
guard let value = serverInfo[field.0] else { return nil }
53+
return "\(field.1): \(value)"
54+
})
55+
56+
messageElements.append("serverInfo: [\(serverInfoELements.joined(separator: ", "))]")
57+
}
58+
59+
// Not accessible
60+
// if let backendMessage = self.backendMessage {
61+
// messageElements.append("backendMessage: \(backendMessage)")
62+
// }
63+
//
64+
// if let unsupportedAuthScheme = self.unsupportedAuthScheme {
65+
// messageElements.append("unsupportedAuthScheme: \(unsupportedAuthScheme)")
66+
// }
67+
//
68+
// if let invalidCommandTag = self.invalidCommandTag {
69+
// messageElements.append("invalidCommandTag: \(invalidCommandTag)")
70+
// }
71+
72+
if let underlying = self.underlying {
73+
messageElements.append("underlying: \(String(reflecting: underlying))")
1574
}
1675

17-
return "Database error: \(self.code.description)"
76+
if let file = self.file {
77+
messageElements.append("triggeredFromRequestInFile: \(file)\(self.line.flatMap({ "#\($0)" }) ?? "" )")
78+
}
79+
80+
if let query = self.query {
81+
messageElements.append("query: \(query)")
82+
}
83+
return "<PSQLError: \(messageElements.joined(separator: ", "))>"
1884
}
1985

2086
}

Sources/PostgresConnectionPool/PoolError.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,33 @@ public enum PoolError: Error {
2323

2424
}
2525

26+
// MARK: - CustomStringConvertible
27+
2628
extension PoolError: CustomStringConvertible {
2729

2830
public var description: String {
2931
switch self {
3032
case .cancelled: return "<PoolError: cancelled>"
3133
case .connectionFailed: return "<PoolError: connectionFailed>"
3234
case .poolDestroyed: return "<PoolError: poolDestroyed>"
33-
case .postgresError(let psqlError): return "<PoolError: postgresError='\(psqlError.description)'>"
35+
case .postgresError(let psqlError): return "<PoolError: postgresError=\(psqlError.description)>"
36+
case .queryCancelled: return "<PoolError: queryCancelled>"
37+
case .unknown: return "<PoolError: unknown>"
38+
}
39+
}
40+
41+
}
42+
43+
// MARK: - CustomDebugStringConvertible
44+
45+
extension PoolError: CustomDebugStringConvertible {
46+
47+
public var debugDescription: String {
48+
switch self {
49+
case .cancelled: return "<PoolError: cancelled>"
50+
case .connectionFailed: return "<PoolError: connectionFailed>"
51+
case .poolDestroyed: return "<PoolError: poolDestroyed>"
52+
case .postgresError(let psqlError): return "<PoolError: postgresError=\(psqlError.debugDescription)>"
3453
case .queryCancelled(query: let query, runtime: let runtime): return "<PoolError: query '\(query)' cancelled after \(runtime.rounded(toPlaces: 3))s>"
3554
case .unknown: return "<PoolError: unknown>"
3655
}

Tests/PostgresConnectionPoolTests/ConnectionErrorTests.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ final class ConnectionErrorTests: XCTestCase {
1515
}()
1616

1717
// TODO: Clean up the error checking
18+
// TODO: Check that the Docker PostgreSQL server is actually up and available first or most tests will fail anyway
1819

1920
private func withConfiguration(
2021
_ configuration: PoolConfiguration,
@@ -41,27 +42,27 @@ final class ConnectionErrorTests: XCTestCase {
4142
}
4243

4344
func testConnectWrongHost() async throws {
44-
try await withConfiguration(self.poolConfiguration(host: "notworking"), expectedErrorDescription: "<PoolError: postgresError='Database error: connectionError'>")
45+
try await withConfiguration(self.poolConfiguration(host: "notworking"), expectedErrorDescription: "<PoolError: postgresError=<PSQLError: connectionError>>")
4546
}
4647

4748
func testConnectWrongPort() async throws {
48-
try await withConfiguration(self.poolConfiguration(port: 99999), expectedErrorDescription: "<PoolError: postgresError='Database error: connectionError'>")
49+
try await withConfiguration(self.poolConfiguration(port: 99999), expectedErrorDescription: "<PoolError: postgresError=<PSQLError: connectionError>>")
4950
}
5051

5152
func testConnectWrongUsername() async throws {
52-
try await withConfiguration(self.poolConfiguration(username: "notworking"), expectedErrorDescription: "<PoolError: postgresError='FATAL: password authentication failed for user \"notworking\"'>")
53+
try await withConfiguration(self.poolConfiguration(username: "notworking"), expectedErrorDescription: "<PoolError: postgresError=<PSQLError: FATAL: password authentication failed for user \"notworking\">>")
5354
}
5455

5556
func testConnectWrongPassword() async throws {
56-
try await withConfiguration(self.poolConfiguration(password: "notworking"), expectedErrorDescription: "<PoolError: postgresError='FATAL: password authentication failed for user \"test_username\"'>")
57+
try await withConfiguration(self.poolConfiguration(password: "notworking"), expectedErrorDescription: "<PoolError: postgresError=<PSQLError: FATAL: password authentication failed for user \"test_username\">>")
5758
}
5859

5960
func testConnectInvalidTLSConfig() async throws {
6061
var tlsConfiguration: TLSConfiguration = .clientDefault
6162
tlsConfiguration.maximumTLSVersion = .tlsv1 // New Postgres versions want at least TLSv1.2
6263

6364
let tls: PostgresConnection.Configuration.TLS = .require(try .init(configuration: tlsConfiguration))
64-
try await withConfiguration(self.poolConfiguration(tls: tls), expectedErrorDescription: "<PoolError: postgresError='Database error: sslUnsupported'>")
65+
try await withConfiguration(self.poolConfiguration(tls: tls), expectedErrorDescription: "<PoolError: postgresError=<PSQLError: sslUnsupported>>")
6566
}
6667

6768
// MARK: -

0 commit comments

Comments
 (0)