Files
spend-sparrow/db/treasure_chest.go
Tim Wundenberg 96ca636fbb
All checks were successful
Build Docker Image / Build-Docker-Image (push) Successful in 4m4s
Build and Push Docker Image / Build-And-Push-Docker-Image (push) Successful in 5m6s
feat(treasurechest): #64 implement hirarchical treasure chests
2025-05-13 12:45:05 +02:00

152 lines
4.1 KiB
Go

package db
import (
"database/sql"
"spend-sparrow/log"
"spend-sparrow/types"
"github.com/google/uuid"
"github.com/jmoiron/sqlx"
)
// While it may be duplicated to check for userId in the database access, it serves as a security layer
type TreasureChest interface {
Insert(userId uuid.UUID, treasureChest *types.TreasureChest) error
Update(userId uuid.UUID, treasureChest *types.TreasureChest) error
GetAll(userId uuid.UUID) ([]*types.TreasureChest, error)
GetAllByParentId(userId uuid.UUID, parentId uuid.UUID) ([]*types.TreasureChest, error)
Get(userId uuid.UUID, id uuid.UUID) (*types.TreasureChest, error)
Delete(userId uuid.UUID, id uuid.UUID) error
}
type TreasureChestSqlite struct {
db *sqlx.DB
}
func NewTreasureChestSqlite(db *sqlx.DB) *TreasureChestSqlite {
return &TreasureChestSqlite{db: db}
}
func (db TreasureChestSqlite) Insert(userId uuid.UUID, treasureChest *types.TreasureChest) error {
_, err := db.db.Exec(`
INSERT INTO treasure_chest (id, parent_id, user_id, name, current_balance, created_at, created_by)
VALUES (?,?,?,?,?,?,?)`, treasureChest.Id, treasureChest.ParentId, userId, treasureChest.Name, 0, treasureChest.CreatedAt, treasureChest.CreatedBy)
if err != nil {
log.Error("treasureChest Insert: %v", err)
return types.ErrInternal
}
return nil
}
func (db TreasureChestSqlite) Update(userId uuid.UUID, treasureChest *types.TreasureChest) error {
r, err := db.db.Exec(`
UPDATE treasure_chest
SET
parent_id = ?,
name = ?,
current_balance = ?,
updated_at = ?,
updated_by = ?
WHERE id = ?
AND user_id = ?`, treasureChest.ParentId, treasureChest.Name, treasureChest.CurrentBalance, treasureChest.UpdatedAt, treasureChest.UpdatedBy, treasureChest.Id, userId)
if err != nil {
log.Error("treasureChest Update: %v", err)
return types.ErrInternal
}
rows, err := r.RowsAffected()
if err != nil {
log.Error("treasureChest Update: %v", err)
return types.ErrInternal
}
if rows == 0 {
log.Info("treasureChest Update: not found")
return ErrNotFound
}
return nil
}
func (db TreasureChestSqlite) GetAll(userId uuid.UUID) ([]*types.TreasureChest, error) {
treasureChests := make([]*types.TreasureChest, 0)
err := db.db.Select(&treasureChests, `
SELECT
id, parent_id, user_id, name, current_balance,
created_at, created_by, updated_at, updated_by
FROM treasure_chest
WHERE user_id = ?
ORDER BY name`, userId)
if err != nil {
log.Error("treasureChest GetAll: %v", err)
return nil, types.ErrInternal
}
return treasureChests, nil
}
func (db TreasureChestSqlite) GetAllByParentId(userId uuid.UUID, parentId uuid.UUID) ([]*types.TreasureChest, error) {
treasureChests := make([]*types.TreasureChest, 0)
err := db.db.Select(&treasureChests, `
SELECT
id, parent_id, user_id, name, current_balance,
created_at, created_by, updated_at, updated_by
FROM treasure_chest
WHERE user_id = ?
AND parent_id = ?
ORDER BY name`, userId, parentId)
if err != nil {
log.Error("treasureChest GetAll: %v", err)
return nil, types.ErrInternal
}
return treasureChests, nil
}
func (db TreasureChestSqlite) Get(userId uuid.UUID, id uuid.UUID) (*types.TreasureChest, error) {
treasureChest := &types.TreasureChest{}
err := db.db.Get(treasureChest, `
SELECT
id, parent_id, user_id, name, current_balance,
created_at, created_by, updated_at, updated_by
FROM treasure_chest
WHERE user_id = ?
AND id = ?`, userId, id)
if err != nil {
if err == sql.ErrNoRows {
return nil, ErrNotFound
}
log.Error("treasureChest Get: %v", err)
return nil, types.ErrInternal
}
return treasureChest, nil
}
func (db TreasureChestSqlite) Delete(userId uuid.UUID, id uuid.UUID) error {
res, err := db.db.Exec("DELETE FROM treasure_chest WHERE id = ? and user_id = ?", id, userId)
if err != nil {
log.Error("treasureChest Delete: %v", err)
return types.ErrInternal
}
rows, err := res.RowsAffected()
if err != nil {
log.Error("treasureChest Delete: %v", err)
return types.ErrInternal
}
if rows == 0 {
log.Info("treasureChest Delete: not found")
return ErrNotFound
}
return nil
}