diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1eaf9a87..926f2fbe 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 @@ -64,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: diff --git a/Package.swift b/Package.swift index af2d07ae..673a4bb2 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,15 @@ -// swift-tools-version:5.10 +// swift-tools-version:6.0 import PackageDescription +#if compiler(>=6.1) +let swiftSettings: [SwiftSetting] = [] +#else let swiftSettings: [SwiftSetting] = [ - .enableUpcomingFeature("StrictConcurrency"), + // 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 let package = Package( name: "postgres-nio", 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 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..581b5113 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,13 @@ 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 { - try await self.withConnection { connection in - try await connection.withTransaction(logger: logger, file: file, line: line, closure) + _ closure: (PostgresConnection) async throws -> sending Result + ) async throws -> sending Result { + // 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) } } - #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. ///