Implement task management commands: add, list, done, undo, remove
This commit is contained in:
308
main.go
308
main.go
@@ -38,15 +38,118 @@ func init() {
|
||||
log.Fatal("Unable to ping database:", err)
|
||||
}
|
||||
|
||||
fmt.Println("Connected to PostgreSQL database!")
|
||||
// fmt.Println("Connected to PostgreSQL database!")
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := &cli.App{
|
||||
Name: "Go Todo App",
|
||||
Name: "gotodo",
|
||||
Usage: "A simple CLI program to manage your tasks",
|
||||
Action: func(c *cli.Context) error {
|
||||
tasks, err := getPendingTasks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Pending Tasks:")
|
||||
printTasks(tasks)
|
||||
return nil
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
// We'll add commands here
|
||||
{
|
||||
Name: "add",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Add a new task",
|
||||
Action: func(c *cli.Context) error {
|
||||
text := c.Args().First()
|
||||
if text == "" {
|
||||
return fmt.Errorf("task text cannot be empty")
|
||||
}
|
||||
return createTask(text)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List tasks with filters",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{Name: "all", Aliases: []string{"a"}, Usage: "List all tasks"},
|
||||
&cli.BoolFlag{Name: "completed", Aliases: []string{"c"}, Usage: "List only completed tasks"},
|
||||
&cli.BoolFlag{Name: "pending", Aliases: []string{"p"}, Usage: "List only pending tasks"},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
var tasks []Task
|
||||
var err error
|
||||
title := "Pending Tasks:"
|
||||
|
||||
if c.Bool("all") {
|
||||
tasks, err = getAllTasks()
|
||||
title = "All Tasks:"
|
||||
} else if c.Bool("completed") {
|
||||
tasks, err = getCompletedTasks()
|
||||
title = "Completed Tasks:"
|
||||
} else {
|
||||
tasks, err = getPendingTasks()
|
||||
title = "Pending Tasks:"
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(title)
|
||||
printTasks(tasks)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "done",
|
||||
Aliases: []string{"do"},
|
||||
Usage: "Mark a task as completed",
|
||||
Action: func(c *cli.Context) error {
|
||||
idStr := c.Args().First()
|
||||
if idStr == "" {
|
||||
return fmt.Errorf("task ID required")
|
||||
}
|
||||
var id int
|
||||
if _, err := fmt.Sscanf(idStr, "%d", &id); err != nil {
|
||||
return fmt.Errorf("invalid task ID: %s", idStr)
|
||||
}
|
||||
return completeTask(id)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "undo",
|
||||
Aliases: []string{"ud"},
|
||||
Usage: "Mark a task as not completed",
|
||||
Action: func(c *cli.Context) error {
|
||||
idStr := c.Args().First()
|
||||
if idStr == "" {
|
||||
return fmt.Errorf("task ID required")
|
||||
}
|
||||
var id int
|
||||
if _, err := fmt.Sscanf(idStr, "%d", &id); err != nil {
|
||||
return fmt.Errorf("invalid task ID: %s", idStr)
|
||||
}
|
||||
return undoTask(id)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "remove",
|
||||
Aliases: []string{"rm"},
|
||||
Usage: "Remove a task",
|
||||
Action: func(c *cli.Context) error {
|
||||
idStr := c.Args().First()
|
||||
if idStr == "" {
|
||||
return fmt.Errorf("task ID required")
|
||||
}
|
||||
var id int
|
||||
if _, err := fmt.Sscanf(idStr, "%d", &id); err != nil {
|
||||
return fmt.Errorf("invalid task ID: %s", idStr)
|
||||
}
|
||||
return deleteTask(id)
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -55,3 +158,202 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func createTask(text string) error {
|
||||
sql := `
|
||||
INSERT INTO tasks (text, completed)
|
||||
VALUES ($1, $2)
|
||||
RETURNING id
|
||||
`
|
||||
|
||||
var id int
|
||||
err := pool.QueryRow(ctx, sql, text, false).Scan(&id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating task: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Created task with ID: %d\n", id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAllTasks() ([]Task, error) {
|
||||
sql := `
|
||||
SELECT id, text, completed, created_at, updated_at
|
||||
FROM tasks
|
||||
ORDER BY created_at DESC
|
||||
`
|
||||
|
||||
rows, err := pool.Query(ctx, sql)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error querying tasks: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var tasks []Task
|
||||
for rows.Next() {
|
||||
var task Task
|
||||
err := rows.Scan(
|
||||
&task.Id,
|
||||
&task.Text,
|
||||
&task.Completed,
|
||||
&task.CreatedAt,
|
||||
&task.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error scanning task row: %w", err)
|
||||
}
|
||||
tasks = append(tasks, task)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("error iterating task rows: %w", err)
|
||||
}
|
||||
|
||||
return tasks, nil
|
||||
}
|
||||
|
||||
func completeTask(id int) error {
|
||||
sql := `
|
||||
UPDATE tasks
|
||||
SET completed = true, updated_at = NOW()
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
commandTag, err := pool.Exec(ctx, sql, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error completing task: %w", err)
|
||||
}
|
||||
|
||||
if commandTag.RowsAffected() == 0 {
|
||||
return fmt.Errorf("no task found with id %d", id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func undoTask(id int) error {
|
||||
sql := `
|
||||
UPDATE tasks
|
||||
SET completed = false, updated_at = NOW()
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
commandTag, err := pool.Exec(ctx, sql, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating task: %w", err)
|
||||
}
|
||||
|
||||
if commandTag.RowsAffected() == 0 {
|
||||
return fmt.Errorf("no task found with id %d", id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteTask(id int) error {
|
||||
sql := `DELETE FROM tasks WHERE id = $1`
|
||||
|
||||
commandTag, err := pool.Exec(ctx, sql, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting task: %w", err)
|
||||
}
|
||||
|
||||
if commandTag.RowsAffected() == 0 {
|
||||
return fmt.Errorf("no task found with id %d", id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPendingTasks() ([]Task, error) {
|
||||
sql := `
|
||||
SELECT id, text, completed, created_at, updated_at
|
||||
FROM tasks
|
||||
WHERE completed = false
|
||||
ORDER BY created_at DESC
|
||||
`
|
||||
|
||||
rows, err := pool.Query(ctx, sql)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error querying pending tasks: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var tasks []Task
|
||||
for rows.Next() {
|
||||
var task Task
|
||||
err := rows.Scan(
|
||||
&task.Id,
|
||||
&task.Text,
|
||||
&task.Completed,
|
||||
&task.CreatedAt,
|
||||
&task.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error scanning task row: %w", err)
|
||||
}
|
||||
tasks = append(tasks, task)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("error iterating task rows: %w", err)
|
||||
}
|
||||
|
||||
return tasks, nil
|
||||
}
|
||||
|
||||
func getCompletedTasks() ([]Task, error) {
|
||||
sql := `
|
||||
SELECT id, text, completed, created_at, updated_at
|
||||
FROM tasks
|
||||
WHERE completed = true
|
||||
ORDER BY created_at DESC
|
||||
`
|
||||
|
||||
rows, err := pool.Query(ctx, sql)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error querying completed tasks: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var tasks []Task
|
||||
for rows.Next() {
|
||||
var task Task
|
||||
err := rows.Scan(
|
||||
&task.Id,
|
||||
&task.Text,
|
||||
&task.Completed,
|
||||
&task.CreatedAt,
|
||||
&task.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error scanning task row: %w", err)
|
||||
}
|
||||
tasks = append(tasks, task)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("error iterating task rows: %w", err)
|
||||
}
|
||||
|
||||
return tasks, nil
|
||||
}
|
||||
|
||||
func printTasks(tasks []Task) {
|
||||
if len(tasks) == 0 {
|
||||
fmt.Println("No tasks found")
|
||||
return
|
||||
}
|
||||
|
||||
for _, task := range tasks {
|
||||
status := "[ ]"
|
||||
if task.Completed {
|
||||
status = "[✓]"
|
||||
}
|
||||
fmt.Printf("%d. %s %s (Created: %s)\n",
|
||||
task.Id,
|
||||
status,
|
||||
task.Text,
|
||||
task.CreatedAt.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user