Files
Media.JoshHeaps.Net/Media.JoshHeaps.Net/DbExecutor.cs
T
2026-01-02 17:13:39 -07:00

123 lines
3.8 KiB
C#

using Npgsql;
namespace Media.JoshHeaps.Net;
public class DbExecutor(IConfiguration config)
{
private string ConnectionString => config["connectionString"]!;
// Returns a single value (first column, first row)
public async Task<T?> ExecuteAsync<T>(string query, object? parameters = null)
{
parameters ??= new();
using var conn = new NpgsqlConnection(ConnectionString);
await conn.OpenAsync();
using var cmd = new NpgsqlCommand(query, conn);
// Add parameters if provided
foreach (var prop in parameters.GetType().GetProperties())
{
cmd.Parameters.AddWithValue($"@{prop.Name}", prop.GetValue(parameters) ?? DBNull.Value);
}
var result = await cmd.ExecuteScalarAsync();
if (result == null || result == DBNull.Value)
return default;
return (T)result;
}
// Returns a list of values (first column from all rows)
public async Task<List<T>> ExecuteListAsync<T>(string query, object? parameters = null)
{
parameters ??= new();
using var conn = new NpgsqlConnection(ConnectionString);
await conn.OpenAsync();
using var cmd = new NpgsqlCommand(query, conn);
foreach (var prop in parameters.GetType().GetProperties())
{
cmd.Parameters.AddWithValue($"@{prop.Name}", prop.GetValue(parameters) ?? DBNull.Value);
}
using var reader = await cmd.ExecuteReaderAsync();
List<T> results = [];
while (await reader.ReadAsync())
{
if (reader.IsDBNull(0))
continue;
results.Add((T)reader.GetValue(0));
}
return results;
}
// Returns a data reader for custom mapping (caller must dispose)
public async Task<T?> ExecuteReaderAsync<T>(string query, Func<NpgsqlDataReader, T?> mapper, object? parameters = null)
{
parameters ??= new();
using var conn = new NpgsqlConnection(ConnectionString);
await conn.OpenAsync();
using var cmd = new NpgsqlCommand(query, conn);
foreach (var prop in parameters.GetType().GetProperties())
{
cmd.Parameters.AddWithValue($"@{prop.Name}", prop.GetValue(parameters) ?? DBNull.Value);
}
using var reader = await cmd.ExecuteReaderAsync();
if (await reader.ReadAsync())
{
return mapper(reader);
}
return default;
}
// Returns a list using custom mapping
public async Task<List<T>> ExecuteListReaderAsync<T>(string query, Func<NpgsqlDataReader, T> mapper, object? parameters = null)
{
parameters ??= new();
using var conn = new NpgsqlConnection(ConnectionString);
await conn.OpenAsync();
using var cmd = new NpgsqlCommand(query, conn);
foreach (var prop in parameters.GetType().GetProperties())
{
cmd.Parameters.AddWithValue($"@{prop.Name}", prop.GetValue(parameters) ?? DBNull.Value);
}
using var reader = await cmd.ExecuteReaderAsync();
var results = new List<T>();
while (await reader.ReadAsync())
{
results.Add(mapper(reader));
}
return results;
}
// Executes a non-query command (INSERT, UPDATE, DELETE) and returns rows affected
public async Task<int> ExecuteNonQueryAsync(string query, object? parameters = null)
{
parameters ??= new();
using var conn = new NpgsqlConnection(ConnectionString);
await conn.OpenAsync();
using var cmd = new NpgsqlCommand(query, conn);
foreach (var prop in parameters.GetType().GetProperties())
{
cmd.Parameters.AddWithValue($"@{prop.Name}", prop.GetValue(parameters) ?? DBNull.Value);
}
return await cmd.ExecuteNonQueryAsync();
}
}