feat(porttracker): add DB access layer and init command
Add Database.cs with SQLite connection management and helper methods (Execute, ExecuteScalar, Query), Schema.cs for schema initialization, and replace default Program.cs with System.CommandLine v3 CLI featuring global --db/--schema options and an init command.
This commit is contained in:
77
tools/NatsNet.PortTracker/Data/Database.cs
Normal file
77
tools/NatsNet.PortTracker/Data/Database.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
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<T>(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<Dictionary<string, object?>> 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<Dictionary<string, object?>>();
|
||||
using var reader = cmd.ExecuteReader();
|
||||
while (reader.Read())
|
||||
{
|
||||
var row = new Dictionary<string, object?>();
|
||||
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 void Dispose()
|
||||
{
|
||||
_connection.Dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user