You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

118 lines
2.9 KiB
Go

package storage
import (
"context"
"fmt"
"time"
"github.com/jackc/pgx/v5/pgxpool"
)
// LogEntry represents a single adventure log message.
type LogEntry struct {
ID int64 `json:"id"`
HeroID int64 `json:"heroId"`
Message string `json:"message"`
CreatedAt time.Time `json:"createdAt"`
}
// LogStore handles adventure log CRUD operations against PostgreSQL.
type LogStore struct {
pool *pgxpool.Pool
}
// NewLogStore creates a new LogStore backed by the given connection pool.
func NewLogStore(pool *pgxpool.Pool) *LogStore {
return &LogStore{pool: pool}
}
// Add inserts a new adventure log entry for the given hero.
func (s *LogStore) Add(ctx context.Context, heroID int64, message string) error {
_, err := s.pool.Exec(ctx,
`INSERT INTO adventure_log (hero_id, message) VALUES ($1, $2)`,
heroID, message,
)
if err != nil {
return fmt.Errorf("add log entry: %w", err)
}
return nil
}
// GetSince returns log entries for a hero created after the given timestamp,
// ordered oldest-first (chronological). Used to build offline reports from
// real adventure log entries written by the offline simulator.
func (s *LogStore) GetSince(ctx context.Context, heroID int64, since time.Time, limit int) ([]LogEntry, error) {
if limit <= 0 {
limit = 200
}
if limit > 500 {
limit = 500
}
rows, err := s.pool.Query(ctx, `
SELECT id, hero_id, message, created_at
FROM adventure_log
WHERE hero_id = $1 AND created_at > $2
ORDER BY created_at ASC
LIMIT $3
`, heroID, since, limit)
if err != nil {
return nil, fmt.Errorf("get log since: %w", err)
}
defer rows.Close()
var entries []LogEntry
for rows.Next() {
var e LogEntry
if err := rows.Scan(&e.ID, &e.HeroID, &e.Message, &e.CreatedAt); err != nil {
return nil, fmt.Errorf("scan log entry: %w", err)
}
entries = append(entries, e)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("log since rows: %w", err)
}
if entries == nil {
entries = []LogEntry{}
}
return entries, nil
}
// GetRecent returns the most recent log entries for a hero, ordered newest-first.
func (s *LogStore) GetRecent(ctx context.Context, heroID int64, limit int) ([]LogEntry, error) {
if limit <= 0 {
limit = 50
}
if limit > 200 {
limit = 200
}
rows, err := s.pool.Query(ctx, `
SELECT id, hero_id, message, created_at
FROM adventure_log
WHERE hero_id = $1
ORDER BY created_at DESC
LIMIT $2
`, heroID, limit)
if err != nil {
return nil, fmt.Errorf("get recent log: %w", err)
}
defer rows.Close()
var entries []LogEntry
for rows.Next() {
var e LogEntry
if err := rows.Scan(&e.ID, &e.HeroID, &e.Message, &e.CreatedAt); err != nil {
return nil, fmt.Errorf("scan log entry: %w", err)
}
entries = append(entries, e)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("log entries rows: %w", err)
}
if entries == nil {
entries = []LogEntry{}
}
return entries, nil
}