pollo/lib/db.go

139 lines
3.5 KiB
Go
Raw Normal View History

2024-06-27 21:23:51 -06:00
package lib
import (
"context"
2024-06-28 23:58:36 -06:00
"crypto/rand"
"encoding/hex"
2024-06-27 21:51:00 -06:00
"fmt"
2024-06-27 21:23:51 -06:00
"github.com/jackc/pgx/v4/pgxpool"
)
var dbPool *pgxpool.Pool
2024-06-28 23:58:36 -06:00
// Migration represents a database migration.
type Migration struct {
Version string
SQL string
}
// GenerateNewID generates a DB with the format "prefix_randomstring".
func GenerateNewID(prefix string) string {
randomBytes := make([]byte, 16)
if _, err := rand.Read(randomBytes); err != nil {
panic(err)
}
return fmt.Sprintf("%s_%s", prefix, hex.EncodeToString(randomBytes))
}
2024-06-27 21:23:51 -06:00
// Initializes the global database connection pool.
2024-10-16 13:20:13 -06:00
func InitializeDBPool(databaseURL string) error {
2024-06-27 21:23:51 -06:00
var err error
2024-10-16 13:20:13 -06:00
dbPool, err = pgxpool.Connect(context.Background(), databaseURL)
2024-06-27 21:23:51 -06:00
if err != nil {
return err
}
return nil
}
func InitializeSchema(dbPool *pgxpool.Pool) error {
2024-06-28 23:58:36 -06:00
migrations := []Migration{
{
Version: "1_create_users_table",
SQL: `
CREATE TABLE IF NOT EXISTS users (
id TEXT NOT NULL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL
);`,
},
{
Version: "2_create_rooms_table",
SQL: `
CREATE TABLE IF NOT EXISTS rooms (
id TEXT NOT NULL PRIMARY KEY,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
userId TEXT NOT NULL,
roomName TEXT,
topicName TEXT,
visible BOOLEAN NOT NULL DEFAULT false,
scale TEXT NOT NULL DEFAULT '0.5,1,2,3,5'
);`,
},
{
Version: "3_add_foreign_key_to_rooms",
SQL: `
ALTER TABLE rooms
ADD CONSTRAINT fk_user_id
FOREIGN KEY (userId) REFERENCES users(id);`,
},
{
Version: "4_create_index_on_users_email",
SQL: `
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
`,
},
{
Version: "5_create_index_on_rooms_userid",
SQL: `
CREATE INDEX IF NOT EXISTS idx_rooms_userid ON rooms(userId);
`,
},
2024-09-16 13:46:25 -06:00
{
Version: "6_create_sessions_table",
SQL: `
CREATE TABLE IF NOT EXISTS sessions (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);
`,
},
2024-06-28 23:58:36 -06:00
}
// Ensure the migrations table exists
_, err := dbPool.Exec(context.Background(), `
CREATE TABLE IF NOT EXISTS migrations (
version VARCHAR(255) PRIMARY KEY
);
`)
2024-06-27 21:23:51 -06:00
if err != nil {
return err
}
2024-06-28 23:58:36 -06:00
// Apply each migration
for _, migration := range migrations {
// Check if this migration has already been applied
var exists bool
err := dbPool.QueryRow(context.Background(), "SELECT EXISTS(SELECT 1 FROM migrations WHERE version = $1)", migration.Version).Scan(&exists)
if err != nil {
return err
}
if !exists {
// Apply the migration
_, err = dbPool.Exec(context.Background(), migration.SQL)
if err != nil {
return err
}
// Mark this migration as applied
_, err = dbPool.Exec(context.Background(), "INSERT INTO migrations (version) VALUES ($1)", migration.Version)
if err != nil {
return err
}
}
}
2024-06-27 21:23:51 -06:00
return nil
}
// Returns the initialized database connection pool.
func GetDBPool() *pgxpool.Pool {
return dbPool
}