Skip to content

Commit

Permalink
Yield deprecation warnings (instead of compiler errors) for previousl…
Browse files Browse the repository at this point in the history
…y working code using the old postgres configuration methods, while setting it up so the compiler correctly defaults to the new ones in ambiguous cases.
  • Loading branch information
gwynne committed May 11, 2023
1 parent 0aa809c commit bae9140
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,11 @@ extension DatabaseConfigurationFactory {
public static func postgres(
hostname: String, port: Int = PostgresConfiguration.ianaPortNumber,
username: String, password: String, database: String? = nil, tlsConfiguration: TLSConfiguration? = nil,
maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
encoder: PostgresDataEncoder, decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
maxConnectionsPerEventLoop: Int = 1,
connectionPoolTimeout: TimeAmount = .seconds(10),
encoder: PostgresDataEncoder = .init(),
decoder: PostgresDataDecoder = .init(),
sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(configuration: .init(
hostname: hostname, port: port, username: username, password: password, database: database, tlsConfiguration: tlsConfiguration),
Expand All @@ -57,8 +60,11 @@ extension DatabaseConfigurationFactory {
@available(*, deprecated, message: "Use `.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
public static func postgres(
configuration: PostgresConfiguration,
maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
encoder: PostgresDataEncoder, decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
maxConnectionsPerEventLoop: Int = 1,
connectionPoolTimeout: TimeAmount = .seconds(10),
encoder: PostgresDataEncoder = .init(),
decoder: PostgresDataDecoder = .init(),
sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(
configuration: .init(legacyConfiguration: configuration),
Expand Down Expand Up @@ -115,70 +121,6 @@ extension DatabaseConfigurationFactory {
encoder: .init(), decoder: decoder, sqlLogLevel: sqlLogLevel
)
}

@available(*, deprecated, message: "Use `.postgres(configuration:.init(hostname:port:username:password:database:tls:),maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
public static func postgres(
hostname: String, port: Int = PostgresConfiguration.ianaPortNumber,
username: String, password: String, database: String? = nil, tlsConfiguration: TLSConfiguration? = nil,
maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(
hostname: hostname, port: port, username: username, password: password, database: database, tlsConfiguration: tlsConfiguration,
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
encoder: .init(), decoder: .init(), sqlLogLevel: sqlLogLevel
)
}

@available(*, deprecated, message: "Use `.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
public static func postgres(
hostname: String, port: Int = PostgresConfiguration.ianaPortNumber,
username: String, password: String, database: String? = nil, tlsConfiguration: TLSConfiguration? = nil,
maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
encoder: PostgresDataEncoder, sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(
hostname: hostname, port: port, username: username, password: password, database: database, tlsConfiguration: tlsConfiguration,
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
encoder: encoder, decoder: .init(), sqlLogLevel: sqlLogLevel
)
}

@available(*, deprecated, message: "Use `.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
public static func postgres(
hostname: String, port: Int = PostgresConfiguration.ianaPortNumber,
username: String, password: String, database: String? = nil, tlsConfiguration: TLSConfiguration? = nil,
maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(
hostname: hostname, port: port, username: username, password: password, database: database, tlsConfiguration: tlsConfiguration,
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
encoder: .init(), decoder: decoder, sqlLogLevel: sqlLogLevel
)
}

@available(*, deprecated, message: "Use `.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
public static func postgres(
configuration: PostgresConfiguration, maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
encoder: PostgresDataEncoder, sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(configuration: configuration,
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
encoder: encoder, decoder: .init(), sqlLogLevel: sqlLogLevel
)
}

@available(*, deprecated, message: "Use `.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
public static func postgres(
configuration: PostgresConfiguration, maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(configuration: configuration,
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
encoder: .init(), decoder: decoder, sqlLogLevel: sqlLogLevel
)
}
}

// N.B.: If you change something in these two types, update the copies in PostgresKit too.
Expand Down
75 changes: 73 additions & 2 deletions Sources/FluentPostgresDriver/FluentPostgresConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ extension DatabaseConfigurationFactory {
configuration: SQLPostgresConfiguration,
maxConnectionsPerEventLoop: Int = 1,
connectionPoolTimeout: TimeAmount = .seconds(10),
encodingContext: PostgresEncodingContext<some PostgresJSONEncoder> = .default,
decodingContext: PostgresDecodingContext<some PostgresJSONDecoder> = .default,
encodingContext: PostgresEncodingContext<some PostgresJSONEncoder>,
decodingContext: PostgresDecodingContext<some PostgresJSONDecoder>,
sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.init {
Expand All @@ -93,6 +93,77 @@ extension DatabaseConfigurationFactory {
}
}

/// We'd like to just default the context parameters of the "actual" method. Unfortunately, there are a few
/// cases involving the UNIX domain socket initalizer where usage can resolve to either the new
/// ``SQLPostgresConfiguration``-based method or the deprecated ``PostgresConfiguration``-based method, with no
/// obvious way to disambiguate which to call. Because the context parameters are generic, if they are defaulted,
/// the compiler resolves the ambiguity in favor of the deprecated method (which has no generic parameters).
/// However, by adding the non-defaulted-parameter variant which takes neither context, we've provided a version
/// which has no generic parameters either, which allows the compiler to resolve the ambiguity in favor of
/// the one with better availability (i.e. the one that isn't deprecated).
///
/// Example affected code:
///
/// _ = DatabaseConfigurationFactory.postgres(configuration: .init(unixDomainSocketPath: "", username: ""))
extension DatabaseConfigurationFactory {
/// ``postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)``
/// with the `decodingContext` defaulted.
public static func postgres(
configuration: SQLPostgresConfiguration,
maxConnectionsPerEventLoop: Int = 1,
connectionPoolTimeout: TimeAmount = .seconds(10),
encodingContext: PostgresEncodingContext<some PostgresJSONEncoder>,
sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(
configuration: configuration,
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop,
connectionPoolTimeout: connectionPoolTimeout,
encodingContext: encodingContext,
decodingContext: .default,
sqlLogLevel: sqlLogLevel
)
}

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

/// ``postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)``
/// with both `encodingContext` and `decodingContext` defaulted.
public static func postgres(
configuration: SQLPostgresConfiguration,
maxConnectionsPerEventLoop: Int = 1,
connectionPoolTimeout: TimeAmount = .seconds(10),
sqlLogLevel: Logger.Level = .debug
) -> DatabaseConfigurationFactory {
.postgres(
configuration: configuration,
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop,
connectionPoolTimeout: connectionPoolTimeout,
encodingContext: .default,
decodingContext: .default,
sqlLogLevel: sqlLogLevel
)
}
}

/// The actual concrete configuration type produced by a configuration factory.
struct FluentPostgresConfiguration<E: PostgresJSONEncoder, D: PostgresJSONDecoder>: DatabaseConfiguration {
var middleware: [any AnyModelMiddleware] = []
let configuration: SQLPostgresConfiguration
Expand Down

0 comments on commit bae9140

Please sign in to comment.