// 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; namespace Catalogger.Backend.Database.Dapper; public class DatabaseConnection(Guid id, ILogger logger, NpgsqlConnection inner) : DbConnection, IDisposable { public Guid ConnectionId => id; private readonly ILogger _logger = logger.ForContext(); private readonly DateTimeOffset _openTime = DateTimeOffset.UtcNow; 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(); var openFor = DateTimeOffset.UtcNow - _openTime; _logger.Verbose("Closing connection {ConnId}, open for {OpenFor}", ConnectionId, openFor); _hasClosed = true; await inner.CloseAsync(); } protected override async ValueTask BeginDbTransactionAsync( IsolationLevel isolationLevel, CancellationToken cancellationToken ) { _logger.Verbose("Beginning transaction on connection {ConnId}", ConnectionId); return await inner.BeginTransactionAsync(isolationLevel, cancellationToken); } public new void Dispose() { Close(); inner.Dispose(); GC.SuppressFinalize(this); } public override async ValueTask DisposeAsync() { await CloseAsync(); await inner.DisposeAsync(); GC.SuppressFinalize(this); } protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) => inner.BeginTransaction(isolationLevel); public override void ChangeDatabase(string databaseName) => inner.ChangeDatabase(databaseName); public override void Close() => inner.Close(); public override void Open() => inner.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(); }