From 09d0abbce1a7a37dbc6d94474dc0d31139a4df7d Mon Sep 17 00:00:00 2001 From: GErP83 Date: Tue, 11 Aug 2026 15:46:55 +0200 Subject: [PATCH 1/2] add Logger.current --- Package.resolved | 10 +- Package.swift | 4 +- README.md | 26 +- .../DatabaseClientPostgres.swift | 27 +- .../DatabaseConnectionPostgres.swift | 4 +- .../FeatherDatabasePostgresTestSuite.swift | 231 +++++++++--------- 6 files changed, 143 insertions(+), 159 deletions(-) diff --git a/Package.resolved b/Package.resolved index 92dedf6..95cab90 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "b8fbf14a005f63f486e18520087e8ea910d9145811a225424d0aa92a8896bd30", + "originHash" : "012336050555ec1139dd40493dd9447383cabc653fe2058ce87f1c7dd218889a", "pins" : [ { "identity" : "feather-database", "kind" : "remoteSourceControl", "location" : "https://github.com/feather-framework/feather-database", "state" : { - "revision" : "0b862ac3ee31859e2c8a54b06390ee92d1a7c0b4", - "version" : "1.0.0-rc.1" + "revision" : "d290d92b2617ad5768c293c4edcdd66b4f178d48", + "version" : "1.0.0-rc.2" } }, { @@ -69,8 +69,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-log", "state" : { - "revision" : "2778fd4e5a12a8aaa30a3ee8285f4ce54c5f3181", - "version" : "1.9.1" + "revision" : "3ffafb9722d5d918c614feb496c8789a3b59d222", + "version" : "1.15.0" } }, { diff --git a/Package.swift b/Package.swift index 98b3c41..b06a5ec 100644 --- a/Package.swift +++ b/Package.swift @@ -35,9 +35,9 @@ let package = Package( .library(name: "FeatherDatabasePostgres", targets: ["FeatherDatabasePostgres"]), ], dependencies: [ - .package(url: "https://github.com/apple/swift-log", from: "1.6.0"), + .package(url: "https://github.com/apple/swift-log.git", from: "1.14.0"), .package(url: "https://github.com/vapor/postgres-nio", from: "1.27.0"), - .package(url: "https://github.com/feather-framework/feather-database", exact: "1.0.0-rc.1"), + .package(url: "https://github.com/feather-framework/feather-database", exact: "1.0.0-rc.2"), // [docc-plugin-placeholder] ], targets: [ diff --git a/README.md b/README.md index c746dd9..27daa5d 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,8 @@ -# Feather Database Postgres +# Feather Database Postgres Postgres driver implementation for the abstract [Feather Database](https://github.com/feather-framework/feather-database) Swift API package. -[ - ![Release: 1.0.0-rc.1](https://img.shields.io/badge/Release-1%2E0%2E0--rc%2E1-F05138) -]( - https://github.com/feather-framework/feather-database-postgres/releases/tag/1.0.0-rc.1 -) +[![Release: 1.0.0-rc.2](https://img.shields.io/badge/Release-1%2E0%2E0--rc%2E2-F05138)](https://github.com/feather-framework/feather-database-postgres/releases/tag/1.0.0-rc.2) ## Features @@ -37,7 +33,7 @@ Postgres driver implementation for the abstract [Feather Database](https://githu Add the dependency to your `Package.swift`: ```swift -.package(url: "https://github.com/feather-framework/feather-database-postgres", exact: "1.0.0-rc.1"), +.package(url: "https://github.com/feather-framework/feather-database-postgres", exact: "1.0.0-rc.2"), ``` Then add `FeatherDatabasePostgres` to your target dependencies: @@ -50,11 +46,7 @@ Then add `FeatherDatabasePostgres` to your target dependencies: API documentation is available at the link below: -[ - ![DocC API documentation](https://img.shields.io/badge/DocC-API_documentation-F05138) -]( - https://feather-framework.github.io/feather-database-postgres/ -) +[![DocC API documentation](https://img.shields.io/badge/DocC-API_documentation-F05138)](https://feather-framework.github.io/feather-database-postgres/) Here is a brief example: @@ -65,9 +57,6 @@ import PostgresNIO import FeatherDatabase import FeatherDatabasePostgres -var logger = Logger(label: "example") -logger.logLevel = .info - let finalCertPath = URL(fileURLWithPath: "/path/to/ca.pem") var tlsConfig = TLSConfiguration.makeClientConfiguration() let rootCert = try NIOSSLCertificate.fromPEMFile(finalCertPath) @@ -83,12 +72,11 @@ let client = PostgresClient( database: "postgres", tls: .require(tlsConfig) ), - backgroundLogger: logger + backgroundLogger: Logger.current ) let database = DatabaseClientPostgres( - client: client, - logger: logger + client: client ) try await withThrowingTaskGroup(of: Void.self) { group in @@ -119,6 +107,8 @@ try await withThrowingTaskGroup(of: Void.self) { group in } ``` +The package uses `Logger.current` from [swift-log](https://github.com/apple/swift-log) for database logging. + ## Other database drivers The following database driver implementations are available for use: diff --git a/Sources/FeatherDatabasePostgres/DatabaseClientPostgres.swift b/Sources/FeatherDatabasePostgres/DatabaseClientPostgres.swift index 6d2b807..d2f054f 100644 --- a/Sources/FeatherDatabasePostgres/DatabaseClientPostgres.swift +++ b/Sources/FeatherDatabasePostgres/DatabaseClientPostgres.swift @@ -16,20 +16,16 @@ public struct DatabaseClientPostgres: DatabaseClient { public typealias Connection = DatabaseConnectionPostgres var client: PostgresNIO.PostgresClient - let logger: Logger /// Create a Postgres database client. /// /// Use this initializer to provide an existing Postgres client. - /// - Parameters: + /// - Parameter: /// - client: The underlying Postgres client. - /// - logger: The logger for database operations. public init( - client: PostgresNIO.PostgresClient, - logger: Logger + client: PostgresNIO.PostgresClient ) { self.client = client - self.logger = logger } // MARK: - database api @@ -44,12 +40,10 @@ public struct DatabaseClientPostgres: DatabaseClient { public func withConnection( _ closure: (Connection) async throws -> T, ) async throws(DatabaseError) -> T { - let logger = self.logger let body: (PostgresConnection) async throws -> T = { connection in try await closure( DatabaseConnectionPostgres( - connection: connection, - logger: logger + connection: connection ) ) } @@ -75,7 +69,6 @@ public struct DatabaseClientPostgres: DatabaseClient { public func withTransaction( _ closure: (Connection) async throws -> T, ) async throws(DatabaseError) -> T { - let logger = self.logger let beginQuery = PostgresQuery(unsafeSQL: "BEGIN", binds: .init()) let commitQuery = PostgresQuery(unsafeSQL: "COMMIT", binds: .init()) let rollbackQuery = PostgresQuery(unsafeSQL: "ROLLBACK", binds: .init()) @@ -83,12 +76,14 @@ public struct DatabaseClientPostgres: DatabaseClient { do { return try await client.withConnection { connection in let databaseConnection = DatabaseConnectionPostgres( - connection: connection, - logger: logger + connection: connection ) do { - _ = try await connection.query(beginQuery, logger: logger) + _ = try await connection.query( + beginQuery, + logger: Logger.current + ) } catch { throw DatabaseError.transaction( @@ -103,7 +98,7 @@ public struct DatabaseClientPostgres: DatabaseClient { do { _ = try await connection.query( commitQuery, - logger: logger + logger: Logger.current ) return result } @@ -113,7 +108,7 @@ public struct DatabaseClientPostgres: DatabaseClient { do { _ = try await connection.query( rollbackQuery, - logger: logger + logger: Logger.current ) } catch { @@ -133,7 +128,7 @@ public struct DatabaseClientPostgres: DatabaseClient { do { _ = try await connection.query( rollbackQuery, - logger: logger + logger: Logger.current ) } catch { diff --git a/Sources/FeatherDatabasePostgres/DatabaseConnectionPostgres.swift b/Sources/FeatherDatabasePostgres/DatabaseConnectionPostgres.swift index 40e2e8b..e819ccc 100644 --- a/Sources/FeatherDatabasePostgres/DatabaseConnectionPostgres.swift +++ b/Sources/FeatherDatabasePostgres/DatabaseConnectionPostgres.swift @@ -6,6 +6,7 @@ // import FeatherDatabase +import Logging import PostgresNIO extension DatabaseQuery { @@ -45,7 +46,6 @@ public struct DatabaseConnectionPostgres: DatabaseConnection { public typealias RowSequence = DatabaseRowSequencePostgres var connection: PostgresConnection - public var logger: Logger /// Execute a Postgres query on this connection. /// @@ -63,7 +63,7 @@ public struct DatabaseConnectionPostgres: DatabaseConnection { do { let sequence = try await connection.query( query.toPostgresQuery(), - logger: logger + logger: Logger.current ) return try await handler( diff --git a/Tests/FeatherDatabasePostgresTests/FeatherDatabasePostgresTestSuite.swift b/Tests/FeatherDatabasePostgresTests/FeatherDatabasePostgresTestSuite.swift index 15e8713..8e18072 100644 --- a/Tests/FeatherDatabasePostgresTests/FeatherDatabasePostgresTestSuite.swift +++ b/Tests/FeatherDatabasePostgresTests/FeatherDatabasePostgresTestSuite.swift @@ -37,144 +37,143 @@ struct FeatherDatabasePostgresTestSuite { _ closure: @escaping (@Sendable (DatabaseClientPostgres) async throws -> Void) ) async throws { - var logger = Logger(label: "test") - logger.logLevel = .info - - let environment = ProcessInfo.processInfo.environment + try await withLogger(Logger(label: "test")) { logger in + + let environment = ProcessInfo.processInfo.environment + + let finalCertPath = + environment["POSTGRES_CA_CERT_PATH"] + ?? URL( + fileURLWithPath: #filePath + ) + .deletingLastPathComponent() + .deletingLastPathComponent() + .deletingLastPathComponent() + .appendingPathComponent("docker") + .appendingPathComponent("postgres") + .appendingPathComponent("certificates") + .appendingPathComponent("ca.pem") + .path() + + let host = environment["POSTGRES_HOST"] ?? "127.0.0.1" + let port = environment["POSTGRES_PORT"].flatMap(Int.init) ?? 5432 + let testDatabaseName = "test_\(randomTableSuffix())" + + var tlsConfig = TLSConfiguration.makeClientConfiguration() + let rootCert = try NIOSSLCertificate.fromPEMFile(finalCertPath) + tlsConfig.trustRoots = .certificates(rootCert) + tlsConfig.certificateVerification = .fullVerification + let clientTLSConfig = tlsConfig + let sslContext = try NIOSSLContext(configuration: tlsConfig) + + let createDatabaseQuery = PostgresQuery( + unsafeSQL: #""" + CREATE DATABASE "\#(testDatabaseName)" + """#, + binds: .init() + ) - let finalCertPath = - environment["POSTGRES_CA_CERT_PATH"] - ?? URL( - fileURLWithPath: #filePath + let dropDatabaseQuery = PostgresQuery( + unsafeSQL: #""" + DROP DATABASE IF EXISTS "\#(testDatabaseName)" WITH (FORCE) + """#, + binds: .init() ) - .deletingLastPathComponent() - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("docker") - .appendingPathComponent("postgres") - .appendingPathComponent("certificates") - .appendingPathComponent("ca.pem") - .path() - - let host = environment["POSTGRES_HOST"] ?? "127.0.0.1" - let port = environment["POSTGRES_PORT"].flatMap(Int.init) ?? 5432 - let testDatabaseName = "test_\(randomTableSuffix())" - - var tlsConfig = TLSConfiguration.makeClientConfiguration() - let rootCert = try NIOSSLCertificate.fromPEMFile(finalCertPath) - tlsConfig.trustRoots = .certificates(rootCert) - tlsConfig.certificateVerification = .fullVerification - let clientTLSConfig = tlsConfig - let sslContext = try NIOSSLContext(configuration: tlsConfig) - - let createDatabaseQuery = PostgresQuery( - unsafeSQL: #""" - CREATE DATABASE "\#(testDatabaseName)" - """#, - binds: .init() - ) - - let dropDatabaseQuery = PostgresQuery( - unsafeSQL: #""" - DROP DATABASE IF EXISTS "\#(testDatabaseName)" WITH (FORCE) - """#, - binds: .init() - ) - - let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) - - do { - let rootConnection = - try await PostgresConnection.connect( - on: eventLoopGroup.next(), - configuration: .init( - host: host, - port: port, - username: "postgres", - password: "postgres", - database: "postgres", - tls: .require(sslContext) - ), - id: 1, - logger: logger - ) - func cleanup() async { + let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) + + do { + let rootConnection = + try await PostgresConnection.connect( + on: eventLoopGroup.next(), + configuration: .init( + host: host, + port: port, + username: "postgres", + password: "postgres", + database: "postgres", + tls: .require(sslContext) + ), + id: 1, + logger: logger + ) + + func cleanup() async { + do { + _ = + try await rootConnection + .query(dropDatabaseQuery, logger: logger) + .get() + } + catch { + // The temporary database may already be gone. + } + + do { + try await rootConnection.close().get() + } + catch { + // Ignore close failures during teardown. + } + + do { + try await eventLoopGroup.shutdownGracefully() + } + catch { + // Ignore shutdown failures during teardown. + } + } + do { _ = try await rootConnection - .query(dropDatabaseQuery, logger: logger) + .query(createDatabaseQuery, logger: logger) .get() } catch { - // The temporary database may already be gone. + await cleanup() + Issue.record(error) + return } - do { - try await rootConnection.close().get() - } - catch { - // Ignore close failures during teardown. - } + let client = PostgresClient( + configuration: .init( + host: host, + port: port, + username: "postgres", + password: "postgres", + database: testDatabaseName, + tls: .require(clientTLSConfig) + ), + backgroundLogger: logger + ) + let database = DatabaseClientPostgres( + client: client + ) do { - try await eventLoopGroup.shutdownGracefully() + try await withThrowingTaskGroup(of: Void.self) { group in + group.addTask { + await client.run() + } + group.addTask { + try await closure(database) + } + _ = try await group.next() + group.cancelAll() + _ = try await group.next() + } } catch { - // Ignore shutdown failures during teardown. + Issue.record(error) } - } - do { - _ = - try await rootConnection - .query(createDatabaseQuery, logger: logger) - .get() - } - catch { await cleanup() - Issue.record(error) - return - } - - let client = PostgresClient( - configuration: .init( - host: host, - port: port, - username: "postgres", - password: "postgres", - database: testDatabaseName, - tls: .require(clientTLSConfig) - ), - backgroundLogger: logger - ) - let database = DatabaseClientPostgres( - client: client, - logger: logger - ) - - do { - try await withThrowingTaskGroup(of: Void.self) { group in - group.addTask { - await client.run() - } - group.addTask { - try await closure(database) - } - _ = try await group.next() - group.cancelAll() - _ = try await group.next() - } } catch { + try? await eventLoopGroup.shutdownGracefully() Issue.record(error) } - - await cleanup() - } - catch { - try? await eventLoopGroup.shutdownGracefully() - Issue.record(error) } } From f0aa7a8da5b16616e5144da1e6ecce1e2da58bbd Mon Sep 17 00:00:00 2001 From: GErP83 Date: Tue, 11 Aug 2026 16:18:30 +0200 Subject: [PATCH 2/2] update readme --- Package.swift | 2 +- README.md | 92 ++++++++++++++++++++++++++------------------------- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/Package.swift b/Package.swift index b06a5ec..3267882 100644 --- a/Package.swift +++ b/Package.swift @@ -35,7 +35,7 @@ let package = Package( .library(name: "FeatherDatabasePostgres", targets: ["FeatherDatabasePostgres"]), ], dependencies: [ - .package(url: "https://github.com/apple/swift-log.git", from: "1.14.0"), + .package(url: "https://github.com/apple/swift-log", from: "1.14.0"), .package(url: "https://github.com/vapor/postgres-nio", from: "1.27.0"), .package(url: "https://github.com/feather-framework/feather-database", exact: "1.0.0-rc.2"), // [docc-plugin-placeholder] diff --git a/README.md b/README.md index 27daa5d..2d851df 100644 --- a/README.md +++ b/README.md @@ -57,57 +57,59 @@ import PostgresNIO import FeatherDatabase import FeatherDatabasePostgres -let finalCertPath = URL(fileURLWithPath: "/path/to/ca.pem") -var tlsConfig = TLSConfiguration.makeClientConfiguration() -let rootCert = try NIOSSLCertificate.fromPEMFile(finalCertPath) -tlsConfig.trustRoots = .certificates(rootCert) -tlsConfig.certificateVerification = .fullVerification - -let client = PostgresClient( - configuration: .init( - host: "127.0.0.1", - port: 5432, - username: "postgres", - password: "postgres", - database: "postgres", - tls: .require(tlsConfig) - ), - backgroundLogger: Logger.current -) - -let database = DatabaseClientPostgres( - client: client -) - -try await withThrowingTaskGroup(of: Void.self) { group in - // run the client as a service - group.addTask { - await client.run() - } - // execute some query - group.addTask { - let result = try await database.withConnection { connection in - try await connection.run( - query: #""" - SELECT - version() AS "version" - WHERE - 1=\#(1); - """# - ) +try await withLogger(Logger(label: "example")) { _ in + let finalCertPath = URL(fileURLWithPath: "/path/to/ca.pem") + var tlsConfig = TLSConfiguration.makeClientConfiguration() + let rootCert = try NIOSSLCertificate.fromPEMFile(finalCertPath) + tlsConfig.trustRoots = .certificates(rootCert) + tlsConfig.certificateVerification = .fullVerification + + let client = PostgresClient( + configuration: .init( + host: "127.0.0.1", + port: 5432, + username: "postgres", + password: "postgres", + database: "postgres", + tls: .require(tlsConfig) + ), + backgroundLogger: Logger.current + ) + + let database = DatabaseClientPostgres( + client: client + ) + + try await withThrowingTaskGroup(of: Void.self) { group in + // run the client as a service + group.addTask { + await client.run() } - - for try await item in result { - let version = try item.decode(column: "version", as: String.self) - print(version) + // execute some query + group.addTask { + let result = try await database.withConnection { connection in + try await connection.run( + query: #""" + SELECT + version() AS "version" + WHERE + 1=\#(1); + """# + ) + } + + for try await item in result { + let version = try item.decode(column: "version", as: String.self) + print(version) + } } + try await group.next() + group.cancelAll() } - try await group.next() - group.cancelAll() } ``` -The package uses `Logger.current` from [swift-log](https://github.com/apple/swift-log) for database logging. +The package uses `Logger.current` from [swift-log](https://github.com/apple/swift-log) for database logging. Use `withLogger` to scope the logger for an operation; calls to `Logger.current` within that scope use the scoped logger. ## Other database drivers