Skip to main content
Glama
migration-manager.tsβ€’5.01 kB
import Database from 'better-sqlite3'; export interface Migration { version: number; description: string; up: (db: Database.Database) => void; down?: (db: Database.Database) => void; } export class MigrationManager { private db: Database.Database; private migrations: Migration[] = []; constructor(db: Database.Database) { this.db = db; this.initializeMigrationTable(); } private initializeMigrationTable(): void { // Create migrations table if it doesn't exist this.db.exec(` CREATE TABLE IF NOT EXISTS schema_migrations ( version INTEGER PRIMARY KEY, description TEXT NOT NULL, applied_at DATETIME DEFAULT CURRENT_TIMESTAMP ) `); } addMigration(migration: Migration): void { this.migrations.push(migration); } getCurrentVersion(): number { const result = this.db.prepare(` SELECT MAX(version) as version FROM schema_migrations `).get() as { version: number | null }; return result.version || 0; } getPendingMigrations(): Migration[] { const currentVersion = this.getCurrentVersion(); return this.migrations .filter(m => m.version > currentVersion) .sort((a, b) => a.version - b.version); } async runMigrations(): Promise<{ applied: number; currentVersion: number }> { const pendingMigrations = this.getPendingMigrations(); if (pendingMigrations.length === 0) { console.error('πŸ“Š Database schema is up to date'); return { applied: 0, currentVersion: this.getCurrentVersion() }; } console.error(`πŸ”„ Running ${pendingMigrations.length} pending migrations...`); let appliedCount = 0; for (const migration of pendingMigrations) { try { console.error(` β”œβ”€ Applying migration ${migration.version}: ${migration.description}`); // Run migration in a transaction this.db.transaction(() => { migration.up(this.db); // Record the migration this.db.prepare(` INSERT INTO schema_migrations (version, description) VALUES (?, ?) `).run(migration.version, migration.description); })(); appliedCount++; console.error(` β”œβ”€ βœ… Migration ${migration.version} applied successfully`); } catch (error) { console.error(` β”œβ”€ ❌ Migration ${migration.version} failed:`, error); throw new Error(`Migration ${migration.version} failed: ${error}`); } } const newVersion = this.getCurrentVersion(); console.error(`βœ… Migrations completed: ${appliedCount} applied, current version: ${newVersion}`); return { applied: appliedCount, currentVersion: newVersion }; } rollback(targetVersion: number): void { const currentVersion = this.getCurrentVersion(); if (targetVersion >= currentVersion) { console.error('⚠️ Target version is not lower than current version'); return; } const migrationsToRollback = this.migrations .filter(m => m.version > targetVersion && m.version <= currentVersion) .sort((a, b) => b.version - a.version); // Reverse order for rollback console.error(`πŸ”„ Rolling back ${migrationsToRollback.length} migrations...`); for (const migration of migrationsToRollback) { if (!migration.down) { throw new Error(`Migration ${migration.version} does not support rollback`); } try { console.error(` β”œβ”€ Rolling back migration ${migration.version}: ${migration.description}`); this.db.transaction(() => { migration.down!(this.db); // Remove migration record this.db.prepare(` DELETE FROM schema_migrations WHERE version = ? `).run(migration.version); })(); console.error(` β”œβ”€ βœ… Migration ${migration.version} rolled back successfully`); } catch (error) { console.error(` β”œβ”€ ❌ Rollback ${migration.version} failed:`, error); throw new Error(`Rollback ${migration.version} failed: ${error}`); } } console.error(`βœ… Rollback completed to version ${targetVersion}`); } listMigrations(): Array<{ version: number; description: string; applied: boolean; applied_at?: string }> { const appliedMigrations = this.db.prepare(` SELECT version, description, applied_at FROM schema_migrations ORDER BY version `).all() as Array<{ version: number; description: string; applied_at: string }>; const appliedVersions = new Set(appliedMigrations.map(m => m.version)); const allMigrations = this.migrations.map(migration => ({ version: migration.version, description: migration.description, applied: appliedVersions.has(migration.version), applied_at: appliedMigrations.find(m => m.version === migration.version)?.applied_at })); return allMigrations.sort((a, b) => a.version - b.version); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ttommyth/rag-memory-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server