Skip to content

Commit ccec1c2

Browse files
authored
Merge pull request #8 from Outdooractive/5_pool_errors
#5: More tests, added 'closeIdleConnections()', added a description to PoolInfo
2 parents 20efbf7 + 2be276f commit ccec1c2

14 files changed

+388
-112
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ This package requires Swift 5.7 or higher (at least Xcode 13), and compiles on m
1313

1414
```swift
1515
dependencies: [
16-
.package(url: "https://github.com/Outdooractive/PostgresConnectionPool.git", from: "0.5.5"),
16+
.package(url: "https://github.com/Outdooractive/PostgresConnectionPool.git", from: "0.6.1"),
1717
],
1818
targets: [
1919
.target(name: "MyTarget", dependencies: [

Sources/PostgresConnectionPool/Extensions/DoubleExtensions.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Foundation
66

77
extension Double {
88

9+
/// Returns the maximum of `self` and the other value.
910
func atLeast(_ minValue: Double) -> Double {
1011
Swift.max(minValue, self)
1112
}

Sources/PostgresConnectionPool/Extensions/EmptyTestable.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import Foundation
1010
protocol EmptyTestable {
1111

1212
var isEmpty: Bool { get }
13+
14+
/// A Boolean value indicating whether the collection is **not** empty.
1315
var isNotEmpty: Bool { get }
1416

1517
}

Sources/PostgresConnectionPool/Extensions/FloatingPointExtensions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import Foundation
77

88
extension FloatingPoint {
99

10-
/// Returns rounded FloatingPoint to specified number of places
10+
/// Returns rounded FloatingPoint to specified number of places.
1111
func rounded(toPlaces places: Int) -> Self {
1212
guard places >= 0 else { return self }
1313
var divisor: Self = 1
1414
for _ in 0..<places { divisor *= 10 }
1515
return (self * divisor).rounded() / divisor
1616
}
1717

18-
/// Rounds current FloatingPoint to specified number of places
18+
/// Rounds current FloatingPoint to specified number of places.
1919
mutating func round(toPlaces places: Int) {
2020
self = rounded(toPlaces: places)
2121
}

Sources/PostgresConnectionPool/Extensions/IntExtensions.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Foundation
66

77
extension Int {
88

9+
/// Returns the maximum of `self` and the other value.
910
func atLeast(_ minValue: Int) -> Int {
1011
Swift.max(minValue, self)
1112
}

Sources/PostgresConnectionPool/Extensions/PSQLError+Description.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import PostgresNIO
99

1010
extension PSQLError: CustomStringConvertible {
1111

12+
/// A short error description.
1213
public var description: String {
1314
if let serverInfo = self.serverInfo,
1415
let severity = serverInfo[.severity],
@@ -26,12 +27,14 @@ extension PSQLError: CustomStringConvertible {
2627

2728
extension PSQLError: CustomDebugStringConvertible {
2829

30+
/// A detailed error description suitable for debugging queries and other problems with the server.
2931
public var debugDescription: String {
3032
var messageElements: [String] = [
3133
"code: \(self.code)"
3234
]
3335

3436
if let serverInfo = self.serverInfo {
37+
// Field -> display name
3538
let fields: OrderedDictionary<PSQLError.ServerInfo.Field, String> = [
3639
.severity: "severity",
3740
.message: "message",
@@ -48,9 +51,9 @@ extension PSQLError: CustomDebugStringConvertible {
4851
.sqlState: "sqlState",
4952
]
5053

51-
let serverInfoELements = fields.compactMap({ field -> String? in
52-
guard let value = serverInfo[field.0] else { return nil }
53-
return "\(field.1): \(value)"
54+
let serverInfoELements = fields.compactMap({ fieldAndName -> String? in
55+
guard let value = serverInfo[fieldAndName.0] else { return nil }
56+
return "\(fieldAndName.1): \(value)"
5457
})
5558

5659
messageElements.append("serverInfo: [\(serverInfoELements.joined(separator: ", "))]")

Sources/PostgresConnectionPool/Extensions/StringExtensions.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Foundation
88

99
extension String {
1010

11+
/// A Boolean value indicating whether the string matches a regular expression.
1112
func matches(
1213
_ regexp: String,
1314
caseInsensitive: Bool = false)
@@ -19,6 +20,7 @@ extension String {
1920
return self.range(of: regexp, options: options) != nil
2021
}
2122

23+
/// Returns a new string with the matches of the regular expression replaced with some other string.
2224
func replacingPattern(
2325
_ regexp: String,
2426
with replacement: String,

Sources/PostgresConnectionPool/Extensions/TaskExtensions.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Foundation
66

77
extension Task where Failure == Error {
88

9+
/// Perform a task after some time.
910
@discardableResult
1011
static func after(
1112
seconds: TimeInterval,

Sources/PostgresConnectionPool/PoolError.swift

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ public enum PoolError: Error {
1212
case cancelled
1313
/// The connection to the database was unexpectedly closed.
1414
case connectionFailed
15-
/// The pool was already shut down.
16-
case poolDestroyed
15+
/// The pool was already shut down. Includes the original `PSQLError`
16+
/// if the pool was shutdown due to a permanent server error.
17+
case poolDestroyed(PSQLError?)
1718
/// Some PostgreSQL error.
1819
case postgresError(PSQLError)
1920
/// The query was cancelled by the server.
@@ -27,14 +28,31 @@ public enum PoolError: Error {
2728

2829
extension PoolError: CustomStringConvertible {
2930

31+
/// A short error description.
3032
public var description: String {
3133
switch self {
32-
case .cancelled: return "<PoolError: cancelled>"
33-
case .connectionFailed: return "<PoolError: connectionFailed>"
34-
case .poolDestroyed: return "<PoolError: poolDestroyed>"
35-
case .postgresError(let psqlError): return "<PoolError: postgresError=\(psqlError.description)>"
36-
case .queryCancelled: return "<PoolError: queryCancelled>"
37-
case .unknown: return "<PoolError: unknown>"
34+
case .cancelled:
35+
return "<PoolError: cancelled>"
36+
37+
case .connectionFailed:
38+
return "<PoolError: connectionFailed>"
39+
40+
case .poolDestroyed(let psqlError):
41+
if let psqlError {
42+
return "<PoolError: poolDestroyed=\(psqlError.description)>"
43+
}
44+
else {
45+
return "<PoolError: poolDestroyed>"
46+
}
47+
48+
case .postgresError(let psqlError):
49+
return "<PoolError: postgresError=\(psqlError.description)>"
50+
51+
case .queryCancelled:
52+
return "<PoolError: queryCancelled>"
53+
54+
case .unknown:
55+
return "<PoolError: unknown>"
3856
}
3957
}
4058

@@ -44,14 +62,31 @@ extension PoolError: CustomStringConvertible {
4462

4563
extension PoolError: CustomDebugStringConvertible {
4664

65+
/// A detailed error description suitable for debugging queries and other problems with the server.
4766
public var debugDescription: String {
4867
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)>"
53-
case .queryCancelled(query: let query, runtime: let runtime): return "<PoolError: query '\(query)' cancelled after \(runtime.rounded(toPlaces: 3))s>"
54-
case .unknown: return "<PoolError: unknown>"
68+
case .cancelled:
69+
return "<PoolError: cancelled>"
70+
71+
case .connectionFailed:
72+
return "<PoolError: connectionFailed>"
73+
74+
case .poolDestroyed(let psqlError):
75+
if let psqlError {
76+
return "<PoolError: poolDestroyed=\(psqlError.debugDescription)>"
77+
}
78+
else {
79+
return "<PoolError: poolDestroyed>"
80+
}
81+
82+
case .postgresError(let psqlError):
83+
return "<PoolError: postgresError=\(psqlError.debugDescription)>"
84+
85+
case .queryCancelled(query: let query, runtime: let runtime):
86+
return "<PoolError: query '\(query)' cancelled after \(runtime.rounded(toPlaces: 3))s>"
87+
88+
case .unknown:
89+
return "<PoolError: unknown>"
5590
}
5691
}
5792

Sources/PostgresConnectionPool/PoolInfo.swift

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//
44

55
import Foundation
6+
import PostgresNIO
67

78
/// General information about the pool and its open connections.
89
public struct PoolInfo {
@@ -37,4 +38,56 @@ public struct PoolInfo {
3738
/// Information about individual open connections to the server.
3839
public let connections: [ConnectionInfo]
3940

41+
42+
/// Whether the pool is accepting connections or was shutdown.
43+
public let isShutdown: Bool
44+
/// The Postgres error If the pool was shutdown forcibly.
45+
public let shutdownError: PSQLError?
46+
47+
}
48+
49+
// MARK: - CustomStringConvertible
50+
51+
extension PoolInfo: CustomStringConvertible {
52+
53+
public var description: String {
54+
var lines: [String] = [
55+
"Pool: \(name)",
56+
"Connections: \(openConnections)/\(activeConnections)/\(availableConnections) (open/active/available)",
57+
"Usage: \(usageCounter)",
58+
"Shutdown? \(isShutdown) \(shutdownError != nil ? "(\(shutdownError!.description))" : "")",
59+
]
60+
61+
if connections.isNotEmpty {
62+
lines.append("Connections:")
63+
64+
for connection in connections.sorted(by: { $0.id < $1.id }) {
65+
lines.append(contentsOf: connection.description.components(separatedBy: "\n").map({ " " + $0 }))
66+
}
67+
}
68+
69+
return lines.joined(separator: "\n")
70+
}
71+
72+
}
73+
74+
extension PoolInfo.ConnectionInfo: CustomStringConvertible {
75+
76+
public var description: String {
77+
var lines: [String] = [
78+
"Connection: \(id) (\(name))",
79+
" State: \(state)",
80+
" Usage: \(usageCounter)",
81+
]
82+
83+
if let query {
84+
lines.append(" Query: \(query)")
85+
if let queryRuntime {
86+
lines.append(" Runtime: \(queryRuntime.rounded(toPlaces: 3))s")
87+
}
88+
}
89+
90+
return lines.joined(separator: "\n")
91+
}
92+
4093
}

0 commit comments

Comments
 (0)