package database import ( "database/sql" "fmt" _ "modernc.org/sqlite" ) type DB struct { conn *sql.DB } func New(dbPath string) (*DB, error) { conn, err := sql.Open("sqlite", dbPath+"?_pragma=journal_mode(WAL)&_pragma=busy_timeout(5000)") if err != nil { return nil, fmt.Errorf("opening database: %w", err) } db := &DB{conn: conn} if err := db.migrate(); err != nil { conn.Close() return nil, fmt.Errorf("running migrations: %w", err) } return db, nil } func (db *DB) Close() error { return db.conn.Close() } func (db *DB) migrate() error { schema := ` CREATE TABLE IF NOT EXISTS tasks ( id TEXT PRIMARY KEY, status TEXT NOT NULL DEFAULT 'pending', language TEXT NOT NULL, proto_repo TEXT NOT NULL, proto_branch TEXT NOT NULL, proto_commit TEXT NOT NULL DEFAULT '', target_repo TEXT NOT NULL, toolchain_image TEXT NOT NULL, image_digest TEXT NOT NULL DEFAULT '', result_commit TEXT NOT NULL DEFAULT '', error TEXT NOT NULL DEFAULT '', log TEXT NOT NULL DEFAULT '', retries INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS idx_tasks_running_per_repo ON tasks(target_repo) WHERE status = 'running'; CREATE TABLE IF NOT EXISTS toolchain_versions ( language TEXT PRIMARY KEY, image_tag TEXT NOT NULL, enabled INTEGER NOT NULL DEFAULT 1, updated_at TEXT NOT NULL ); ` _, err := db.conn.Exec(schema) return err } func (db *DB) Conn() *sql.DB { return db.conn }