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