From bae9140e3764a78d0effd1d88051f0bea1242f4d Mon Sep 17 00:00:00 2001 From: Gwynne Raskind Date: Thu, 11 May 2023 12:30:57 -0500 Subject: [PATCH 1/3] Yield deprecation warnings (instead of compiler errors) for previously working code using the old postgres configuration methods, while setting it up so the compiler correctly defaults to the new ones in ambiguous cases. --- ...uentPostgresConfiguration+Deprecated.swift | 78 +++---------------- .../FluentPostgresConfiguration.swift | 75 +++++++++++++++++- 2 files changed, 83 insertions(+), 70 deletions(-) diff --git a/Sources/FluentPostgresDriver/Deprecations/FluentPostgresConfiguration+Deprecated.swift b/Sources/FluentPostgresDriver/Deprecations/FluentPostgresConfiguration+Deprecated.swift index 6cfbfa6..600c52c 100644 --- a/Sources/FluentPostgresDriver/Deprecations/FluentPostgresConfiguration+Deprecated.swift +++ b/Sources/FluentPostgresDriver/Deprecations/FluentPostgresConfiguration+Deprecated.swift @@ -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), @@ -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), @@ -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. diff --git a/Sources/FluentPostgresDriver/FluentPostgresConfiguration.swift b/Sources/FluentPostgresDriver/FluentPostgresConfiguration.swift index 7891a7e..b7f835b 100644 --- a/Sources/FluentPostgresDriver/FluentPostgresConfiguration.swift +++ b/Sources/FluentPostgresDriver/FluentPostgresConfiguration.swift @@ -77,8 +77,8 @@ extension DatabaseConfigurationFactory { configuration: SQLPostgresConfiguration, maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10), - encodingContext: PostgresEncodingContext = .default, - decodingContext: PostgresDecodingContext = .default, + encodingContext: PostgresEncodingContext, + decodingContext: PostgresDecodingContext, sqlLogLevel: Logger.Level = .debug ) -> DatabaseConfigurationFactory { .init { @@ -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, + 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, + 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: DatabaseConfiguration { var middleware: [any AnyModelMiddleware] = [] let configuration: SQLPostgresConfiguration From cb39774b14f391240049e7aa04eb595245308863 Mon Sep 17 00:00:00 2001 From: Gwynne Raskind Date: Thu, 11 May 2023 12:42:10 -0500 Subject: [PATCH 2/3] API breakage checker is basically a joke with this package. --- .../allowlist-branch-fix-deprecations.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .api-breakage/allowlist-branch-fix-deprecations.txt diff --git a/.api-breakage/allowlist-branch-fix-deprecations.txt b/.api-breakage/allowlist-branch-fix-deprecations.txt new file mode 100644 index 0000000..fb86138 --- /dev/null +++ b/.api-breakage/allowlist-branch-fix-deprecations.txt @@ -0,0 +1,18 @@ +API breakage: func DatabaseConfigurationFactory.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:) has removed default argument from parameter 3 +API breakage: func DatabaseConfigurationFactory.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:) has removed default argument from parameter 4 +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:sqlLogLevel:) has parameter 0 type change from Swift.String to PostgresKit.SQLPostgresConfiguration +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:sqlLogLevel:) has parameter 2 type change from Swift.String to NIOCore.TimeAmount +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:sqlLogLevel:) has parameter 3 type change from Swift.String to Logging.Logger.Level +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:sqlLogLevel:) has parameter 0 type change from Swift.String to PostgresKit.SQLPostgresConfiguration +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:sqlLogLevel:) has parameter 2 type change from Swift.String to NIOCore.TimeAmount +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:sqlLogLevel:) has parameter 3 type change from Swift.String to PostgresNIO.PostgresEncodingContext +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:sqlLogLevel:) has parameter 4 type change from Swift.String? to Logging.Logger.Level +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:decoder:sqlLogLevel:) has parameter 0 type change from Swift.String to PostgresKit.SQLPostgresConfiguration +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:decoder:sqlLogLevel:) has parameter 2 type change from Swift.String to NIOCore.TimeAmount +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:decoder:sqlLogLevel:) has parameter 3 type change from Swift.String to PostgresNIO.PostgresDecodingContext +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:decoder:sqlLogLevel:) has parameter 4 type change from Swift.String? to Logging.Logger.Level +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:sqlLogLevel:) has been renamed to func postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:sqlLogLevel:) +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:sqlLogLevel:) has been renamed to func postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:sqlLogLevel:) +API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:decoder:sqlLogLevel:) has been renamed to func postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:decodingContext:sqlLogLevel:) +API breakage: func DatabaseConfigurationFactory.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:sqlLogLevel:) has been removed +API breakage: func DatabaseConfigurationFactory.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:decoder:sqlLogLevel:) has been removed From 034271f0de92f9605b573c1f07fdffe60434e0a7 Mon Sep 17 00:00:00 2001 From: Gwynne Raskind Date: Thu, 11 May 2023 12:55:48 -0500 Subject: [PATCH 3/3] Fix typos --- Sources/FluentPostgresDriver/FluentPostgresDatabase.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/FluentPostgresDriver/FluentPostgresDatabase.swift b/Sources/FluentPostgresDriver/FluentPostgresDatabase.swift index b2a2bdd..3ec68a7 100644 --- a/Sources/FluentPostgresDriver/FluentPostgresDatabase.swift +++ b/Sources/FluentPostgresDriver/FluentPostgresDatabase.swift @@ -65,7 +65,7 @@ extension _FluentPostgresDatabase: Database { return self.withConnection { conn in guard let sqlConn = conn as? any SQLDatabase else { fatalError(""" - Connection yieled by a Fluent+Postgres database is not also an SQLDatabase. + Connection yielded by a Fluent+Postgres database is not also an SQLDatabase. This is a bug in Fluent; please report it at https://github.com/vapor/fluent-postgres-driver/issues """) } @@ -124,7 +124,7 @@ extension _FluentPostgresDatabase: PostgresDatabase { func withConnection(_ closure: @escaping (PostgresConnection) -> EventLoopFuture) -> EventLoopFuture { guard let psqlDb: any PostgresDatabase = self.database as? any PostgresDatabase else { fatalError(""" - Connection yieled by a Fluent+Postgres database is not also a PostgresDatabase. + Connection yielded by a Fluent+Postgres database is not also a PostgresDatabase. This is a bug in Fluent; please report it at https://github.com/vapor/fluent-postgres-driver/issues """) }