Files
cole-maxwell1 1382c42803 feat: add Hetzner-hosted todo application stack
Implement the server-rendered Go todo application with PostgreSQL persistence, Tailwind styling, health checks, and test coverage.

Provision production and staging infrastructure with OpenTofu, including private networking, static IPs, Object Storage backups, and load balancing.

Configure Rocky Linux hosts with Ansible, rootless Podman, PostgreSQL, WAL-G backup automation, staging restores, and generated inventory.
2026-08-06 21:34:56 -05:00

65 lines
1.5 KiB
Go

package db
import (
"context"
"fmt"
_ "github.com/lib/pq"
"xorm.io/xorm"
"todo-hetzner/app/internal/model"
)
type Store struct {
engine *xorm.Engine
}
func Open(databaseURL string) (*Store, error) {
engine, err := xorm.NewEngine("postgres", databaseURL)
if err != nil {
return nil, fmt.Errorf("create database engine: %w", err)
}
engine.SetMaxOpenConns(10)
engine.SetMaxIdleConns(5)
if err := engine.Sync2(new(model.Todo)); err != nil {
engine.Close()
return nil, fmt.Errorf("migrate database: %w", err)
}
return &Store{engine: engine}, nil
}
func (s *Store) Ping(ctx context.Context) error {
return s.engine.DB().PingContext(ctx)
}
func (s *Store) Close() error {
return s.engine.Close()
}
func (s *Store) List(ctx context.Context) ([]model.Todo, error) {
var todos []model.Todo
err := s.engine.Context(ctx).Desc("created_at", "id").Find(&todos)
return todos, err
}
func (s *Store) Create(ctx context.Context, title string) error {
_, err := s.engine.Context(ctx).Insert(&model.Todo{Title: title})
return err
}
func (s *Store) Toggle(ctx context.Context, id int64) (bool, error) {
var todo model.Todo
found, err := s.engine.Context(ctx).ID(id).Get(&todo)
if err != nil || !found {
return found, err
}
todo.Completed = !todo.Completed
_, err = s.engine.Context(ctx).ID(id).Cols("completed", "updated_at").Update(&todo)
return true, err
}
func (s *Store) Delete(ctx context.Context, id int64) (bool, error) {
affected, err := s.engine.Context(ctx).ID(id).Delete(new(model.Todo))
return affected > 0, err
}