package storage import ( "database/sql" "time" _ "github.com/mattn/go-sqlite3" ) // DB wraps sql.DB type DB struct { conn *sql.DB } // Default is the package-level DB used by handlers var Default *DB // Init opens the sqlite database at path and ensures the table exists func Init(path string) (*DB, error) { conn, err := sql.Open("sqlite3", path) if err != nil { return nil, err } // set reasonable pragmas if _, err := conn.Exec("PRAGMA journal_mode=WAL;"); err != nil { // ignore } schema := `CREATE TABLE IF NOT EXISTS messages ( message TEXT NOT NULL, timestamp TEXT NOT NULL );` if _, err := conn.Exec(schema); err != nil { conn.Close() return nil, err } return &DB{conn: conn}, nil } // SetDefault sets the package default DB func SetDefault(d *DB) { Default = d } // Close closes the underlying connection func (d *DB) Close() error { if d == nil || d.conn == nil { return nil } return d.conn.Close() } // InsertMessage inserts a message with timestamp into the DB func (d *DB) InsertMessage(msg string, ts time.Time) error { if d == nil || d.conn == nil { return nil } _, err := d.conn.Exec("INSERT INTO messages(message, timestamp) VALUES(?, ?)", msg, ts.Format(time.RFC3339)) return err } // Message is the returned message shape type Message struct { Message string `json:"message"` Timestamp string `json:"timestamp"` } // QueryMessages returns messages ordered by newest first func (d *DB) QueryMessages(limit, offset int) ([]Message, error) { if d == nil || d.conn == nil { return nil, nil } rows, err := d.conn.Query("SELECT message, timestamp FROM messages ORDER BY rowid DESC LIMIT ? OFFSET ?", limit, offset) if err != nil { return nil, err } defer rows.Close() res := []Message{} for rows.Next() { var m Message if err := rows.Scan(&m.Message, &m.Timestamp); err != nil { return nil, err } res = append(res, m) } return res, nil }