using System.Data.Common; using System.Runtime.CompilerServices; using Dapper; using FruityFoundation.Base.Structures; using FruityFoundation.DataAccess.Abstractions; namespace FruityFoundation.DataAccess.Core; // ReSharper disable once ClassWithVirtualMembersNeverInherited.Global public class DbTransaction : IDatabaseTransactionConnection where TConnectionType : ConnectionType { private readonly DbTransaction _transaction; internal DbTransaction(DbTransaction transaction) { _transaction = transaction; } /// public async Task> Query( string sql, object? param = null, CancellationToken cancellationToken = default ) { if (_transaction.Connection is not { } conn) throw new InvalidOperationException("Transaction connection cannot be null"); var command = new CommandDefinition(sql, param, transaction: _transaction, cancellationToken: cancellationToken); return await conn.QueryAsync(command); } /// public async IAsyncEnumerable QueryUnbuffered( string sql, object? param = null, [EnumeratorCancellation] CancellationToken cancellationToken = default ) { if (_transaction.Connection is not { } conn) throw new InvalidOperationException("Transaction connection cannot be null"); var query = conn.QueryUnbufferedAsync(sql, param, transaction: _transaction) .WithCancellation(cancellationToken); await foreach (var item in query) yield return item; } /// public async Task QuerySingle(string sql, object? param = null, CancellationToken cancellationToken = default) { if (_transaction.Connection is not { } conn) throw new InvalidOperationException("Transaction connection cannot be null"); var command = new CommandDefinition(sql, param, transaction: _transaction, cancellationToken: cancellationToken); return await conn.QuerySingleAsync(command); } /// public async Task> TryQueryFirst(string sql, object? param = null, CancellationToken cancellationToken = default) { if (_transaction.Connection is not { } conn) throw new InvalidOperationException("Transaction connection cannot be null"); return await conn.QueryUnbufferedAsync(sql, param, transaction: _transaction) .FirstOrEmptyAsync(cancellationToken); } /// public async Task Execute(string sql, object? param = null, CancellationToken cancellationToken = default) { if (_transaction.Connection is not { } conn) throw new InvalidOperationException("Transaction connection cannot be null"); var command = new CommandDefinition(sql, param, transaction: _transaction, cancellationToken: cancellationToken); await conn.ExecuteAsync(command); } /// public async Task ExecuteScalar(string sql, object? param = null, CancellationToken cancellationToken = default) { if (_transaction.Connection is not { } conn) throw new InvalidOperationException("Transaction connection cannot be null"); var command = new CommandDefinition(sql, param, transaction: _transaction, cancellationToken: cancellationToken); return await conn.ExecuteScalarAsync(command); } /// public async Task ExecuteReader( string sql, object? param = null, CancellationToken cancellationToken = default ) { if (_transaction.Connection is not { } conn) throw new InvalidOperationException("Transaction connection cannot be null"); var command = new CommandDefinition(sql, param, transaction: _transaction, cancellationToken: cancellationToken); return await conn.ExecuteReaderAsync(command); } /// public async Task Commit(CancellationToken cancellationToken) { await _transaction.CommitAsync(cancellationToken); } /// public async Task Rollback(CancellationToken cancellationToken) { await _transaction.RollbackAsync(cancellationToken); } protected virtual void Dispose(bool disposing) { if (disposing) { #pragma warning disable IDISP007 _transaction.Dispose(); #pragma warning restore IDISP007 } } /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual async ValueTask DisposeAsyncCore() { #pragma warning disable IDISP007 await _transaction.DisposeAsync(); #pragma warning restore IDISP007 } /// public async ValueTask DisposeAsync() { await DisposeAsyncCore(); GC.SuppressFinalize(this); } }