Simple extensible node migrator library.

Simple extensible one-way migration tool for performing various tasks in order in multiple environments.

- Can be used for running any kind of tasks that need to be executed on multiple environments.
- Works great for migrating database schemas and data but also for changing image file formats etc.
- The storage method is extensive so the information about which migrations have been carried out can be stored anywhere (database, simple file etc).
- Has built-in TypeORM storage that can use MySQL / MariaDB / Postgres / SQLite / Microsoft SQL Server / Oracle / WebSQL.
- Each migration is a simple async function receiving a custom context and returning anything serializable for success or throwing error on failure.
- Written in TypeScript.
- Includes 100% test coverage.
Installation
This package is distributed via npm
npm install migrator-js
Commands
yarn start
to start the example application.
yarn build
to build the production version.
yarn test
to run tests.
yarn coverage
to gather code coverage.
yarn lint
to lint the codebase.
yarn prettier
to run prettier.
yarn audit
to run all pre-commit checks (prettier, build, lint, test)
Example migration script
import { IMigrationContext } from "../";
export default async (context: IMigrationContext): Promise<string> => {
const sum = await context.connection.query("SELECT 1+1 AS sum");
return `1+1=${sum}`;
};
Example script that runs chosen migrations
Store it in src/scripts/migrate.ts
etc and add NPM script to run it.
package.json
{
"scripts": {
"migrate": "yarn build && node build/example"
}
}
src/scripts/migrate.ts
import chalk from "chalk";
import path from "path";
import { Migrator, MigratorTypeormStorage } from "../src";
export interface MigrationContext {
version: string;
}
async function run() {
console.log("");
const migrator = new Migrator<MigrationContext>(
{
version: "1",
},
{
pattern: path.join(__dirname, "migrations", "!(*.spec|*.test|*.d).{ts,js}"),
storage: new MigratorTypeormStorage({
type: "sqlite",
database: path.join(__dirname, "..", "..", "migrate.sqlite3"),
}),
},
);
try {
const { pendingMigrations, chosenMigrations, performedMigrations, failedMigrations } = await migrator.migrate();
if (pendingMigrations.length === 0) {
console.error(`${chalk.black.bgWhite(` NOTHING TO MIGRATE `)} `);
} else if (chosenMigrations.length === 0) {
console.error(`${chalk.black.bgWhite(` NO MIGRATIONS CHOSEN `)} `);
} else if (performedMigrations.length > 0 && failedMigrations.length === 0) {
console.error(`${chalk.black.bgGreen(` ALL MIGRATIONS SUCCEEDED `)} - ${performedMigrations.length} total`);
} else if (performedMigrations.length === 0 && failedMigrations.length > 0) {
console.error(`${chalk.black.bgRed(` ALL MIGRATIONS FAILED `)} - ${failedMigrations.length} total`);
} else {
console.error(
`${chalk.black.bgYellow(` SOME MIGRATIONS FAILED `)} - ${performedMigrations.length} succeeded, ${
failedMigrations.length
} failed`,
);
}
if (failedMigrations.length === 0) {
process.exit(0);
} else {
process.exit(1);
}
} catch (e) {
console.error(`${chalk.black.bgRed(` RUNNING MIGRATOR FAILED `)}`, e.stack);
} finally {
await migrator.close();
}
}
run().catch(e => console.error(chalk.black.bgRed(` RUNNING MIGRATOR FAILED `), e.stack));