97 lines
2.3 KiB
Go
97 lines
2.3 KiB
Go
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
|
|
}
|