filename:
assistant/memory/sqlite.go
branch:
main
back to repo
package memory
import (
"database/sql"
"fmt"
"path/filepath"
_ "modernc.org/sqlite"
)
// Open opens the SQLite database at path and applies schema.
func Open(path string) (*sql.DB, error) {
abs, err := filepath.Abs(path)
if err != nil {
return nil, err
}
dsn := "file:" + filepath.ToSlash(abs) + "?_pragma=busy_timeout(5000)&_pragma=foreign_keys(ON)"
db, err := sql.Open("sqlite", dsn)
if err != nil {
return nil, err
}
if err := db.Ping(); err != nil {
_ = db.Close()
return nil, err
}
if err := migrate(db); err != nil {
_ = db.Close()
return nil, err
}
return db, nil
}
func migrate(db *sql.DB) error {
stmts := []string{
`CREATE TABLE IF NOT EXISTS memories (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);`,
`CREATE TABLE IF NOT EXISTS calendar_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
notes TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'open' CHECK(status IN ('open','done','cancelled')),
due_at TEXT,
source TEXT NOT NULL DEFAULT 'manual' CHECK(source IN ('manual','agent')),
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);`,
`CREATE INDEX IF NOT EXISTS idx_cal_due ON calendar_items(due_at);`,
`CREATE TABLE IF NOT EXISTS calendar_pending (
id INTEGER PRIMARY KEY AUTOINCREMENT,
payload_json TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending','applied','rejected','expired')),
created_at TEXT NOT NULL DEFAULT (datetime('now')),
expires_at TEXT NOT NULL
);`,
`CREATE INDEX IF NOT EXISTS idx_cal_pending_status ON calendar_pending(status);`,
`CREATE TABLE IF NOT EXISTS calendar_meta (
k TEXT PRIMARY KEY,
v INTEGER NOT NULL DEFAULT 0
);`,
`INSERT OR IGNORE INTO calendar_meta (k, v) VALUES ('revision', 0);`,
}
for _, s := range stmts {
if _, err := db.Exec(s); err != nil {
return fmt.Errorf("migrate: %w", err)
}
}
return nil
}