feat(data,worker): add db schema init and signalr hub skeleton
Data layer: Paths helper with ~/%USERPROFILE% expansion, SqliteConnectionFactory (WAL + foreign keys), SchemaInitializer that applies the embedded schema.sql, and POCO entities for lists/tasks/tags/worktrees. Worker: WorkerConfig loader (~/.todo-app/worker.config.json with defaults), WorkerHub exposing Ping(), and Program.cs wiring Kestrel to 127.0.0.1:<port>, SignalR at /hub, schema applied on startup. Pins Microsoft.Data.Sqlite and Microsoft.Extensions.Hosting to 8.x for net8.0 compatibility. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
41
src/ClaudeDo.Data/SchemaInitializer.cs
Normal file
41
src/ClaudeDo.Data/SchemaInitializer.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Reflection;
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
||||
namespace ClaudeDo.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Applies the embedded schema.sql script. Safe to call on every start — the script uses
|
||||
/// IF NOT EXISTS / INSERT OR IGNORE.
|
||||
/// </summary>
|
||||
public static class SchemaInitializer
|
||||
{
|
||||
private const string ResourceName = "ClaudeDo.Data.schema.sql";
|
||||
|
||||
public static void Apply(SqliteConnectionFactory factory)
|
||||
{
|
||||
using var conn = factory.Open();
|
||||
ApplyTo(conn);
|
||||
}
|
||||
|
||||
public static void ApplyTo(SqliteConnection conn)
|
||||
{
|
||||
var sql = LoadScript();
|
||||
using var tx = conn.BeginTransaction();
|
||||
using var cmd = conn.CreateCommand();
|
||||
cmd.Transaction = tx;
|
||||
cmd.CommandText = sql;
|
||||
cmd.ExecuteNonQuery();
|
||||
tx.Commit();
|
||||
}
|
||||
|
||||
private static string LoadScript()
|
||||
{
|
||||
var asm = typeof(SchemaInitializer).Assembly;
|
||||
using var stream = asm.GetManifestResourceStream(ResourceName)
|
||||
?? throw new InvalidOperationException(
|
||||
$"Embedded resource '{ResourceName}' not found in {asm.GetName().Name}. " +
|
||||
$"Available: {string.Join(", ", asm.GetManifestResourceNames())}");
|
||||
using var reader = new StreamReader(stream);
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user