using Microsoft.Data.Sqlite; namespace NatsNet.PortTracker.Data; public sealed class Database : IDisposable { private readonly SqliteConnection _connection; public Database(string dbPath) { var connectionString = new SqliteConnectionStringBuilder { DataSource = dbPath, Mode = SqliteOpenMode.ReadWriteCreate, ForeignKeys = true }.ToString(); _connection = new SqliteConnection(connectionString); _connection.Open(); using var cmd = _connection.CreateCommand(); cmd.CommandText = "PRAGMA journal_mode=WAL;"; cmd.ExecuteNonQuery(); } public SqliteConnection Connection => _connection; public SqliteCommand CreateCommand(string sql) { var cmd = _connection.CreateCommand(); cmd.CommandText = sql; return cmd; } public int Execute(string sql, params (string name, object? value)[] parameters) { using var cmd = CreateCommand(sql); foreach (var (name, value) in parameters) cmd.Parameters.AddWithValue(name, value ?? DBNull.Value); return cmd.ExecuteNonQuery(); } public T? ExecuteScalar(string sql, params (string name, object? value)[] parameters) { using var cmd = CreateCommand(sql); foreach (var (name, value) in parameters) cmd.Parameters.AddWithValue(name, value ?? DBNull.Value); var result = cmd.ExecuteScalar(); if (result is null or DBNull) return default; return (T)Convert.ChangeType(result, typeof(T)); } public List> Query(string sql, params (string name, object? value)[] parameters) { using var cmd = CreateCommand(sql); foreach (var (name, value) in parameters) cmd.Parameters.AddWithValue(name, value ?? DBNull.Value); var results = new List>(); using var reader = cmd.ExecuteReader(); while (reader.Read()) { var row = new Dictionary(); for (int i = 0; i < reader.FieldCount; i++) { row[reader.GetName(i)] = reader.IsDBNull(i) ? null : reader.GetValue(i); } results.Add(row); } return results; } public int ExecuteInTransaction(string sql, params (string name, object? value)[] parameters) { using var transaction = _connection.BeginTransaction(); try { using var cmd = CreateCommand(sql); cmd.Transaction = transaction; foreach (var (name, value) in parameters) cmd.Parameters.AddWithValue(name, value ?? DBNull.Value); var affected = cmd.ExecuteNonQuery(); transaction.Commit(); return affected; } catch { transaction.Rollback(); throw; } } public void Dispose() { _connection.Dispose(); } }