SilentRenderStrategy

The SilentRenderStrategy suppresses all rendering output, making it ideal for testing, library usage, and scenarios where visual output is not desired.

Overview

SilentRenderStrategy produces zero output, ensuring completely silent operation. This is perfect for unit tests, automated systems, and library integrations where rendering output would clutter logs or interfere with other output.

Features

  • ✅ Zero output (complete silence)
  • ✅ Zero configuration required
  • ✅ Fastest performance (no I/O operations)
  • ✅ Clean test output
  • ✅ Library-friendly
  • ✅ No file system overhead
  • ✅ Perfect for headless environments

Installation

SilentRenderStrategy is included in the core MSR package:

import { SilentRenderStrategy } from '@migration-script-runner/core';

Basic Usage

With MigrationScriptExecutor

import { MigrationScriptExecutor, SilentRenderStrategy } from '@migration-script-runner/core';

const executor = new MigrationScriptExecutor({ handler, 
    renderStrategy: new SilentRenderStrategy()
});

await executor.migrate();  // No output produced

In Tests

import { MigrationScriptExecutor, SilentRenderStrategy, SilentLogger } from '@migration-script-runner/core';

describe('Migration Tests', () => {
    let executor: MigrationScriptExecutor;

    beforeEach(() => {
        executor = new MigrationScriptExecutor({ handler, 
            logger: new SilentLogger(),
            renderStrategy: new SilentRenderStrategy()
        });
    });

    it('should execute migrations without output', async () => {
        // No console clutter during test execution
        const result = await executor.migrate();
        expect(result.success).toBe(true);
    });
});

Library Integration

import { MigrationScriptExecutor, SilentRenderStrategy } from '@migration-script-runner/core';

class MyApplication {
    async initDatabase() {
        // Run migrations silently during app startup
        const executor = new MigrationScriptExecutor({ handler, 
            renderStrategy: new SilentRenderStrategy()
        });

        const result = await executor.migrate();

        if (!result.success) {
            throw new Error('Database migration failed');
        }

        // Continue with application startup
    }
}

Output Examples

All methods produce no output:

const strategy = new SilentRenderStrategy();

strategy.renderBanner('0.3.0', 'PostgreSQL');     // No output
strategy.renderMigrated(scripts, handler);         // No output
strategy.renderPending(pendingScripts);            // No output
strategy.renderExecuted(executedScripts);          // No output
strategy.renderIgnored(ignoredScripts);            // No output

Use Cases

Unit Testing

Keep test output clean and focused:

import { MigrationScriptExecutor, SilentRenderStrategy, SilentLogger } from '@migration-script-runner/core';

describe('MigrationScriptExecutor', () => {
    it('should handle empty migration list', async () => {
        const executor = new MigrationScriptExecutor({ handler, 
            logger: new SilentLogger(),
            renderStrategy: new SilentRenderStrategy()
        });

        const result = await executor.migrate();

        // Clean output, only test results shown
        expect(result.executed).toHaveLength(0);
    });
});

Without SilentRenderStrategy:

  MigrationScriptExecutor
  __  __ _                 _   _               ____            _       _
 |  \/  (_) __ _ _ __ __ _| |_(_) ___  _ __   / ___|  ___ _ __(_)_ __ | |_
 ...
+---------------------------------------+
|             Migrated                  |
+---------------------------------------+
...
    ✓ should handle empty migration list

With SilentRenderStrategy:

  MigrationScriptExecutor
    ✓ should handle empty migration list

Library Usage

When embedding MSR in a library:

import { MigrationScriptExecutor, SilentRenderStrategy } from '@migration-script-runner/core';

export class DatabaseManager {
    async initialize() {
        const executor = new MigrationScriptExecutor({ handler, 
            renderStrategy: new SilentRenderStrategy()
        });

        const result = await executor.migrate();

        // Library users don't see migration output
        // Only application logs are shown
        if (result.success) {
            console.log('Database initialized successfully');
        }
    }
}

Background Jobs

For scheduled or background migration tasks:

import { MigrationScriptExecutor, SilentRenderStrategy } from '@migration-script-runner/core';

// Cron job or scheduled task
async function runScheduledMigrations() {
    const executor = new MigrationScriptExecutor({ handler, 
        renderStrategy: new SilentRenderStrategy()
    });

    const result = await executor.migrate();

    // Only log important events, not migration tables
    if (result.executed.length > 0) {
        logger.info(`Executed ${result.executed.length} migrations`);
    }
}

Automated Systems

For fully automated deployments:

import { MigrationScriptExecutor, SilentRenderStrategy, FileLogger } from '@migration-script-runner/core';

async function deployApplication() {
    // Run migrations silently, log to file
    const executor = new MigrationScriptExecutor({ handler, 
        logger: new FileLogger({ logPath: './deploy.log' }),
        renderStrategy: new SilentRenderStrategy()
    });

    try {
        const result = await executor.migrate();

        // Only log summary, not tables
        console.log(`Deployment: ${result.executed.length} migrations applied`);

        await startApplication();
    } catch (error) {
        console.error('Deployment failed:', error);
        process.exit(1);
    }
}

Headless Environments

For Docker containers, Lambda functions, etc.:

import { MigrationScriptExecutor, SilentRenderStrategy } from '@migration-script-runner/core';

// Lambda function
export const handler = async (event) => {
    const executor = new MigrationScriptExecutor(dbHandler, config, {
        renderStrategy: new SilentRenderStrategy()
    });

    const result = await executor.migrate();

    return {
        statusCode: result.success ? 200 : 500,
        body: JSON.stringify({
            executed: result.executed.length,
            success: result.success
        })
    };
};

Integration Tests

For end-to-end testing:

describe('E2E Tests', () => {
    beforeAll(async () => {
        // Set up test database silently
        const executor = new MigrationScriptExecutor(testHandler, config, {
            renderStrategy: new SilentRenderStrategy()
        });

        await executor.migrate();
    });

    it('should create users', async () => {
        // Test actual functionality, not migration output
        const user = await createUser({ name: 'Test' });
        expect(user).toBeDefined();
    });
});

Best Practices

1. Combine with SilentLogger for Complete Silence

// Good: Complete silence
const executor = new MigrationScriptExecutor({ handler, 
    logger: new SilentLogger(),
    renderStrategy: new SilentRenderStrategy()
});

// Partial: Logger still produces output
const executor = new MigrationScriptExecutor({ handler, 
    renderStrategy: new SilentRenderStrategy()
    // Default ConsoleLogger still logs
});

2. Use in Test Environments Only

// Good: Environment-specific configuration
const renderStrategy = process.env.NODE_ENV === 'test'
    ? new SilentRenderStrategy()
    : new AsciiTableRenderStrategy();

const executor = new MigrationScriptExecutor({ handler,  renderStrategy });

// Avoid: Silent in production (makes debugging hard)
const executor = new MigrationScriptExecutor({ handler, 
    renderStrategy: new SilentRenderStrategy()  // Hard to debug
});

3. Still Check Migration Results

// Good: Silent but validate results
const executor = new MigrationScriptExecutor({ handler, 
    renderStrategy: new SilentRenderStrategy()
});

const result = await executor.migrate();

if (!result.success) {
    console.error('Migrations failed:', result.errors);
    process.exit(1);
}

// Avoid: Silent and ignoring results
await executor.migrate();  // Errors not handled

4. Document Why Silence is Needed

// Good: Clear intent
// Use SilentRenderStrategy to avoid cluttering test output
// Migration status is checked via result.success
const executor = new MigrationScriptExecutor({ handler, 
    renderStrategy: new SilentRenderStrategy()
});

// Avoid: No explanation
const executor = new MigrationScriptExecutor({ handler, 
    renderStrategy: new SilentRenderStrategy()  // Why?
});

5. Provide Alternative Feedback

// Good: Silent tables, but provide feedback
const executor = new MigrationScriptExecutor({ handler, 
    renderStrategy: new SilentRenderStrategy()
});

const result = await executor.migrate();

if (result.executed.length > 0) {
    console.log(`✓ Applied ${result.executed.length} migrations`);
}

// Avoid: Complete silence with no feedback
await executor.migrate();  // User has no idea what happened

Performance

SilentRenderStrategy is the fastest rendering strategy because it performs no I/O operations:

Strategy Overhead I/O Operations
SilentRenderStrategy < 0.1ms 0
AsciiTableRenderStrategy 5-50ms Console/file writes
JsonRenderStrategy (compact) 1-10ms Console/file writes
JsonRenderStrategy (pretty) 2-15ms Console/file writes

Limitations

  • No visual feedback: Users get no output at all
  • Harder debugging: Can’t see what migrations ran
  • Not suitable for CLI: Interactive users expect output
  • Not suitable for production monitoring: No way to track progress

For production deployments, consider JsonRenderStrategy with structured logging.

API Reference

Constructor

constructor()

Creates a new SilentRenderStrategy instance. No configuration required.

Example:

const strategy = new SilentRenderStrategy();

Methods

All methods are no-ops (produce no output):

renderMigrated(scripts: IScripts, handler: IDatabaseMigrationHandler, limit?: number): void

No-op: Produces no output for migrated scripts.

renderPending(scripts: MigrationScript[]): void

No-op: Produces no output for pending migrations.

renderExecuted(scripts: IMigrationInfo[]): void

No-op: Produces no output for executed migrations.

renderIgnored(scripts: MigrationScript[]): void

No-op: Produces no output for ignored migrations.

renderBanner(version: string, handlerName: string): void

No-op: Produces no banner output.