// Copyright (C) 2021-present sam (starshines.gay)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
using System.Data;
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using Npgsql;
using Serilog;
namespace Catalogger.Backend.Database;
public class DatabaseConnection(NpgsqlConnection inner) : DbConnection, IDisposable
{
public NpgsqlConnection Inner => inner;
private bool _hasClosed;
public override async Task OpenAsync(CancellationToken cancellationToken) =>
await inner.OpenAsync(cancellationToken);
public override async Task CloseAsync()
{
if (_hasClosed)
{
await inner.CloseAsync();
return;
}
DatabasePool.DecrementConnections();
_hasClosed = true;
await inner.CloseAsync();
}
protected override async ValueTask BeginDbTransactionAsync(
IsolationLevel isolationLevel,
CancellationToken cancellationToken
) => await inner.BeginTransactionAsync(isolationLevel, cancellationToken);
public new void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected override void Dispose(bool disposing)
{
Log.Error("Called Dispose method on DbConnection, should call DisposeAsync!");
Log.Warning("CloseAsync will be called synchronously.");
CloseAsync().Wait();
inner.Dispose();
}
public override async ValueTask DisposeAsync()
{
await CloseAsync();
await inner.DisposeAsync();
GC.SuppressFinalize(this);
}
protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) =>
throw new SyncException(nameof(BeginDbTransaction));
public override void ChangeDatabase(string databaseName) => inner.ChangeDatabase(databaseName);
public override void Close() => throw new SyncException(nameof(Close));
public override void Open() => throw new SyncException(nameof(Open));
[AllowNull]
public override string ConnectionString
{
get => inner.ConnectionString;
set => inner.ConnectionString = value;
}
public override string Database => inner.Database;
public override ConnectionState State => inner.State;
public override string DataSource => inner.DataSource;
public override string ServerVersion => inner.ServerVersion;
protected override DbCommand CreateDbCommand() => inner.CreateCommand();
public class SyncException(string method) : Exception($"Tried to use sync method {method}");
}