package database import ( "database/sql" "fmt" _ "github.com/jackc/pgx/v5/stdlib" "rag/file-system/internal/common" ) func NewPostgresDB(databaseURL string) (*sql.DB, error) { db, err := sql.Open("pgx", databaseURL) if err != nil { return nil, fmt.Errorf("failed to open database: %w", err) } if err := db.Ping(); err != nil { return nil, fmt.Errorf("failed to ping database: %w", err) } db.SetMaxOpenConns(25) db.SetMaxIdleConns(5) common.Logger.Info("connected to PostgreSQL") return db, nil } func RunMigrations(db *sql.DB) error { migrations := []string{ `CREATE TABLE IF NOT EXISTS folders ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), parent_id UUID REFERENCES folders(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, owner_id VARCHAR(36) NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE(parent_id, name, owner_id) )`, `CREATE INDEX IF NOT EXISTS idx_folders_parent ON folders(parent_id)`, `CREATE INDEX IF NOT EXISTS idx_folders_owner ON folders(owner_id)`, `CREATE TABLE IF NOT EXISTS files ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), folder_id UUID REFERENCES folders(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, s3_key VARCHAR(512) NOT NULL, s3_bucket VARCHAR(255) NOT NULL, size BIGINT NOT NULL DEFAULT 0, content_type VARCHAR(255) NOT NULL DEFAULT 'application/octet-stream', owner_id VARCHAR(36) NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() )`, `CREATE INDEX IF NOT EXISTS idx_files_folder ON files(folder_id)`, `CREATE INDEX IF NOT EXISTS idx_files_owner ON files(owner_id)`, `CREATE INDEX IF NOT EXISTS idx_files_s3_key ON files(s3_key)`, `CREATE TABLE IF NOT EXISTS share_links ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), resource_type VARCHAR(10) NOT NULL, resource_id UUID NOT NULL, token VARCHAR(32) NOT NULL UNIQUE, password VARCHAR(255), expires_at TIMESTAMPTZ, download_count INT NOT NULL DEFAULT 0, max_downloads INT, created_by VARCHAR(36) NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() )`, `CREATE INDEX IF NOT EXISTS idx_share_token ON share_links(token)`, `CREATE INDEX IF NOT EXISTS idx_share_resource ON share_links(resource_type, resource_id)`, } for _, m := range migrations { if _, err := db.Exec(m); err != nil { return fmt.Errorf("migration failed: %w\nSQL: %s", err, m) } } common.Logger.Info("database migrations completed") return nil }