using System; using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Linq; using System.Linq.Dynamic.Core; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; using Dapper; using GB5Shared.DTO.Framework.Login; using Microsoft.Data.SqlClient; namespace GB5Shared.QueryExecutor { /// /// Defines the contract for executing database queries and commands. /// This interface supports both automatic connection management (single calls) /// and explicit transaction management (multiple calls on a single connection). /// public interface IQueryExecutor { #region Transaction Management /// /// Begins a new database transaction and returns the connection and transaction objects. /// /// Important: This method creates a new, dedicated connection for this transaction. /// You must pass the returned object to subsequent Query/Execute calls /// to ensure they run on this specific connection. This allows multiple transactions to run /// concurrently on different connections. /// /// /// The login context containing database connection details. /// A tuple containing the active and . Task< DbTransaction> BeginTransactionAsync(LoginDTO LoginDTO); /// /// Commits the active transaction and disposes the associated connection. /// /// The connection object returned by . /// The transaction object returned by . Task CommitAsync(DbTransaction transaction); /// /// Rolls back the active transaction and disposes the associated connection. /// /// The connection object returned by . /// The transaction object returned by . Task RollbackAsync( DbTransaction transaction); #endregion #region Standard Query & Execute (Automatic Transaction Support) /// /// Fetches a single record as a DTO based on the SQL query. /// /// The type of DTO. /// Login context for connection resolution. /// The SQL query string. /// Optional parameters for the SQL query. /// /// Optional. If provided, the query executes on this specific transaction/connection. /// If null, a temporary connection is created and closed automatically. /// /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED /// to the query, allowing dirty reads for non-critical, high-throughput read scenarios. /// WARNING: READ UNCOMMITTED may return dirty reads — uncommitted, /// potentially rolled-back data from concurrent transactions. Never use for financial, /// inventory, or any data that must be consistent. Ignored when an external /// is supplied. /// /// A single DTO or default(T) if no match is found. Task QuerySingleAsync(LoginDTO LoginDTO, string sql, object parameters = null!, DbTransaction? transaction = null, bool useReadUncommitted = false, CancellationToken cancellationToken = default); /// /// Fetches multiple records as a list of DTOs based on the SQL query. /// /// The type of DTO. /// Login context for connection resolution. /// The SQL query string. /// Optional parameters for the SQL query. /// /// Optional. If provided, the query executes on this specific transaction/connection. /// If null, a temporary connection is created and closed automatically. /// /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED /// to the query. See for full dirty-read warning. /// Ignored when an external is supplied. /// /// A list of DTOs. Task> QueryAsync( LoginDTO LoginDTO, string sql, object parameters = null!, DbTransaction? transaction = null, bool useReadUncommitted = false, CancellationToken cancellationToken = default ); /// /// Executes a SQL command (INSERT, UPDATE, DELETE, etc.) and returns the number of affected rows. /// /// Login context for connection resolution. /// The SQL command string. /// Optional parameters for the SQL command. /// /// Optional. If provided, the command executes on this specific transaction/connection. /// If null, a temporary connection is created and closed automatically. /// /// The number of rows affected. Task ExecuteAsync(LoginDTO LoginDTO, string sql, object parameters = null!, DbTransaction? transaction = null, CancellationToken cancellationToken = default); /// /// Executes a SQL command using an explicit transaction and connection, /// typically used after manually retrieving a transaction. /// /// The SQL command string. /// Parameters for the SQL command. /// The explicit transaction to use. /// The number of rows affected. Task ExecuteAsync(string sql, object param, DbTransaction transaction); /// /// Executes a command and returns the database-generated identity (ID) value (e.g., SCOPE_IDENTITY()). /// /// Login context for connection resolution. /// The INSERT SQL statement. /// Optional parameters. /// Optional transaction to enlist in. /// The generated ID of the inserted record. Task ExecuteIdentityAsync(LoginDTO loginDTO, string sql, object? parameters = null, DbTransaction? transaction = null); /// /// Executes a query and returns the first column of the first row (e.g., COUNT, SUM). /// /// The return type. /// Login context. /// The SQL query. /// Optional parameters. /// Optional transaction to enlist in. /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. /// See for full dirty-read warning. /// Ignored when an external is supplied. /// /// The scalar value. Task ExecuteScalarAsync(LoginDTO loginDTO, string sql, object? parameters = null, DbTransaction? transaction = null, bool useReadUncommitted = false, CancellationToken cancellationToken = default); #endregion #region Streaming & Bulk Operations /// /// Streams the results of a query asynchronously, suitable for large datasets. /// Uses CommandBehavior.SequentialAccess for efficient memory usage. /// /// The type of DTO. /// Login context. /// The SQL query string. /// Optional parameters. /// Optional transaction to enlist in. /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. /// See for full dirty-read warning. /// Ignored when an external is supplied. /// /// An asynchronous stream of DTOs. /// /// WARNING: This method buffers the full result set in memory before yielding. /// For true row-by-row streaming on large result sets (>5 000 rows), use /// which uses a DataReader with SequentialAccess. /// IAsyncEnumerable StreamAsync( LoginDTO LoginDTO, string sql, object parameters = null!, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default, DbTransaction? transaction = null, bool useReadUncommitted = false ); /// /// Streams query results asynchronously using a DataReader, ideal for processing large result sets row-by-row. /// /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. /// See for full dirty-read warning. /// Ignored when an external is supplied. /// IAsyncEnumerable QueryStreamAsync( LoginDTO LoginDTO, string sql, object parameters = null!, [EnumeratorCancellation] CancellationToken cancellationToken = default, DbTransaction? transaction = null, bool useReadUncommitted = false ); /// /// Executes a bulk insert for a collection of DTOs in a single roundtrip if possible. /// /// The type of DTO. /// Login context. /// The SQL insert statement. /// The collection of items to insert. /// Optional transaction to enlist in. /// The number of rows affected. Task BulkInsertAsync(LoginDTO LoginDTO, string sql, IEnumerable items, DbTransaction? transaction = null); /// /// Performs a bulk insert using Table-Valued Parameters (TVP). Specific to SQL Server. /// Task BulkInsertMultipleAsync( LoginDTO loginDTO, string commandText, Dictionary tvpParameters ); #endregion #region Specialized Query Methods /// /// Fetches records in a paginated fashion. /// Executes the main query and a COUNT query to determine total records. /// /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. /// See for full dirty-read warning. /// Ignored when an external is supplied. /// Task> QueryPagedAsync( LoginDTO LoginDTO, string sql, object parameters = null!, DbTransaction? transaction = null, bool useReadUncommitted = false ); /// /// Executes a query mapping two related tables (Join) into a single DTO hierarchy. /// /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. /// See for full dirty-read warning. /// Ignored when an external is supplied. /// Task> QueryMultiMapAsync( LoginDTO loginDTO, string sql, Func map, object parameters = null!, string splitOn = "Id", DbTransaction? transaction = null, bool useReadUncommitted = false ); /// /// Executes a query mapping three related tables (Join) into a single DTO hierarchy. /// /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. /// See for full dirty-read warning. /// Ignored when an external is supplied. /// Task> QueryMultiMapAsync( LoginDTO loginDTO, string sql, Func map, object parameters = null!, string splitOn = "Id,Id", DbTransaction? transaction = null, bool useReadUncommitted = false ); /// /// Executes a query mapping five related tables. /// /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. /// See for full dirty-read warning. /// Ignored when an external is supplied. /// Task> QueryMultiMapAsync( LoginDTO loginDTO, string sql, Func map, object parameters = null!, string splitOn = "Id,Id,Id,Id", DbTransaction? transaction = null, bool useReadUncommitted = false ); /// /// Executes a query mapping seven related tables. /// /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. /// See for full dirty-read warning. /// Ignored when an external is supplied. /// Task> QueryMultiMapAsync( LoginDTO loginDTO, string sql, Func map, object parameters = null!, string splitOn = "Id,Id,Id,Id,Id,Id", DbTransaction? transaction = null, bool useReadUncommitted = false ); /// /// Executes a query and maps results to an array structure. /// /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. /// See for full dirty-read warning. /// Ignored when an external is supplied. /// Task> QueryAsyncArray( LoginDTO loginDTO, string sql, Func map, object parameters = null!, string splitOn = "Id", DbTransaction? transaction = null, bool useReadUncommitted = false ); /// /// Executes a COUNT query based on a provided SQL query string. /// Can wrap the query or use the query directly if it is already a count query. /// /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. /// See for full dirty-read warning. /// Ignored when an external is supplied. /// Task TotalCountSql( string sqlQuery, LoginDTO loginDTO, object? parameters = null, bool isCountQuery = false, DbTransaction? transaction = null, bool useReadUncommitted = false ); /// /// Executes a query returning an asynchronous enumerable. /// /// /// Optional. When true, prepends SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. /// See for full dirty-read warning. /// Ignored when an external is supplied. /// IAsyncEnumerable ExecuteQueryAsync( LoginDTO LoginDTO, string sql, object parameters = null!, DbTransaction? transaction = null, bool useReadUncommitted = false ); #endregion #region Connection Name & Procedures /// /// Fetches data using a specific named connection string (defined in configuration), /// separate from the default LoginDTO connection. /// Task> QueryAsync( string ConnectionName, string sql, object parameters = null! ); /// /// Executes a list of Stored Procedures and returns a list of string status messages. /// Each procedure execution is treated as a step. /// Task> ProcedureExecuteAsync( LoginDTO loginDTO, IEnumerable<(string ProcedureName, object Param)> procedures ); /// /// Executes a Count query specifically designed for TVP scenarios. /// Task ExecuteTvpCountQueryAsync( LoginDTO loginDTO, string sqlQuery, Dictionary tvpParameters ); #endregion #region Legacy Session Methods (HttpContext Based) /// /// Executes a query within a "Session" managed by HttpContext Items. /// Note: This relies on the HTTP context and may not work in background tasks. /// Consider using explicit transactions () for better control. /// Task> SessionQueryAsync(LoginDTO loginDTO, string sql, object param = null!); /// /// Fetches a single result within a "Session" managed by HttpContext. /// Task SessionQuerySingleAsync(LoginDTO loginDTO, string sql, object param = null!); /// /// Executes a command within a "Session" managed by HttpContext. /// Task SessionExecuteAsync(LoginDTO loginDTO, string sql, object param = null!); /// /// Commits the transaction stored in the current HttpContext Session. /// Task SameSessionCommitAsync(); /// /// Rolls back the transaction stored in the current HttpContext Session. /// Task SameSessionRollbackAsync(); #endregion #region Helper Methods /// /// Executes a list of SQL statements inside a single isolated transaction. /// This method manages the connection and transaction lifecycle internally. /// Task ExecuteInTransactionAsync( LoginDTO LoginDTO, IEnumerable<(string sql, object param)> statements ); Task QueryMultipleAsync( LoginDTO loginDTO, string sql, object parameters = null!, DbTransaction? transaction = null ); Task QueryMultipleAsync( LoginDTO loginDTO, string sql, object parameters = null!, DbTransaction? transaction = null, CommandType commandType = CommandType.StoredProcedure); #endregion } }