Migrations and DB optimization
This commit is contained in:
parent
4ad17de80a
commit
2ade3e1380
4 changed files with 95 additions and 35 deletions
|
@ -29,6 +29,7 @@ func RegisterUserHandler(c echo.Context) error {
|
|||
user := lib.User{Name: name, Email: email, Password: hashedPassword}
|
||||
println("User: ", user.Name, user.Email, user.Password)
|
||||
if err := lib.SaveUser(lib.GetDBPool(), &user); err != nil {
|
||||
println("Error saving user: ", err.Error())
|
||||
return c.JSON(http.StatusInternalServerError, "Failed to save user")
|
||||
}
|
||||
|
||||
|
|
113
lib/db.go
113
lib/db.go
|
@ -2,6 +2,8 @@ package lib
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
|
@ -9,11 +11,24 @@ import (
|
|||
|
||||
var dbPool *pgxpool.Pool
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
// Initializes the global database connection pool.
|
||||
func InitializeDBPool(host, user, password, dbname string, port int) error {
|
||||
// Construct the connection string using the provided parameters
|
||||
connString := fmt.Sprintf("postgres://%s:%s@%s:%d/%s", user, password, host, port, dbname)
|
||||
|
||||
var err error
|
||||
dbPool, err = pgxpool.Connect(context.Background(), connString)
|
||||
if err != nil {
|
||||
|
@ -23,29 +38,85 @@ func InitializeDBPool(host, user, password, dbname string, port int) error {
|
|||
}
|
||||
|
||||
func InitializeSchema(dbPool *pgxpool.Pool) error {
|
||||
const schemaSQL = `
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255) UNIQUE NOT NULL,
|
||||
password VARCHAR(255) NOT NULL
|
||||
);
|
||||
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'
|
||||
);
|
||||
`
|
||||
// TODO: Add more tables to the schema
|
||||
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);
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := dbPool.Exec(context.Background(), schemaSQL)
|
||||
// Ensure the migrations table exists
|
||||
_, err := dbPool.Exec(context.Background(), `
|
||||
CREATE TABLE IF NOT EXISTS migrations (
|
||||
version VARCHAR(255) PRIMARY KEY
|
||||
);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
14
lib/room.go
14
lib/room.go
|
@ -2,10 +2,7 @@ package lib
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
|
@ -21,15 +18,6 @@ type Room struct {
|
|||
Scale string
|
||||
}
|
||||
|
||||
// GenerateNewID generates a new room ID with the format "room_randomstring".
|
||||
func GenerateNewID() string {
|
||||
randomBytes := make([]byte, 16)
|
||||
if _, err := rand.Read(randomBytes); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return fmt.Sprintf("room_%s", hex.EncodeToString(randomBytes))
|
||||
}
|
||||
|
||||
// CreateRoom creates a new room in the database.
|
||||
func CreateRoom(dbPool *pgxpool.Pool, userID, roomName string) (*Room, error) {
|
||||
if dbPool == nil {
|
||||
|
@ -37,7 +25,7 @@ func CreateRoom(dbPool *pgxpool.Pool, userID, roomName string) (*Room, error) {
|
|||
}
|
||||
|
||||
// Generate a new ID for the room
|
||||
newRoomID := GenerateNewID()
|
||||
newRoomID := GenerateNewID("room")
|
||||
|
||||
// Insert the new room into the database
|
||||
_, err := dbPool.Exec(context.Background(), "INSERT INTO rooms (id, userid, roomname, topicname, visible, scale) VALUES ($1, $2, $3, $4, $5, $6)", newRoomID, userID, roomName, "My First Topic", false, "0.5,1,2,3,5")
|
||||
|
|
|
@ -65,7 +65,7 @@ func SaveUser(dbPool *pgxpool.Pool, user *User) error {
|
|||
return errors.New("database connection pool is not initialized")
|
||||
}
|
||||
|
||||
commandTag, err := dbPool.Exec(context.Background(), "INSERT INTO users (name, email, password) VALUES ($1, $2, $3)", user.Name, user.Email, user.Password)
|
||||
commandTag, err := dbPool.Exec(context.Background(), "INSERT INTO users (id, name, email, password) VALUES ($1, $2, $3, $4)", GenerateNewID("user"), user.Name, user.Email, user.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
Loading…
Add table
Reference in a new issue