using System.Data;
using Microsoft.Data.SqlClient;
namespace ZA.CoreService.ESBCertificateManager.Services;
///
/// Stellt sicher, dass optionale Schema-Patches auf bestehenden Datenbanken
/// angewendet wurden (z. B. SonicContainer.CertificateCheckUrl).
///
public static class DatabaseSchemaPatcher
{
private static readonly string[] LegacyCertificateCheckUrlColumns =
[
"vertifiaktechecurl",
"VerifyCertificateCheckCurl",
"CertificateCheckCurl",
"ZertifikatCheckCurl"
];
private static bool? _hasCertificateCheckUrlColumn;
public static async Task EnsureCertificateCheckUrlColumnAsync(
string connectionString,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(connectionString))
{
return;
}
await using SqlConnection connection = new(connectionString);
await connection.OpenAsync(cancellationToken);
if (await ColumnExistsAsync(
connection,
"CertificateCheckUrl",
cancellationToken))
{
_hasCertificateCheckUrlColumn = true;
return;
}
foreach (string legacyColumn in LegacyCertificateCheckUrlColumns)
{
if (!await ColumnExistsAsync(
connection,
legacyColumn,
cancellationToken))
{
continue;
}
await using SqlCommand renameCommand = new(
"""
EXEC sp_rename
N'dbo.SonicContainer.LEGACY_COLUMN',
N'CertificateCheckUrl',
N'COLUMN';
"""
.Replace(
"LEGACY_COLUMN",
legacyColumn,
StringComparison.Ordinal),
connection);
await renameCommand.ExecuteNonQueryAsync(cancellationToken);
_hasCertificateCheckUrlColumn = true;
return;
}
const string addColumnSql = """
ALTER TABLE [dbo].[SonicContainer]
ADD [CertificateCheckUrl] [nvarchar](500) NULL;
""";
await using SqlCommand addCommand = new(addColumnSql, connection);
await addCommand.ExecuteNonQueryAsync(cancellationToken);
_hasCertificateCheckUrlColumn = true;
}
public static async Task HasCertificateCheckUrlColumnAsync(
string connectionString,
CancellationToken cancellationToken = default)
{
if (_hasCertificateCheckUrlColumn is bool cached)
{
return cached;
}
if (string.IsNullOrWhiteSpace(connectionString))
{
return false;
}
await using SqlConnection connection = new(connectionString);
await connection.OpenAsync(cancellationToken);
_hasCertificateCheckUrlColumn = await ColumnExistsAsync(
connection,
"CertificateCheckUrl",
cancellationToken);
return _hasCertificateCheckUrlColumn.Value;
}
private static async Task ColumnExistsAsync(
SqlConnection connection,
string columnName,
CancellationToken cancellationToken)
{
await using SqlCommand command = new(
"SELECT COL_LENGTH(N'dbo.SonicContainer', @ColumnName);",
connection);
command.Parameters.Add(
new SqlParameter("@ColumnName", SqlDbType.NVarChar, 128)
{
Value = columnName
});
object? result =
await command.ExecuteScalarAsync(cancellationToken);
return result is not null and not DBNull;
}
}