""" Automatic database migrations system """ import logging from sqlalchemy import inspect from .. import db logger = logging.getLogger(__name__) class Migration: """Base migration class""" # Higher version numbers run later version = 0 description = "Base migration" def should_run(self, inspector): """Determine if this migration should run""" return True def run(self): """Execute the migration""" raise NotImplementedError class AddFolderIdToFiles(Migration): """Add folder_id column to files table""" version = 1 description = "Add folder_id column to files table" def should_run(self, inspector): """Check if folder_id column exists in files table""" if 'files' not in inspector.get_table_names(): return False columns = [col['name'] for col in inspector.get_columns('files')] return 'folder_id' not in columns def run(self): """Add the folder_id column and foreign key constraint""" try: db.engine.execute('ALTER TABLE files ADD COLUMN folder_id INTEGER;') db.engine.execute('ALTER TABLE files ADD CONSTRAINT fk_files_folder_id FOREIGN KEY (folder_id) REFERENCES folders (id);') logger.info("Added folder_id column to files table") return True except Exception as e: logger.error(f"Error adding folder_id column: {str(e)}") return False # Add all migrations here MIGRATIONS = [ AddFolderIdToFiles(), # Remove the Share table migration since we're not using it ] def run_migrations(): """Run all pending migrations""" logger.info("Checking for pending database migrations...") inspector = inspect(db.engine) # Sort migrations by version pending_migrations = sorted([m for m in MIGRATIONS if m.should_run(inspector)], key=lambda m: m.version) if not pending_migrations: logger.info("No pending migrations found.") return logger.info(f"Found {len(pending_migrations)} pending migrations.") success_count = 0 for migration in pending_migrations: logger.info(f"Running migration {migration.version}: {migration.description}") try: success = migration.run() if success: success_count += 1 else: logger.warning(f"Migration {migration.version} reported failure") except Exception as e: logger.error(f"Error in migration {migration.version}: {str(e)}") logger.info(f"Migration complete. {success_count}/{len(pending_migrations)} migrations successful.")