UNPKG

undeexcepturi

Version:

TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.

189 lines (135 loc) 6.39 kB
--- title: Migrations --- > To use migrations we need to first install `@mikro-orm/migrations` package. MikroORM has integrated support for migrations via [umzug](https://github.com/sequelize/umzug). It allows you to generate migrations with current schema differences. By default, each migration will be all executed inside a transaction, and all of them will be wrapped in one master transaction, so if one of them fails, everything will be rolled back. ## Migration class Migrations are classes that extend Migration abstract class: ```typescript import { Migration } from '@mikro-orm/migrations'; export class Migration20191019195930 extends Migration { async up(): Promise<void> { this.addSql('select 1 + 1'); } } ``` To support undoing those changed, you can implement the `down` method, which throws an error by default. Migrations are by default wrapped in a transaction. You can override this behaviour on per migration basis by implementing the `isTransactional(): boolean` method. `Configuration` object and driver instance are available in the `Migration` class context. You can execute queries in the migration via `Migration.execute()` method, which will run queries in the same transaction as the rest of the migration. The `Migration.addSql()` method also accepts instances of knex. Knex instance can be accessed via `Migration.getKnex()`; ## Initial migration If you want to start using migrations, and you already have the schema generated, you can do so by creating so called initial migration: > Initial migration can be created only if there are no migrations previously generated or executed. ```sh npx mikro-orm migration:create --initial ``` This will create the initial migration, containing the schema dump from `schema:create` command. The migration will be automatically marked as executed. ## Configuration ```typescript await MikroORM.init({ // default values: migrations: { tableName: 'mikro_orm_migrations', // name of database table with log of executed transactions path: './migrations', // path to the folder with migrations pattern: /^[\w-]+\d+\.ts$/, // regex pattern for the migration files transactional: true, // wrap each migration in a transaction disableForeignKeys: true, // wrap statements with `set foreign_key_checks = 0` or equivalent allOrNothing: true, // wrap all migrations in master transaction dropTables: true, // allow to disable table dropping safe: false, // allow to disable table and column dropping emit: 'ts', // migration generation mode }, }) ``` ## Using via CLI You can use it via CLI: ```sh npx mikro-orm migration:create # Create new migration with current schema diff npx mikro-orm migration:up # Migrate up to the latest version npx mikro-orm migration:down # Migrate one step down npx mikro-orm migration:list # List all executed migrations npx mikro-orm migration:pending # List all pending migrations ``` > To create blank migration file, we can use `npx mikro-orm migration:create --blank`. For `migration:up` and `migration:down` commands you can specify `--from` (`-f`), `--to` (`-t`) and `--only` (`-o`) options to run only a subset of migrations: ```sh npx mikro-orm migration:up --from 2019101911 --to 2019102117 # the same as above npx mikro-orm migration:up --only 2019101923 # apply a single migration npx mikro-orm migration:down --to 0 # migrate down all migrations ``` > To run TS migration files, you will need to [enable `useTsNode` flag](./installation.md) in your `package.json`. ## Using the Migrator programmatically Or you can create a simple script where you initialize MikroORM like this: ```typescript title="./migrate.ts" import { MikroORM } from '@mikro-orm/core'; (async () => { const orm = await MikroORM.init({ dbName: 'your-db-name', // ... }); const migrator = orm.getMigrator(); await migrator.createMigration(); // creates file Migration20191019195930.ts await migrator.up(); // runs migrations up to the latest await migrator.up('name'); // runs only given migration, up await migrator.up({ to: 'up-to-name' }); // runs migrations up to given version await migrator.down(); // migrates one step down await migrator.down('name'); // runs only given migration, down await migrator.down({ to: 'down-to-name' }); // runs migrations down to given version await migrator.down({ to: 0 }); // migrates down to the first version await orm.close(true); })(); ``` Then run this script via `ts-node` (or compile it to plain JS and use `node`): ```sh $ ts-node migrate ``` ## Providing transaction context In some cases you might want to control the transaction context yourself: ```ts await orm.em.transactional(async em => { await migrator.up({ transaction: em.getTransactionContext() }); }); ``` ## Importing migrations statically If you do not want to dynamically import a folder (e.g. when bundling your code with webpack) you can import migrations directly. ```typescript import { MikroORM } from '@mikro-orm/core'; import { Migration20191019195930 } from '../migrations/Migration20191019195930.ts'; await MikroORM.init({ migrations: { migrationsList: [ { name: 'Migration20191019195930.ts', class: Migration20191019195930, }, ], }, }); ``` With the help of [webpack's context module api](https://webpack.js.org/guides/dependency-management/#context-module-api) we can dynamically import the migrations making it possible to import all files in a folder. ```typescript import { MikroORM } from '@mikro-orm/core'; import { basename } from 'path'; const migrations = {}; function importAll(r) { r.keys().forEach( (key) => (migrations[basename(key)] = Object.values(r(key))[0]) ); } importAll(require.context('../migrations', false, /\.ts$/)); const migrationsList = Object.keys(migrations).map((migrationName) => ({ name: migrationName, class: migrations[migrationName], })); await MikroORM.init({ migrations: { migrationsList, }, }); ``` ## Limitations ### MySQL There is no way to rollback DDL changes in MySQL. An implicit commit is forced for those queries automatically, so transactions are not working as expected. - https://github.com/mikro-orm/mikro-orm/issues/217 - https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html