// 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}"); }