package database import ( "database/sql" "log" _ "modernc.org/sqlite" ) type DB struct { db *sql.DB } func New() *DB { d := &DB{} con, err := sql.Open("sqlite", "./todogo.db") if err != nil { log.Fatal(err) } d.db = con err = d.init() if err != nil { log.Fatal(err) } return d } func (d *DB) init() error { d.migrate() return nil } func (d *DB) InsertTodo(title string) error { _, err := d.db.Exec("INSERT INTO todos(title, completed) VALUES(?, ?)", title, 0) return err } func (d *DB) ToggleTodo(id int) error { _, err := d.db.Exec(` UPDATE todos SET completed = (CASE WHEN completed = 0 THEN 1 ELSE 0 END) WHERE id = ? `, id) return err } func (d *DB) DeleteTodo(id int) error { _, err := d.db.Exec("DELETE FROM todos WHERE id = ?", id) return err } func (d *DB) GetAllTodos() ([]*Todo, error) { rows, err := d.db.Query("SELECT id, title, completed FROM todos") if err != nil { return nil, err } defer rows.Close() todos := scanTodos(rows) return todos, nil } func (d *DB) GetTodosByCompleted(completed bool) ([]*Todo, error) { completedInt := 0 if completed { completedInt = 1 } rows, err := d.db.Query("SELECT id, title, completed FROM todos WHERE completed = ?", completedInt) if err != nil { return nil, err } defer rows.Close() todos := scanTodos(rows) return todos, nil } func (d *DB) GetIncompleteTodosCount() int { row := d.db.QueryRow("SELECT COUNT(*) FROM todos WHERE completed = 0") var count int err := row.Scan(&count) if err != nil { log.Printf("failed to get incomplete count") return 0 } return count } func (d *DB) DeleteCompletedTodos() error { _, err := d.db.Exec("DELETE FROM todos WHERE completed = 1") return err } func scanTodos(rows *sql.Rows) []*Todo { var todos []*Todo for rows.Next() { t := scanTodo(rows) if t != nil { todos = append(todos, t) } } return todos } func scanTodo(row *sql.Rows) *Todo { t := new(Todo) err := row.Scan(&t.Id, &t.Title, &t.Completed) if err != nil { log.Printf("Failed to read row %s", err) return nil } return t } type Todo struct { Id int Title string Completed bool }