Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
container: swift:noble
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with: { 'fetch-depth': 0 }
- name: API breaking changes
run: |
Expand Down Expand Up @@ -74,10 +74,12 @@ jobs:
POSTGRES_HOST_AUTH_METHOD: ${{ matrix.postgres-auth }}
POSTGRES_INITDB_ARGS: --auth-host=${{ matrix.postgres-auth }}
steps:
- name: Ensure curl is available
run: apt-get update -y && apt-get install -y curl
- name: Check out package
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Run all tests
run: swift test --sanitize=thread --enable-code-coverage
run: swift test --enable-code-coverage
- name: Submit coverage report to Codecov.io
uses: vapor/[email protected]
with:
Expand Down Expand Up @@ -115,6 +117,6 @@ jobs:
PGPASSWORD="${POSTGRES_PASSWORD_A}" psql -w "${POSTGRES_DB_B}" <<<"ALTER SCHEMA public OWNER TO ${POSTGRES_USER_B};"
timeout-minutes: 15
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Run all tests
run: swift test --sanitize=thread
run: swift test
7 changes: 5 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ let package = Package(
.library(name: "FluentPostgresDriver", targets: ["FluentPostgresDriver"]),
],
dependencies: [
.package(url: "https://github.com/vapor/fluent-kit.git", from: "1.49.0"),
.package(url: "https://github.com/vapor/postgres-kit.git", from: "2.13.4"),
.package(url: "https://github.com/vapor/fluent-kit.git", from: "1.52.2"),
.package(url: "https://github.com/vapor/postgres-kit.git", from: "2.14.0"),
.package(url: "https://github.com/vapor/async-kit.git", from: "1.21.0"),
],
targets: [
.target(
Expand All @@ -23,6 +24,7 @@ let package = Package(
.product(name: "FluentKit", package: "fluent-kit"),
.product(name: "FluentSQL", package: "fluent-kit"),
.product(name: "PostgresKit", package: "postgres-kit"),
.product(name: "AsyncKit", package: "async-kit"),
],
swiftSettings: swiftSettings
),
Expand All @@ -39,6 +41,7 @@ let package = Package(

var swiftSettings: [SwiftSetting] { [
.enableUpcomingFeature("ExistentialAny"),
.enableUpcomingFeature("MemberImportVisibility"),
.enableUpcomingFeature("ConciseMagicFile"),
.enableUpcomingFeature("ForwardTrailingClosures"),
.enableUpcomingFeature("DisableOutwardActorInference"),
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 43 additions & 3 deletions Sources/FluentPostgresDriver/FluentPostgresConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@ extension DatabaseConfigurationFactory {
/// - urlString: The URL describing the connection, as a string.
/// - maxConnectionsPerEventLoop: Maximum number of connections to open per event loop.
/// - connectionPoolTimeout: Maximum time to wait for a connection to become available per request.
/// - pruneInterval: How often to check for and prune idle database connections. If `nil` (the default),
/// no pruning is performed.
/// - maxIdleTimeBeforePruning: How long a connection may remain idle before being pruned, if pruning is enabled.
/// Defaults to 2 minutes. Ignored if `pruneInterval` is `nil`.
/// - encodingContext: Encoding context to use for serializing data.
/// - decodingContext: Decoding context to use for deserializing data.
/// - sqlLogLevel: Level at which to log SQL queries.
public static func postgres(
url urlString: String,
maxConnectionsPerEventLoop: Int = 1,
connectionPoolTimeout: TimeAmount = .seconds(10),
pruneInterval: TimeAmount? = nil,
maxIdleTimeBeforePruning: TimeAmount = .seconds(120),
encodingContext: PostgresEncodingContext<some PostgresJSONEncoder> = .default,
decodingContext: PostgresDecodingContext<some PostgresJSONDecoder> = .default,
sqlLogLevel: Logger.Level = .debug
Expand All @@ -30,6 +36,8 @@ extension DatabaseConfigurationFactory {
configuration: try .init(url: urlString),
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop,
connectionPoolTimeout: connectionPoolTimeout,
pruneInterval: pruneInterval,
maxIdleTimeBeforePruning: maxIdleTimeBeforePruning,
encodingContext: encodingContext,
decodingContext: decodingContext,
sqlLogLevel: sqlLogLevel
Expand All @@ -44,13 +52,19 @@ extension DatabaseConfigurationFactory {
/// - url: The URL describing the connection.
/// - maxConnectionsPerEventLoop: Maximum number of connections to open per event loop.
/// - connectionPoolTimeout: Maximum time to wait for a connection to become available per request.
/// - pruneInterval: How often to check for and prune idle database connections. If `nil` (the default),
/// no pruning is performed.
/// - maxIdleTimeBeforePruning: How long a connection may remain idle before being pruned, if pruning is enabled.
/// Defaults to 2 minutes. Ignored if `pruneInterval` is `nil`.
/// - encodingContext: Encoding context to use for serializing data.
/// - decodingContext: Decoding context to use for deserializing data.
/// - sqlLogLevel: Level at which to log SQL queries.
public static func postgres(
url: URL,
maxConnectionsPerEventLoop: Int = 1,
connectionPoolTimeout: TimeAmount = .seconds(10),
pruneInterval: TimeAmount? = nil,
maxIdleTimeBeforePruning: TimeAmount = .seconds(120),
encodingContext: PostgresEncodingContext<some PostgresJSONEncoder> = .default,
decodingContext: PostgresDecodingContext<some PostgresJSONDecoder> = .default,
sqlLogLevel: Logger.Level = .debug
Expand All @@ -59,6 +73,8 @@ extension DatabaseConfigurationFactory {
configuration: try .init(url: url),
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop,
connectionPoolTimeout: connectionPoolTimeout,
pruneInterval: pruneInterval,
maxIdleTimeBeforePruning: maxIdleTimeBeforePruning,
encodingContext: encodingContext,
decodingContext: decodingContext,
sqlLogLevel: sqlLogLevel
Expand All @@ -71,13 +87,19 @@ extension DatabaseConfigurationFactory {
/// - configuration: A ``PostgresKit/SQLPostgresConfiguration`` describing the connection.
/// - maxConnectionsPerEventLoop: Maximum number of connections to open per event loop.
/// - connectionPoolTimeout: Maximum time to wait for a connection to become available per request.
/// - pruneInterval: How often to check for and prune idle database connections. If `nil` (the default),
/// no pruning is performed.
/// - maxIdleTimeBeforePruning: How long a connection may remain idle before being pruned, if pruning is enabled.
/// Defaults to 2 minutes. Ignored if `pruneInterval` is `nil`.
/// - encodingContext: Encoding context to use for serializing data.
/// - decodingContext: Decoding context to use for deserializing data.
/// - sqlLogLevel: Level at which to log SQL queries.
public static func postgres(
configuration: SQLPostgresConfiguration,
maxConnectionsPerEventLoop: Int = 1,
connectionPoolTimeout: TimeAmount = .seconds(10),
pruneInterval: TimeAmount? = nil,
maxIdleTimeBeforePruning: TimeAmount = .seconds(120),
encodingContext: PostgresEncodingContext<some PostgresJSONEncoder>,
decodingContext: PostgresDecodingContext<some PostgresJSONDecoder>,
sqlLogLevel: Logger.Level = .debug
Expand All @@ -87,6 +109,8 @@ extension DatabaseConfigurationFactory {
configuration: configuration,
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop,
connectionPoolTimeout: connectionPoolTimeout,
pruningInterval: pruneInterval,
maxIdleTimeBeforePruning: maxIdleTimeBeforePruning,
encodingContext: encodingContext,
decodingContext: decodingContext,
sqlLogLevel: sqlLogLevel
Expand All @@ -108,56 +132,68 @@ extension DatabaseConfigurationFactory {
///
/// _ = DatabaseConfigurationFactory.postgres(configuration: .init(unixDomainSocketPath: "", username: ""))
extension DatabaseConfigurationFactory {
/// ``postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)``
/// ``postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:pruneInterval:maxIdleTimeBeforePruning:encodingContext:decodingContext:sqlLogLevel:)``
/// with the `decodingContext` defaulted.
public static func postgres(
configuration: SQLPostgresConfiguration,
maxConnectionsPerEventLoop: Int = 1,
connectionPoolTimeout: TimeAmount = .seconds(10),
pruneInterval: TimeAmount? = nil,
maxIdleTimeBeforePruning: TimeAmount = .seconds(120),
encodingContext: PostgresEncodingContext<some PostgresJSONEncoder>,
sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(
configuration: configuration,
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop,
connectionPoolTimeout: connectionPoolTimeout,
pruneInterval: pruneInterval,
maxIdleTimeBeforePruning: maxIdleTimeBeforePruning,
encodingContext: encodingContext,
decodingContext: .default,
sqlLogLevel: sqlLogLevel
)
}

/// ``postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)``
/// ``postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:pruneInterval:maxIdleTimeBeforePruning:encodingContext:decodingContext:sqlLogLevel:)``
/// with the `encodingContext` defaulted.
public static func postgres(
configuration: SQLPostgresConfiguration,
maxConnectionsPerEventLoop: Int = 1,
connectionPoolTimeout: TimeAmount = .seconds(10),
pruneInterval: TimeAmount? = nil,
maxIdleTimeBeforePruning: TimeAmount = .seconds(120),
decodingContext: PostgresDecodingContext<some PostgresJSONDecoder>,
sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(
configuration: configuration,
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop,
connectionPoolTimeout: connectionPoolTimeout,
pruneInterval: pruneInterval,
maxIdleTimeBeforePruning: maxIdleTimeBeforePruning,
encodingContext: .default,
decodingContext: decodingContext,
sqlLogLevel: sqlLogLevel
)
}

/// ``postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)``
/// ``postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:pruneInterval:maxIdleTimeBeforePruning:encodingContext:decodingContext:sqlLogLevel:)``
/// with both `encodingContext` and `decodingContext` defaulted.
public static func postgres(
configuration: SQLPostgresConfiguration,
maxConnectionsPerEventLoop: Int = 1,
connectionPoolTimeout: TimeAmount = .seconds(10),
pruneInterval: TimeAmount? = nil,
maxIdleTimeBeforePruning: TimeAmount = .seconds(120),
sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(
configuration: configuration,
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop,
connectionPoolTimeout: connectionPoolTimeout,
pruneInterval: pruneInterval,
maxIdleTimeBeforePruning: maxIdleTimeBeforePruning,
encodingContext: .default,
decodingContext: .default,
sqlLogLevel: sqlLogLevel
Expand All @@ -171,6 +207,8 @@ struct FluentPostgresConfiguration<E: PostgresJSONEncoder, D: PostgresJSONDecode
fileprivate let configuration: SQLPostgresConfiguration
let maxConnectionsPerEventLoop: Int
let connectionPoolTimeout: TimeAmount
let pruningInterval: TimeAmount?
let maxIdleTimeBeforePruning: TimeAmount
let encodingContext: PostgresEncodingContext<E>
let decodingContext: PostgresDecodingContext<D>
let sqlLogLevel: Logger.Level
Expand All @@ -181,6 +219,8 @@ struct FluentPostgresConfiguration<E: PostgresJSONEncoder, D: PostgresJSONDecode
source: connectionSource,
maxConnectionsPerEventLoop: self.maxConnectionsPerEventLoop,
requestTimeout: self.connectionPoolTimeout,
pruneInterval: self.pruningInterval,
maxIdleTimeBeforePruning: self.maxIdleTimeBeforePruning,
on: databases.eventLoopGroup
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ extension _FluentPostgresDatabase: Database {
}
}

func transaction<T>(_ closure: @escaping @Sendable (any Database) -> EventLoopFuture<T>) -> EventLoopFuture<T> {
func transaction<T: Sendable>(_ closure: @escaping @Sendable (any Database) -> EventLoopFuture<T>) -> EventLoopFuture<T> {
guard !self.inTransaction else {
return closure(self)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ struct PostgresConverterDelegate: SQLConverterDelegate {
case .dictionary:
SQLRaw("JSONB")
case .array(of: let type):
if let type = type, let dataType = self.customDataType(type) {
if let type, let dataType = self.customDataType(type) {
SQLArrayDataType(dataType: dataType)
} else {
SQLRaw("JSONB")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import FluentBenchmark
import FluentKit
import FluentPostgresDriver
import FluentSQL
import Logging
import PostgresKit
import SQLKit
Expand Down Expand Up @@ -310,6 +311,8 @@ extension DatabaseConfigurationFactory {
return .postgres(
configuration: baseSubconfig,
connectionPoolTimeout: .seconds(30),
pruneInterval: .seconds(30),
maxIdleTimeBeforePruning: .seconds(60),
encodingContext: encodingContext,
decodingContext: decodingContext
)
Expand Down
Loading