Files
pulse-api/internal/repository/db.go
2026-02-06 11:19:55 +00:00

103 lines
3.4 KiB
Go

package repository
import (
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
)
func NewDB(databaseURL string) (*sqlx.DB, error) {
db, err := sqlx.Connect("postgres", databaseURL)
if err != nil {
return nil, err
}
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
return db, nil
}
func RunMigrations(db *sqlx.DB) error {
migrations := []string{
`CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
username VARCHAR(100) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
email_verified BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE TABLE IF NOT EXISTS habits (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
description TEXT DEFAULT '''',
color VARCHAR(20) DEFAULT '#6366f1',
icon VARCHAR(50) DEFAULT 'check',
frequency VARCHAR(20) DEFAULT 'daily',
target_days INTEGER[] DEFAULT '{1,2,3,4,5,6,0}',
target_count INTEGER DEFAULT 1,
is_archived BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE TABLE IF NOT EXISTS habit_logs (
id SERIAL PRIMARY KEY,
habit_id INTEGER REFERENCES habits(id) ON DELETE CASCADE,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
date DATE NOT NULL,
count INTEGER DEFAULT 1,
note TEXT DEFAULT '''',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(habit_id, date)
)`,
`CREATE TABLE IF NOT EXISTS email_tokens (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
token VARCHAR(255) UNIQUE NOT NULL,
type VARCHAR(20) NOT NULL,
expires_at TIMESTAMP NOT NULL,
used_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE TABLE IF NOT EXISTS tasks (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(255) NOT NULL,
description TEXT DEFAULT '''',
icon VARCHAR(10) DEFAULT '📋',
color VARCHAR(7) DEFAULT '#6B7280',
due_date DATE,
priority INTEGER DEFAULT 0,
completed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE INDEX IF NOT EXISTS idx_habits_user_id ON habits(user_id)`,
`CREATE INDEX IF NOT EXISTS idx_habit_logs_habit_id ON habit_logs(habit_id)`,
`CREATE INDEX IF NOT EXISTS idx_habit_logs_date ON habit_logs(date)`,
`CREATE INDEX IF NOT EXISTS idx_habit_logs_user_date ON habit_logs(user_id, date)`,
`CREATE INDEX IF NOT EXISTS idx_email_tokens_token ON email_tokens(token)`,
`CREATE INDEX IF NOT EXISTS idx_email_tokens_user_id ON email_tokens(user_id)`,
`CREATE INDEX IF NOT EXISTS idx_tasks_user_id ON tasks(user_id)`,
`CREATE INDEX IF NOT EXISTS idx_tasks_due_date ON tasks(due_date)`,
`CREATE INDEX IF NOT EXISTS idx_tasks_completed ON tasks(user_id, completed_at)`,
// Migration: add email_verified column if not exists
`DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='email_verified') THEN
ALTER TABLE users ADD COLUMN email_verified BOOLEAN DEFAULT FALSE;
END IF;
END $$;`,
}
for _, migration := range migrations {
if _, err := db.Exec(migration); err != nil {
return err
}
}
return nil
}