diff --git a/pkg/state/state_postgres.go b/pkg/state/state_postgres.go new file mode 100644 index 0000000..ebdcb75 --- /dev/null +++ b/pkg/state/state_postgres.go @@ -0,0 +1,60 @@ +package state + +import ( + "context" + "log/slog" + "os" + + "github.com/jackc/pgx/v5/pgxpool" +) + +// ----- PGState holds the shared connection pool +type PGState struct { + pool *pgxpool.Pool +} + +// ----- Create a new PGState, reading connection info from env vars +func NewPGState() *PGState { + ctx := context.Background() + + // Get connection URL from environment (standard: PGHOST, PGPORT, etc.) + dbURL := os.Getenv("DATABASE_URL") // canonical way: use DATABASE_URL + if dbURL == "" { + slog.Error("DATABASE_URL environment variable must be set") + os.Exit(1) + } + + // Create a pool config + config, err := pgxpool.ParseConfig(dbURL) + if err != nil { + slog.Error("Failed to parse DATABASE_URL", "error", err) + os.Exit(1) + } + + // Optionally set pool tuning here + config.MaxConns = 10 + + pool, err := pgxpool.NewWithConfig(ctx, config) + if err != nil { + slog.Error("Failed to create pgx pool", "error", err) + os.Exit(1) + } + + slog.Info("Connected to Postgres", "max_conns", config.MaxConns) + return &PGState{pool: pool} +} + +// ----- Sequence-based NextID (implements ServerState) +func (s *PGState) NextID() int { + ctx := context.Background() + + var id int + err := s.pool.QueryRow(ctx, `SELECT nextval('session_id_seq')`).Scan(&id) + if err != nil { + slog.Error("NextID query failed", "error", err) + panic("NextID(): " + err.Error()) // interface doesn't allow returning error + } + + slog.Debug("NextID generated", "id", id) + return id +}