add db package

db package allows for writing games to postgres db
This commit is contained in:
Bhavnoor Singh Saroya 2025-08-18 21:29:05 -07:00
parent 7426ddaf74
commit 38368ba151
2 changed files with 106 additions and 0 deletions

97
db/db.go Normal file
View file

@ -0,0 +1,97 @@
package db
import (
"context"
"encoding/json"
"fmt"
"github.com/BattlesnakeOfficial/rules/board"
"github.com/jackc/pgx/v5/pgxpool"
)
// the db package provides a simple interface to interact with a PostgreSQL database, it is extremely simple and only writing, reading and deleting game info
// @ author Bhavnoor Singh Saroya
// Database wraps pgxpool
type Database struct {
Pool *pgxpool.Pool
}
// Connect initializes the pool and creates the table if needed
func Connect(dsn string) (*Database, error) {
ctx := context.Background()
pool, err := pgxpool.New(ctx, dsn)
if err != nil {
return nil, fmt.Errorf("db connect: %w", err)
}
// Ensure table exists
_, err = pool.Exec(ctx, `
CREATE TABLE IF NOT EXISTS items (
id UUID PRIMARY KEY,
info JSONB NOT NULL,
frames JSONB[]
)
`)
if err != nil {
return nil, fmt.Errorf("create table: %w", err)
}
return &Database{Pool: pool}, nil
}
func (db *Database) GetInfo(ctx context.Context, id string) (*board.Game, error) {
var gameData []byte
var it board.Game
err := db.Pool.QueryRow(ctx,
"SELECT info FROM items WHERE id=$1", id).
Scan(&gameData)
if err != nil {
return nil, err
}
// 2. Unmarshal the byte slice into the struct.
err = json.Unmarshal(gameData, &it)
if err != nil {
return nil, err
}
return &it, nil
}
func (db *Database) WriteInfo(ctx context.Context, info board.Game, frames []board.GameEvent) error {
var err error
var uuid string = info.ID
// 1. Marshal the struct into a byte slice.
gameData, err := json.Marshal(info)
if err != nil {
return fmt.Errorf("marshal game info: %w", err)
}
// convert []board.GameEvent to []json.RawMessage
var framesData []json.RawMessage
for _, f := range frames {
b, err := json.Marshal(f)
if err != nil {
return fmt.Errorf("marshal frame: %w", err)
}
framesData = append(framesData, b)
}
// use pgtype to wrap into postgres []JSONB
_, errr := db.Pool.Exec(ctx,
"INSERT INTO items (id, info, frames) VALUES ($1, $2, $3)",
uuid, gameData, framesData)
if errr != nil {
print("error writing to db, bad stuff happened: ")
// panic(fmt.Sprintf("Error inserting item: %v", err))
return fmt.Errorf("insert item: %w", errr)
}
return nil
}
func (db *Database) Delete(ctx context.Context, id int) error {
_, err := db.Pool.Exec(ctx,
"DELETE FROM items WHERE id=$1", id)
return err
}