From c0eef0592d89637a163416a17b438c61eacce3ed Mon Sep 17 00:00:00 2001 From: Fabian Fett Date: Wed, 17 Sep 2025 11:49:25 +0200 Subject: [PATCH 1/7] Drop Swift 5.10 --- .github/workflows/test.yml | 5 +- Package.swift | 2 +- .../Connection/PostgresConnection.swift | 57 +------------------ .../PostgresNIO/New/VariadicGenerics.swift | 12 ++-- Sources/PostgresNIO/Pool/PostgresClient.swift | 39 ++----------- 5 files changed, 17 insertions(+), 98 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1eaf9a87..c96bf57a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,10 +18,9 @@ jobs: fail-fast: false matrix: swift-image: - - swift:5.10-jammy - - swift:6.0-noble + - swift:6.0-jammy - swift:6.1-noble - - swiftlang/swift:nightly-6.2-noble + - swift:6.2-noble - swiftlang/swift:nightly-main-noble container: ${{ matrix.swift-image }} runs-on: ubuntu-latest diff --git a/Package.swift b/Package.swift index af2d07ae..0d726e39 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.10 +// swift-tools-version:6.0 import PackageDescription let swiftSettings: [SwiftSetting] = [ diff --git a/Sources/PostgresNIO/Connection/PostgresConnection.swift b/Sources/PostgresNIO/Connection/PostgresConnection.swift index e267d8f9..fc48fa31 100644 --- a/Sources/PostgresNIO/Connection/PostgresConnection.swift +++ b/Sources/PostgresNIO/Connection/PostgresConnection.swift @@ -531,7 +531,6 @@ extension PostgresConnection { } } - #if compiler(>=6.0) /// Puts the connection into an open transaction state, for the provided `closure`'s lifetime. /// /// The function starts a transaction by running a `BEGIN` query on the connection against the database. It then @@ -552,9 +551,8 @@ extension PostgresConnection { file: String = #file, line: Int = #line, isolation: isolated (any Actor)? = #isolation, - // DO NOT FIX THE WHITESPACE IN THE NEXT LINE UNTIL 5.10 IS UNSUPPORTED - // https://github.com/swiftlang/swift/issues/79285 - _ process: (PostgresConnection) async throws -> sending Result) async throws -> sending Result { + _ process: (PostgresConnection) async throws -> sending Result + ) async throws -> sending Result { do { try await self.query("BEGIN;", logger: logger) } catch { @@ -583,57 +581,6 @@ extension PostgresConnection { throw transactionError } } - #else - /// Puts the connection into an open transaction state, for the provided `closure`'s lifetime. - /// - /// The function starts a transaction by running a `BEGIN` query on the connection against the database. It then - /// lends the connection to the user provided closure. The user can then modify the database as they wish. If the user - /// provided closure returns successfully, the function will attempt to commit the changes by running a `COMMIT` - /// query against the database. If the user provided closure throws an error, the function will attempt to rollback the - /// changes made within the closure. - /// - /// - Parameters: - /// - logger: The `Logger` to log into for the transaction. - /// - file: The file, the transaction was started in. Used for better error reporting. - /// - line: The line, the transaction was started in. Used for better error reporting. - /// - closure: The user provided code to modify the database. Use the provided connection to run queries. - /// The connection must stay in the transaction mode. Otherwise this method will throw! - /// - Returns: The closure's return value. - public func withTransaction( - logger: Logger, - file: String = #file, - line: Int = #line, - _ process: (PostgresConnection) async throws -> Result - ) async throws -> Result { - do { - try await self.query("BEGIN;", logger: logger) - } catch { - throw PostgresTransactionError(file: file, line: line, beginError: error) - } - - var closureHasFinished: Bool = false - do { - let value = try await process(self) - closureHasFinished = true - try await self.query("COMMIT;", logger: logger) - return value - } catch { - var transactionError = PostgresTransactionError(file: file, line: line) - if !closureHasFinished { - transactionError.closureError = error - do { - try await self.query("ROLLBACK;", logger: logger) - } catch { - transactionError.rollbackError = error - } - } else { - transactionError.commitError = error - } - - throw transactionError - } - } - #endif } // MARK: EventLoopFuture interface diff --git a/Sources/PostgresNIO/New/VariadicGenerics.swift b/Sources/PostgresNIO/New/VariadicGenerics.swift index 7931c90c..b284c7a2 100644 --- a/Sources/PostgresNIO/New/VariadicGenerics.swift +++ b/Sources/PostgresNIO/New/VariadicGenerics.swift @@ -116,7 +116,8 @@ extension PostgresRow { extension AsyncSequence where Element == PostgresRow { // --- snip TODO: Remove once bug is fixed, that disallows tuples of one @inlinable - public func decode( + @preconcurrency + public func decode( _: Column.Type, context: PostgresDecodingContext, file: String = #fileID, @@ -128,7 +129,8 @@ extension AsyncSequence where Element == PostgresRow { } @inlinable - public func decode( + @preconcurrency + public func decode( _: Column.Type, file: String = #fileID, line: Int = #line @@ -137,7 +139,8 @@ extension AsyncSequence where Element == PostgresRow { } // --- snap TODO: Remove once bug is fixed, that disallows tuples of one - public func decode( + @preconcurrency + public func decode( _ columnType: (repeat each Column).Type, context: PostgresDecodingContext, file: String = #fileID, @@ -148,7 +151,8 @@ extension AsyncSequence where Element == PostgresRow { } } - public func decode( + @preconcurrency + public func decode( _ columnType: (repeat each Column).Type, file: String = #fileID, line: Int = #line diff --git a/Sources/PostgresNIO/Pool/PostgresClient.swift b/Sources/PostgresNIO/Pool/PostgresClient.swift index 0279be07..15b3a7b8 100644 --- a/Sources/PostgresNIO/Pool/PostgresClient.swift +++ b/Sources/PostgresNIO/Pool/PostgresClient.swift @@ -308,7 +308,6 @@ public final class PostgresClient: Sendable, ServiceLifecycle.Service { return try await closure(lease.connection) } - #if compiler(>=6.0) /// Lease a connection for the provided `closure`'s lifetime. /// /// - Parameter closure: A closure that uses the passed `PostgresConnection`. The closure **must not** capture @@ -316,9 +315,8 @@ public final class PostgresClient: Sendable, ServiceLifecycle.Service { /// - Returns: The closure's return value. public func withConnection( isolation: isolated (any Actor)? = #isolation, - // DO NOT FIX THE WHITESPACE IN THE NEXT LINE UNTIL 5.10 IS UNSUPPORTED - // https://github.com/swiftlang/swift/issues/79285 - _ closure: (PostgresConnection) async throws -> sending Result) async throws -> sending Result { + _ closure: (PostgresConnection) async throws -> sending Result + ) async throws -> sending Result { let lease = try await self.leaseConnection() defer { lease.release() } @@ -346,41 +344,12 @@ public final class PostgresClient: Sendable, ServiceLifecycle.Service { file: String = #file, line: Int = #line, isolation: isolated (any Actor)? = #isolation, - // DO NOT FIX THE WHITESPACE IN THE NEXT LINE UNTIL 5.10 IS UNSUPPORTED - // https://github.com/swiftlang/swift/issues/79285 - _ closure: (PostgresConnection) async throws -> sending Result) async throws -> sending Result { + _ closure: (PostgresConnection) async throws -> sending Result + ) async throws -> sending Result { try await self.withConnection { connection in try await connection.withTransaction(logger: logger, file: file, line: line, closure) } } - #else - - /// Lease a connection, which is in an open transaction state, for the provided `closure`'s lifetime. - /// - /// The function leases a connection from the underlying connection pool and starts a transaction by running a `BEGIN` - /// query on the leased connection against the database. It then lends the connection to the user provided closure. - /// The user can then modify the database as they wish. If the user provided closure returns successfully, the function - /// will attempt to commit the changes by running a `COMMIT` query against the database. If the user provided closure - /// throws an error, the function will attempt to rollback the changes made within the closure. - /// - /// - Parameters: - /// - logger: The `Logger` to log into for the transaction. - /// - file: The file, the transaction was started in. Used for better error reporting. - /// - line: The line, the transaction was started in. Used for better error reporting. - /// - closure: The user provided code to modify the database. Use the provided connection to run queries. - /// The connection must stay in the transaction mode. Otherwise this method will throw! - /// - Returns: The closure's return value. - public func withTransaction( - logger: Logger, - file: String = #file, - line: Int = #line, - _ closure: (PostgresConnection) async throws -> Result - ) async throws -> Result { - try await self.withConnection { connection in - try await connection.withTransaction(logger: logger, file: file, line: line, closure) - } - } - #endif /// Run a query on the Postgres server the client is connected to. /// From b6b08fe988e3e4522c2def5135ab7f65fad62f52 Mon Sep 17 00:00:00 2001 From: Fabian Fett Date: Wed, 17 Sep 2025 11:50:57 +0200 Subject: [PATCH 2/7] Fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d03b8da..fa4495e2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Continuous Integration - Swift 5.10+ + Swift 6.0+ SSWG Incubation Level: Graduated @@ -163,7 +163,7 @@ Please see [SECURITY.md] for details on the security process. [Team Chat]: https://discord.gg/vapor [MIT License]: LICENSE [Continuous Integration]: https://github.com/vapor/postgres-nio/actions -[Swift 5.10]: https://swift.org +[Swift 6.0]: https://swift.org [Security.md]: https://github.com/vapor/.github/blob/main/SECURITY.md [`PostgresConnection`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresconnection From adbfcc92dc4744b231a711dd5369dc26b97d8620 Mon Sep 17 00:00:00 2001 From: Fabian Fett Date: Wed, 17 Sep 2025 11:56:51 +0200 Subject: [PATCH 3/7] Remove feature flag as now enabled by default --- Package.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index 0d726e39..12cb6351 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,7 @@ // swift-tools-version:6.0 import PackageDescription -let swiftSettings: [SwiftSetting] = [ - .enableUpcomingFeature("StrictConcurrency"), -] +let swiftSettings: [SwiftSetting] = [] let package = Package( name: "postgres-nio", From 0bb951b090b6988456f38782c29347a3139d9736 Mon Sep 17 00:00:00 2001 From: Fabian Fett Date: Wed, 17 Sep 2025 12:15:48 +0200 Subject: [PATCH 4/7] Make 6.0 compile --- Sources/PostgresNIO/Pool/PostgresClient.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/PostgresNIO/Pool/PostgresClient.swift b/Sources/PostgresNIO/Pool/PostgresClient.swift index 15b3a7b8..581b5113 100644 --- a/Sources/PostgresNIO/Pool/PostgresClient.swift +++ b/Sources/PostgresNIO/Pool/PostgresClient.swift @@ -346,8 +346,9 @@ public final class PostgresClient: Sendable, ServiceLifecycle.Service { isolation: isolated (any Actor)? = #isolation, _ closure: (PostgresConnection) async throws -> sending Result ) async throws -> sending Result { - try await self.withConnection { connection in - try await connection.withTransaction(logger: logger, file: file, line: line, closure) + // for 6.0 to compile we need to explicitly forward the isolation. + try await self.withConnection(isolation: isolation) { connection in + try await connection.withTransaction(logger: logger, file: file, line: line, isolation: isolation, closure) } } From 5a741fc59ee6eff695a2a844d982655e6ba011f3 Mon Sep 17 00:00:00 2001 From: Fabian Fett Date: Wed, 17 Sep 2025 14:12:27 +0200 Subject: [PATCH 5/7] Work around false positives. --- Package.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Package.swift b/Package.swift index 12cb6351..9942e09c 100644 --- a/Package.swift +++ b/Package.swift @@ -1,7 +1,13 @@ // swift-tools-version:6.0 import PackageDescription +#if compiler(>=6.1) let swiftSettings: [SwiftSetting] = [] +#else +let swiftSettings: [SwiftSetting] = [ + .swiftLanguageMode(.v5) +] +#endif let package = Package( name: "postgres-nio", From 26122f23c085f64efa9df3a075ef74f2278e22b2 Mon Sep 17 00:00:00 2001 From: Fabian Fett Date: Wed, 17 Sep 2025 14:21:52 +0200 Subject: [PATCH 6/7] Added a comment. --- Package.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Package.swift b/Package.swift index 9942e09c..673a4bb2 100644 --- a/Package.swift +++ b/Package.swift @@ -5,6 +5,8 @@ import PackageDescription let swiftSettings: [SwiftSetting] = [] #else let swiftSettings: [SwiftSetting] = [ + // Sadly the 6.0 compiler concurrency checker finds false positives. + // To be able to compile, lets reduce the language version down to 5 for 6.0 only. .swiftLanguageMode(.v5) ] #endif From b14335c0ba9cfc9cec753c431253176bdb75de02 Mon Sep 17 00:00:00 2001 From: Gwynne Raskind Date: Wed, 17 Sep 2025 08:30:50 -0500 Subject: [PATCH 7/7] Bump the Swift image for the integration tests too --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c96bf57a..926f2fbe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,7 +63,7 @@ jobs: - postgres-image: postgres:13 postgres-auth: trust container: - image: swift:6.1-noble + image: swift:6.2-noble volumes: [ 'pgrunshare:/var/run/postgresql' ] runs-on: ubuntu-latest env: