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)`, `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 $$;`, `ALTER TABLE users ADD COLUMN IF NOT EXISTS telegram_chat_id BIGINT`, `ALTER TABLE users ADD COLUMN IF NOT EXISTS notifications_enabled BOOLEAN DEFAULT true`, `ALTER TABLE users ADD COLUMN IF NOT EXISTS timezone VARCHAR(50) DEFAULT 'Europe/Moscow'`, `ALTER TABLE tasks ADD COLUMN IF NOT EXISTS reminder_time TIME`, `ALTER TABLE habits ADD COLUMN IF NOT EXISTS reminder_time TIME`, `CREATE INDEX IF NOT EXISTS idx_users_telegram_chat_id ON users(telegram_chat_id)`, } for _, migration := range migrations { if _, err := db.Exec(migration); err != nil { return err } } return nil }