import { drizzle } from 'drizzle-orm/node-postgres'; import { Pool } from 'pg'; import { migrate } from 'drizzle-orm/node-postgres/migrator'; import * as schema from '@shared/schema'; import { sql } from 'drizzle-orm'; let db: ReturnType | null = null; let pool: Pool | null = null; export function getDatabase() { if (!db) { const databaseUrl = process.env.DATABASE_URL; if (!databaseUrl) { throw new Error('DATABASE_URL environment variable is not set'); } pool = new Pool({ connectionString: databaseUrl, }); db = drizzle(pool, { schema }); } return db; } export async function runMigrations() { try { const database = getDatabase(); // Push schema to database (creates/updates tables as needed) // This is equivalent to running `drizzle-kit push` console.log('Checking database schema...'); // Enable pgcrypto extension for gen_random_uuid() await database.execute(sql`CREATE EXTENSION IF NOT EXISTS "pgcrypto"`); // Create tables if they don't exist await database.execute(sql` CREATE TABLE IF NOT EXISTS users ( id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(), username TEXT NOT NULL UNIQUE, password TEXT NOT NULL ) `); await database.execute(sql` CREATE TABLE IF NOT EXISTS labels ( id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, color TEXT NOT NULL ) `); await database.execute(sql` CREATE TABLE IF NOT EXISTS tasks ( id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(), title TEXT NOT NULL, description TEXT, status TEXT NOT NULL DEFAULT 'todo', priority TEXT NOT NULL DEFAULT 'medium', due_date TIMESTAMP, time_tracked INTEGER NOT NULL DEFAULT 0, is_tracking BOOLEAN NOT NULL DEFAULT false, project_id TEXT, notes TEXT, label_id VARCHAR REFERENCES labels(id) ) `); console.log('✓ Database schema is up to date'); } catch (error) { console.error('Failed to run migrations:', error); throw error; } } export async function initializeDatabase() { try { // Run migrations first await runMigrations(); const database = getDatabase(); // Create default labels if they don't exist const existingLabels = await database.select().from(schema.labels); if (existingLabels.length === 0) { const defaultLabels = [ { name: "Work", color: "#3B82F6" }, { name: "Personal", color: "#10B981" }, { name: "Urgent", color: "#EF4444" }, { name: "Study", color: "#8B5CF6" }, ]; await database.insert(schema.labels).values(defaultLabels); console.log('✓ Created default labels'); } console.log('✓ Database initialized successfully'); } catch (error) { console.error('Failed to initialize database:', error); throw error; } } export async function closeDatabase() { if (pool) { await pool.end(); pool = null; db = null; console.log('✓ Database connection closed'); } }