Skip to content

Refactor MigrationScriptExecutor to reduce complexity #68

Description

@vlavrynovych

Problem

MigrationScriptExecutor has become a God class again with too many responsibilities:

  1. Migration orchestration - coordinating the overall migration process
  2. Rollback logic - implementing 4 different rollback strategies (BACKUP, DOWN, BOTH, NONE)
  3. Hook execution - calling lifecycle hooks (onBeforeMigrate, onAfterMigrate, onMigrationError)
  4. Script execution - running individual migration scripts
  5. State management - tracking executed and pending migrations
  6. Rendering - coordinating with ConsoleRenderer for output

This violates the Single Responsibility Principle and makes the class difficult to maintain and test.

Proposed Solution

Extract responsibilities into focused services:

1. RollbackService

  • Encapsulates all rollback strategies (BACKUP, DOWN, BOTH, NONE)
  • Methods:
    • rollback(strategy: RollbackStrategy, attemptedScripts: MigrationScript[]): Promise<void>
    • rollbackWithBackup(): Promise<void>
    • rollbackWithDown(scripts: MigrationScript[]): Promise<void>
    • rollbackWithBoth(scripts: MigrationScript[]): Promise<void>
  • Dependencies: BackupService, IDatabaseMigrationHandler, Config, ILogger

2. MigrationHookExecutor

  • Manages lifecycle hook execution
  • Methods:
    • executeBeforeMigrate(script: MigrationScript): Promise<void>
    • executeAfterMigrate(result: MigrationScript, message: string): Promise<void>
    • executeMigrationError(script: MigrationScript, error: Error): Promise<void>
  • Dependencies: IMigrationLifecycleHooks

3. MigrationScriptExecutor (Simplified)

  • Focused only on orchestrating the overall migration flow
  • Delegates to specialized services
  • Methods remain the same but implementation is simplified:
    • migrate(): Promise<IMigrationResult>
    • list(limit?: number): Promise<void>
  • Dependencies:
    • RollbackService
    • MigrationHookExecutor
    • MigrationScriptRunner
    • BackupService
    • MigrationScanner
    • ConsoleRenderer
    • Config
    • ILogger

Benefits

  1. Single Responsibility Principle - each class has one clear purpose
  2. Easier Testing - smaller, focused unit tests
  3. Better Maintainability - changes to rollback logic don't affect hook execution
  4. Improved Readability - clear separation of concerns
  5. Reusability - RollbackService and MigrationHookExecutor can be used independently

Implementation Notes

  • Keep backward compatibility - public API remains unchanged
  • Move private methods to appropriate services
  • Update tests to reflect new structure
  • Update documentation with new architecture

Acceptance Criteria

  • RollbackService created with all rollback strategies
  • MigrationHookExecutor created for lifecycle hooks
  • MigrationScriptExecutor refactored to use new services
  • All tests passing with 100% coverage
  • Documentation updated (architecture.md, api/index.md)
  • No breaking changes to public API

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions