using Microsoft.Extensions.Hosting; namespace Tau.Acuvim.Portal.Configuration; public static class ConnectionStringResolver { public sealed record Resolution(string ConnectionString, string Source); // Precedence: // 1. Database.ConnectionString (explicit) — always wins. // 2. Database.AutoProvisionLocalTimescaleDb == true AND env != Production — build from TimescaleDb block. // 3. Otherwise — throw. Production must supply an explicit connection string. public static Resolution Resolve( DatabaseOptions database, TimescaleDbOptions timescale, IHostEnvironment env) { if (!string.IsNullOrWhiteSpace(database.ConnectionString)) { return new Resolution(database.ConnectionString, "Database:ConnectionString"); } if (database.AutoProvisionLocalTimescaleDb && !env.IsProduction()) { var built = $"Host={timescale.Host};Port={timescale.Port};Database={timescale.Database};" + $"Username={timescale.Username};Password={timescale.Password}"; return new Resolution(built, "auto-provision from TimescaleDb section"); } if (database.AutoProvisionLocalTimescaleDb && env.IsProduction()) { throw new InvalidOperationException( "AutoProvisionLocalTimescaleDb=true is not permitted in Production. " + "Set Database:ConnectionString explicitly via env var or secret."); } throw new InvalidOperationException( "No database connection string available. Set Database:ConnectionString, " + "or enable Database:AutoProvisionLocalTimescaleDb in a non-Production environment."); } }