Implement get goals (#25)

Closes #13

Reviewed-on: #25
This commit is contained in:
Sebastiaan de Schaetzen 2025-05-08 11:51:16 +02:00
parent 5a19fc041d
commit aa26a8f338
4 changed files with 95 additions and 3 deletions

View File

@ -40,3 +40,19 @@ func TestGetUserBadId(t *testing.T) {
e := startServer(t)
e.GET("/user/bad-id").Expect().Status(400)
}
func TestGetUserGoalsWhenNoGoalsPresent(t *testing.T) {
e := startServer(t)
result := e.GET("/user/1/goals").Expect().Status(200).JSON().Array()
result.Length().IsEqual(0)
}
func TestGetUserGoalsNoUser(t *testing.T) {
e := startServer(t)
e.GET("/user/999/goals").Expect().Status(404)
}
func TestGetUserGoalsBadId(t *testing.T) {
e := startServer(t)
e.GET("/user/bad-id/goals").Expect().Status(400)
}

View File

@ -57,3 +57,32 @@ func (db *Db) GetUser(id int) (*User, error) {
}
return user, nil
}
func (db *Db) UserExists(userId int) (bool, error) {
count := 0
err := db.db.Query("select count(*) from users where id = ?").
Bind(userId).ScanSingle(&count)
if err != nil {
return false, err
}
return count > 0, nil
}
func (db *Db) GetUserGoals(userId int) ([]Goal, error) {
goals := make([]Goal, 0)
var err error
for row := range db.db.Query("select id, name, target, progress, weight from goals where user_id = ?").
Bind(userId).Range(&err) {
goal := Goal{}
err = row.Scan(&goal.ID, &goal.Name, &goal.Target, &goal.Progress, &goal.Weight)
if err != nil {
return nil, err
}
goals = append(goals, goal)
}
if err != nil {
return nil, err
}
return goals, nil
}

View File

@ -15,10 +15,18 @@ import (
var migrations embed.FS
var db *Db
// ServerConfig holds configuration for the server.
type ServerConfig struct {
// The datasource to the SQLite database.
// Use ":memory:" for an in-memory database.
Datasource string
Port string
Started chan bool
// The port to listen on.
// Use an empty string to listen on a random port.
Port string
// The channel that gets signaled when the server has started.
Started chan bool
}
func getUsers(c *gin.Context) {
@ -54,6 +62,41 @@ func getUser(c *gin.Context) {
c.IndentedJSON(http.StatusOK, user)
}
func getUserGoals(c *gin.Context) {
userIdStr := c.Param("userId")
userId, err := strconv.Atoi(userIdStr)
if err != nil {
log.Printf("Invalid user ID: %v", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
return
}
exists, err := db.UserExists(userId)
if err != nil {
log.Printf("Error checking user existence: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal Server Error"})
return
}
if !exists {
log.Printf("Error checking user existence: %v", err)
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
goals, err := db.GetUserGoals(userId)
if err != nil {
log.Printf("Error getting user goals: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal Server Error"})
return
}
c.IndentedJSON(http.StatusOK, goals)
}
/*
*
Initialises the database, and then starts the server.
If the context gets cancelled, the server is shutdown and the database is closed.
*/
func start(ctx context.Context, config *ServerConfig) {
db = NewDb(config.Datasource)
defer db.db.MustClose()
@ -61,6 +104,7 @@ func start(ctx context.Context, config *ServerConfig) {
router := gin.Default()
router.GET("/api/users", getUsers)
router.GET("/api/user/:userId", getUser)
router.GET("/api/user/:userId/goals", getUserGoals)
srv := &http.Server{
Addr: ":" + config.Port,
@ -73,7 +117,9 @@ func start(ctx context.Context, config *ServerConfig) {
}()
log.Printf("Running server on port %s\n", config.Port)
config.Started <- true
if config.Started != nil {
config.Started <- true
}
<-ctx.Done()
log.Println("Shutting down")
if err := srv.Shutdown(context.Background()); err != nil {

View File

@ -15,6 +15,7 @@ create table history
create table goals
(
id integer primary key,
user_id integer not null,
name text not null,
target integer not null,
progress integer not null,