package main import ( "database/sql" "encoding/json" "net/http" "strconv" "github.com/go-chi/chi/v5" ) func createTodo(db *sql.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var input CreateTodo if err := json.NewDecoder(r.Body).Decode(&input); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } priority := int64(1) if input.Priority != nil { priority = *input.Priority } status := "pending" if input.Status != nil { status = *input.Status } var todo Todo err := db.QueryRow( `INSERT INTO todos (title, description, due_date, priority, status) VALUES (?, ?, ?, ?, ?) RETURNING id, title, description, due_date, priority, status`, input.Title, input.Description, input.DueDate, priority, status, ).Scan(&todo.ID, &todo.Title, &todo.Description, &todo.DueDate, &todo.Priority, &todo.Status) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(todo) } } func listTodos(db *sql.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { rows, err := db.Query("SELECT id, title, description, due_date, priority, status FROM todos") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer rows.Close() var todos []Todo for rows.Next() { var t Todo if err := rows.Scan(&t.ID, &t.Title, &t.Description, &t.DueDate, &t.Priority, &t.Status); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } todos = append(todos, t) } if todos == nil { todos = []Todo{} } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(todos) } } func getTodo(db *sql.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) var todo Todo err := db.QueryRow( "SELECT id, title, description, due_date, priority, status FROM todos WHERE id = ?", id, ).Scan(&todo.ID, &todo.Title, &todo.Description, &todo.DueDate, &todo.Priority, &todo.Status) if err == sql.ErrNoRows { http.Error(w, "not found", http.StatusNotFound) return } if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(todo) } } func updateTodo(db *sql.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) var existing Todo err := db.QueryRow( "SELECT id, title, description, due_date, priority, status FROM todos WHERE id = ?", id, ).Scan(&existing.ID, &existing.Title, &existing.Description, &existing.DueDate, &existing.Priority, &existing.Status) if err == sql.ErrNoRows { http.Error(w, "not found", http.StatusNotFound) return } if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } var input UpdateTodo if err := json.NewDecoder(r.Body).Decode(&input); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if input.Title != nil { existing.Title = *input.Title } if input.Description != nil { existing.Description = input.Description } if input.DueDate != nil { existing.DueDate = input.DueDate } if input.Priority != nil { existing.Priority = *input.Priority } if input.Status != nil { existing.Status = *input.Status } var updated Todo err = db.QueryRow( `UPDATE todos SET title = ?, description = ?, due_date = ?, priority = ?, status = ? WHERE id = ? RETURNING id, title, description, due_date, priority, status`, existing.Title, existing.Description, existing.DueDate, existing.Priority, existing.Status, id, ).Scan(&updated.ID, &updated.Title, &updated.Description, &updated.DueDate, &updated.Priority, &updated.Status) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(updated) } } func deleteTodo(db *sql.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) result, err := db.Exec("DELETE FROM todos WHERE id = ?", id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } rows, _ := result.RowsAffected() if rows == 0 { http.Error(w, "not found", http.StatusNotFound) return } w.WriteHeader(http.StatusNoContent) } }