202 lines
4.6 KiB
Go
202 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
|
|
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/config"
|
|
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/db/postgres"
|
|
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/models"
|
|
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/repository"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
var pool *pgxpool.Pool
|
|
var ctx = context.Background()
|
|
|
|
func init() {
|
|
var err error
|
|
pool, err = pgxpool.New(ctx, config.Db.Url)
|
|
if err != nil {
|
|
log.Fatal("Unable to connect to database:", err)
|
|
}
|
|
|
|
if err := pool.Ping(ctx); err != nil {
|
|
log.Fatal("Unable to ping database:", err)
|
|
}
|
|
|
|
// fmt.Println("Connected to PostgreSQL database!")
|
|
}
|
|
|
|
func main() {
|
|
taskRespository := postgres.NewTaskRepository(pool)
|
|
|
|
app := &cli.App{
|
|
Name: "gotodo",
|
|
Usage: "A simple CLI program to manage your tasks",
|
|
Action: func(c *cli.Context) error {
|
|
completedState := false
|
|
tasks, err := taskRespository.GetAll(ctx, repository.GetAllTaskFilters{
|
|
Limit: 100,
|
|
Completed: &completedState,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Println("Pending Tasks:")
|
|
printTasks(tasks)
|
|
return nil
|
|
},
|
|
Commands: []*cli.Command{
|
|
{
|
|
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 taskRespository.Save(ctx, &models.Task{
|
|
Text: 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 []models.Task
|
|
var err error
|
|
title := "Pending Tasks:"
|
|
|
|
if c.Bool("all") {
|
|
tasks, err = taskRespository.GetAll(ctx, repository.GetAllTaskFilters{
|
|
Limit: 100,
|
|
})
|
|
title = "All Tasks:"
|
|
} else if c.Bool("completed") {
|
|
completedState := true
|
|
tasks, err = taskRespository.GetAll(ctx, repository.GetAllTaskFilters{
|
|
Limit: 100,
|
|
Completed: &completedState,
|
|
})
|
|
title = "Completed Tasks:"
|
|
} else {
|
|
completedState := false
|
|
tasks, err = taskRespository.GetAll(ctx, repository.GetAllTaskFilters{
|
|
Limit: 100,
|
|
Completed: &completedState,
|
|
})
|
|
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)
|
|
}
|
|
|
|
completedState := true
|
|
_, err := taskRespository.Update(ctx, id, &models.UpdateTaskInput{
|
|
Completed: &completedState,
|
|
})
|
|
|
|
return err
|
|
},
|
|
},
|
|
{
|
|
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)
|
|
}
|
|
|
|
completedState := false
|
|
_, err := taskRespository.Update(ctx, id, &models.UpdateTaskInput{
|
|
Completed: &completedState,
|
|
})
|
|
|
|
return err
|
|
},
|
|
},
|
|
{
|
|
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 taskRespository.Delete(ctx, id)
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
err := app.Run(os.Args)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func printTasks(tasks []models.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"))
|
|
}
|
|
}
|