New: Extend Postgres support to enable all connection string options

Signed-off-by: solidDoWant <fred.heinecke@yahoo.com>
This commit is contained in:
solidDoWant 2025-09-29 05:08:30 +00:00
parent ff6a69701f
commit d58f9adf01
No known key found for this signature in database
GPG key ID: 8FB1B42C043D666B
4 changed files with 86 additions and 6 deletions

View file

@ -9,6 +9,7 @@
using Npgsql; using Npgsql;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Options;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Datastore.Migration.Framework; using NzbDrone.Core.Datastore.Migration.Framework;
@ -179,6 +180,7 @@ protected void SetupContainer()
// Set up remaining container services // Set up remaining container services
Mocker.SetConstant(Options.Create(postgresOptions)); Mocker.SetConstant(Options.Create(postgresOptions));
Mocker.GetMock<IOptions<LogOptions>>().Setup(v => v.Value).Returns(new LogOptions());
Mocker.SetConstant<IConfigFileProvider>(Mocker.Resolve<ConfigFileProvider>()); Mocker.SetConstant<IConfigFileProvider>(Mocker.Resolve<ConfigFileProvider>());
Mocker.SetConstant<IConnectionStringFactory>(Mocker.Resolve<ConnectionStringFactory>()); Mocker.SetConstant<IConnectionStringFactory>(Mocker.Resolve<ConnectionStringFactory>());
Mocker.SetConstant<IMigrationController>(Mocker.Resolve<MigrationController>()); Mocker.SetConstant<IMigrationController>(Mocker.Resolve<MigrationController>());

View file

@ -65,6 +65,8 @@ public interface IConfigFileProvider : IHandleAsync<ApplicationStartedEvent>,
string PostgresPassword { get; } string PostgresPassword { get; }
string PostgresMainDb { get; } string PostgresMainDb { get; }
string PostgresLogDb { get; } string PostgresLogDb { get; }
string PostgresMainDbConnectionString { get; }
string PostgresLogDbConnectionString { get; }
string Theme { get; } string Theme { get; }
bool TrustCgnatIpAddresses { get; } bool TrustCgnatIpAddresses { get; }
} }
@ -251,6 +253,8 @@ public AuthenticationType AuthenticationMethod
public string PostgresMainDb => _postgresOptions?.MainDb ?? GetValue("PostgresMainDb", "radarr-main", persist: false); public string PostgresMainDb => _postgresOptions?.MainDb ?? GetValue("PostgresMainDb", "radarr-main", persist: false);
public string PostgresLogDb => _postgresOptions?.LogDb ?? GetValue("PostgresLogDb", "radarr-log", persist: false); public string PostgresLogDb => _postgresOptions?.LogDb ?? GetValue("PostgresLogDb", "radarr-log", persist: false);
public int PostgresPort => (_postgresOptions?.Port ?? 0) != 0 ? _postgresOptions.Port : GetValueInt("PostgresPort", 5432, persist: false); public int PostgresPort => (_postgresOptions?.Port ?? 0) != 0 ? _postgresOptions.Port : GetValueInt("PostgresPort", 5432, persist: false);
public string PostgresMainDbConnectionString => _postgresOptions?.MainDbConnectionString ?? GetValue("PostgresMainDbConnectionString", string.Empty, persist: false);
public string PostgresLogDbConnectionString => _postgresOptions?.LogDbConnectionString ?? GetValue("PostgresLogDbConnectionString", string.Empty, persist: false);
public bool LogDbEnabled => _logOptions.DbEnabled ?? GetValueBoolean("LogDbEnabled", true, persist: false); public bool LogDbEnabled => _logOptions.DbEnabled ?? GetValueBoolean("LogDbEnabled", true, persist: false);
public bool LogSql => _logOptions.Sql ?? GetValueBoolean("LogSql", false, persist: false); public bool LogSql => _logOptions.Sql ?? GetValueBoolean("LogSql", false, persist: false);
public int LogRotate => _logOptions.Rotate ?? GetValueInt("LogRotate", 50, persist: false); public int LogRotate => _logOptions.Rotate ?? GetValueInt("LogRotate", 50, persist: false);

View file

@ -17,16 +17,32 @@ public interface IConnectionStringFactory
public class ConnectionStringFactory : IConnectionStringFactory public class ConnectionStringFactory : IConnectionStringFactory
{ {
private readonly IConfigFileProvider _configFileProvider; private readonly IConfigFileProvider _configFileProvider;
private bool _usePostgres;
private bool _usePostgresConnectionStrings;
public ConnectionStringFactory(IAppFolderInfo appFolderInfo, IConfigFileProvider configFileProvider) public ConnectionStringFactory(IAppFolderInfo appFolderInfo, IConfigFileProvider configFileProvider)
{ {
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
MainDbConnection = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresMainDb) : ValidatePostgresOptions();
GetConnectionString(appFolderInfo.GetDatabase());
LogDbConnection = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresLogDb) : if (_usePostgres)
GetConnectionString(appFolderInfo.GetLogDatabase()); {
if (_usePostgresConnectionStrings)
{
MainDbConnection = GetPostgresConnectionInfoFromConnectionString(_configFileProvider.PostgresMainDbConnectionString);
LogDbConnection = GetPostgresConnectionInfoFromConnectionString(_configFileProvider.PostgresLogDbConnectionString);
return;
}
MainDbConnection = GetPostgresConnectionInfoFromIndividualValues(_configFileProvider.PostgresMainDb);
LogDbConnection = GetPostgresConnectionInfoFromIndividualValues(_configFileProvider.PostgresLogDb);
return;
}
// Default to sqlite
MainDbConnection = GetConnectionString(appFolderInfo.GetDatabase());
LogDbConnection = GetConnectionString(appFolderInfo.GetLogDatabase());
} }
public DatabaseConnectionInfo MainDbConnection { get; private set; } public DatabaseConnectionInfo MainDbConnection { get; private set; }
@ -60,9 +76,9 @@ private static DatabaseConnectionInfo GetConnectionString(string dbPath)
return new DatabaseConnectionInfo(DatabaseType.SQLite, connectionBuilder.ConnectionString); return new DatabaseConnectionInfo(DatabaseType.SQLite, connectionBuilder.ConnectionString);
} }
private DatabaseConnectionInfo GetPostgresConnectionString(string dbName) private DatabaseConnectionInfo GetPostgresConnectionInfoFromIndividualValues(string dbName)
{ {
var connectionBuilder = new NpgsqlConnectionStringBuilder var connectionBuilder = new NpgsqlConnectionStringBuilder()
{ {
Database = dbName, Database = dbName,
Host = _configFileProvider.PostgresHost, Host = _configFileProvider.PostgresHost,
@ -74,5 +90,61 @@ private DatabaseConnectionInfo GetPostgresConnectionString(string dbName)
return new DatabaseConnectionInfo(DatabaseType.PostgreSQL, connectionBuilder.ConnectionString); return new DatabaseConnectionInfo(DatabaseType.PostgreSQL, connectionBuilder.ConnectionString);
} }
private DatabaseConnectionInfo GetPostgresConnectionInfoFromConnectionString(string connectionString)
{
var connectionBuilder = new NpgsqlConnectionStringBuilder(connectionString)
{
Enlist = false
};
return new DatabaseConnectionInfo(DatabaseType.PostgreSQL, connectionBuilder.ConnectionString);
}
/// <summary>
/// Validates that either Postgres connection strings are both set or neither are set, and that either connection strings or
/// other Postgres settings are set, but not both.
/// </summary>
/// <exception cref="ArgumentException">Thrown when configuration is invalid.</exception>
private void ValidatePostgresOptions()
{
var isMainDBConnectionStringSet = !string.IsNullOrWhiteSpace(_configFileProvider.PostgresMainDbConnectionString);
var isLogDBConnectionStringSet = !string.IsNullOrWhiteSpace(_configFileProvider.PostgresLogDbConnectionString);
var isHostSet = !string.IsNullOrWhiteSpace(_configFileProvider.PostgresHost);
if (!isHostSet && !isMainDBConnectionStringSet && !isLogDBConnectionStringSet)
{
// No Postgres settings are set, so nothing to validate
return;
}
_usePostgres = true;
if (_configFileProvider.LogDbEnabled)
{
if (!isMainDBConnectionStringSet && isLogDBConnectionStringSet)
{
throw new ArgumentException("Postgres MainDbConnectionString is set but LogDbConnectionString is not. Both must be set or neither.");
}
if (isLogDBConnectionStringSet && !isMainDBConnectionStringSet)
{
throw new ArgumentException("Postgres LogDbConnectionString is set but MainDbConnectionString is not. Both must be set or neither.");
}
}
// At this point either all required connection strings are set or neither, so only one needs to be checked
var areConnectionStringConfigsSet = isMainDBConnectionStringSet;
// This one _must_ be set if connection strings are not being used, so it is used as a test to see if the user attempted configuration via individual settings
var areOtherPostgresConfigsSet = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace();
if (areConnectionStringConfigsSet && areOtherPostgresConfigsSet)
{
throw new ArgumentException($"Either both Postgres connection strings must be set, or the other Postgres settings must be set, but not both.");
}
_usePostgresConnectionStrings = areConnectionStringConfigsSet;
}
} }
} }

View file

@ -10,6 +10,8 @@ public class PostgresOptions
public string Password { get; set; } public string Password { get; set; }
public string MainDb { get; set; } public string MainDb { get; set; }
public string LogDb { get; set; } public string LogDb { get; set; }
public string MainDbConnectionString { get; set; }
public string LogDbConnectionString { get; set; }
public static PostgresOptions GetOptions() public static PostgresOptions GetOptions()
{ {