| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- "use strict";
- var _bluebird = _interopRequireDefault(require("bluebird"));
- var _fs = _interopRequireDefault(require("fs"));
- var _migration2 = _interopRequireDefault(require("./migration"));
- var _path = _interopRequireDefault(require("path"));
- var _events = require("events");
- var _migrationsList = _interopRequireDefault(require("./migrationsList"));
- var _Storage = _interopRequireDefault(require("./storages/Storage"));
- var _JSONStorage = _interopRequireDefault(require("./storages/JSONStorage"));
- var _MongoDBStorage = _interopRequireDefault(require("./storages/MongoDBStorage"));
- var _SequelizeStorage = _interopRequireDefault(require("./storages/SequelizeStorage"));
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
- /**
- * @class Umzug
- * @extends EventEmitter
- */
- module.exports = class Umzug extends _events.EventEmitter {
- /**
- * Constructs Umzug instance.
- *
- * @param {Object} [options]
- * @param {String} [options.storage='json'] - The storage. Possible values:
- * 'json', 'sequelize', 'mongodb', an argument for `require()`, including absolute paths.
- * @param {function|false} [options.logging=false] - The logging function.
- * A function that gets executed every time migrations start and have ended.
- * @param {String} [options.upName='up'] - The name of the positive method
- * in migrations.
- * @param {String} [options.downName='down'] - The name of the negative method
- * in migrations.
- * @param {Object} [options.storageOptions] - The options for the storage.
- * Check the available storages for further details.
- * @param {Object|Array} [options.migrations] - options for loading migration
- * files, or (advanced) an array of Migration instances
- * @param {Array} [options.migrations.params] - The params that gets passed to
- * the migrations. Might be an array or a synchronous function which returns
- * an array.
- * @param {String} [options.migrations.path] - The path to the migrations
- * directory.
- * @param {RegExp} [options.migrations.pattern] - The pattern that determines
- * whether or not a file is a migration.
- * @param {Migration~wrap} [options.migrations.wrap] - A function that
- * receives and returns the to be executed function. This can be used to
- * modify the function.
- * @param {Migration~customResolver} [options.migrations.customResolver] - A
- * function that specifies how to get a migration object from a path. This
- * should return an object of the form { up: Function, down: Function }.
- * Without this defined, a regular javascript import will be performed.
- * @constructs Umzug
- */
- constructor(options = {}) {
- super();
- this.options = _objectSpread({
- storage: 'json',
- storageOptions: {},
- logging: false,
- upName: 'up',
- downName: 'down'
- }, options);
- if (this.options.logging && typeof this.options.logging !== 'function') {
- throw new Error('The logging-option should be either a function or false');
- }
- if (!Array.isArray(this.options.migrations)) {
- this.options.migrations = _objectSpread({
- params: [],
- path: _path.default.resolve(process.cwd(), 'migrations'),
- pattern: /^\d+[\w-]+\.js$/,
- traverseDirectories: false,
- wrap: fun => fun
- }, this.options.migrations);
- }
- this.storage = this._initStorage();
- }
- /**
- * Executes given migrations with a given method.
- *
- * @param {Object} [options]
- * @param {String[]} [options.migrations=[]]
- * @param {String} [options.method='up']
- * @returns {Promise}
- */
- execute(options = {}) {
- const self = this;
- options = _objectSpread({
- migrations: [],
- method: 'up'
- }, options);
- return _bluebird.default.map(options.migrations, migration => self._findMigration(migration)).then(migrations => _objectSpread({}, options, {
- migrations
- })).then(options => _bluebird.default.each(options.migrations, migration => {
- const name = _path.default.basename(migration.file, _path.default.extname(migration.file));
- let startTime;
- return self._wasExecuted(migration).catch(() => false).then(executed => typeof executed === 'undefined' ? true : executed).tap(executed => {
- if (!executed || options.method === 'down') {
- const fun = migration[options.method] || _bluebird.default.resolve;
- let params = self.options.migrations.params;
- if (typeof params === 'function') {
- params = params();
- }
- if (options.method === 'up') {
- self.log('== ' + name + ': migrating =======');
- self.emit('migrating', name, migration);
- } else {
- self.log('== ' + name + ': reverting =======');
- self.emit('reverting', name, migration);
- }
- startTime = new Date();
- return fun.apply(migration, params);
- }
- }).then(executed => {
- if (!executed && options.method === 'up') {
- return _bluebird.default.resolve(self.storage.logMigration(migration.file));
- } else if (options.method === 'down') {
- return _bluebird.default.resolve(self.storage.unlogMigration(migration.file));
- }
- }).tap(() => {
- const duration = ((new Date() - startTime) / 1000).toFixed(3);
- if (options.method === 'up') {
- self.log('== ' + name + ': migrated (' + duration + 's)\n');
- self.emit('migrated', name, migration);
- } else {
- self.log('== ' + name + ': reverted (' + duration + 's)\n');
- self.emit('reverted', name, migration);
- }
- });
- }));
- }
- /**
- * Lists executed migrations.
- *
- * @returns {Promise.<Migration>}
- */
- executed() {
- return _bluebird.default.resolve(this.storage.executed()).bind(this).map(file => new _migration2.default(file));
- }
- /**
- * Lists pending migrations.
- *
- * @returns {Promise.<Migration[]>}
- */
- pending() {
- return this._findMigrations().bind(this).then(function (all) {
- return _bluebird.default.join(all, this.executed());
- }).spread((all, executed) => {
- const executedFiles = executed.map(migration => migration.file);
- return all.filter(migration => executedFiles.indexOf(migration.file) === -1);
- });
- }
- /**
- * Execute migrations up.
- *
- * If options is a migration name (String), it will be executed.
- * If options is a list of migration names (String[]), them will be executed.
- * If options is Object:
- * - { from: 'migration-1', to: 'migration-n' } - execute migrations in range.
- * - { migrations: [] } - execute migrations in array.
- *
- * @param {String|String[]|Object} options
- * @param {String} [options.from] - The first migration to execute (exc).
- * @param {String} [options.to] - The last migration to execute (inc).
- * @param {String[]} [options.migrations] - List of migrations to execute.
- * @returns {Promise}
- */
- up(options) {
- return this._run('up', options, this.pending.bind(this));
- }
- /**
- * Execute migrations down.
- *
- * If options is a migration name (String), it will be executed.
- * If options is a list of migration names (String[]), them will be executed.
- * If options is Object:
- * - { from: 'migration-n', to: 'migration-1' } - execute migrations in range.
- * - { migrations: [] } - execute migrations in array.
- *
- * @param {String|String[]|Object} options
- * @param {String} [options.from] - The first migration to execute (exc).
- * @param {String} [options.to] - The last migration to execute (inc).
- * @param {String[]} [options.migrations] - List of migrations to execute.
- * @returns {Promise}
- */
- down(options) {
- const getExecuted = function () {
- return this.executed().bind(this).then(migrations => migrations.reverse());
- }.bind(this);
- if (typeof options === 'undefined' || !Object.keys(options).length) {
- return getExecuted().bind(this).then(function (migrations) {
- return migrations[0] ? this.down(migrations[0].file) : _bluebird.default.resolve([]);
- });
- } else {
- return this._run('down', options, getExecuted.bind(this));
- }
- }
- /**
- * Callback function to get migrations in right order.
- *
- * @callback Umzug~rest
- * @return {Promise.<Migration[]>}
- */
- /**
- * Execute migrations either down or up.
- *
- * If options is a migration name (String), it will be executed.
- * If options is a list of migration names (String[]), them will be executed.
- * If options is Object:
- * - { from: 'migration-1', to: 'migration-n' } - execute migrations in range.
- * - { migrations: [] } - execute migrations in array.
- *
- * @param {String} method - Method to run. Either 'up' or 'down'.
- * @param {String|String[]|Object} options
- * @param {String} [options.from] - The first migration to execute (exc).
- * @param {String} [options.to] - The last migration to execute (inc).
- * @param {String[]} [options.migrations] - List of migrations to execute.
- * @param {Umzug~rest} [rest] - Function to get migrations in right order.
- * @returns {Promise}
- * @private
- */
- _run(method, options, rest) {
- if (typeof options === 'string') {
- return this._run(method, [options]);
- } else if (Array.isArray(options)) {
- return _bluebird.default.resolve(options).bind(this).map(function (migration) {
- return this._findMigration(migration);
- }).then(function (migrations) {
- return method === 'up' ? this._arePending(migrations) : this._wereExecuted(migrations);
- }).then(function () {
- return this._run(method, {
- migrations: options
- });
- });
- }
- options = _objectSpread({
- to: null,
- from: null,
- migrations: null
- }, options || {});
- if (options.migrations) {
- return this.execute({
- migrations: options.migrations,
- method: method
- });
- } else {
- return rest().bind(this).then(function (migrations) {
- let result = _bluebird.default.resolve().bind(this);
- if (options.to) {
- result = result.then(function () {
- // There must be a migration matching to options.to...
- return this._findMigration(options.to);
- }).then(function (migration) {
- // ... and it must be pending/executed.
- return method === 'up' ? this._isPending(migration) : this._wasExecuted(migration);
- });
- }
- return result.then(() => _bluebird.default.resolve(migrations));
- }).then(function (migrations) {
- if (options.from) {
- return this._findMigrationsFromMatch(options.from, method);
- } else {
- return migrations;
- }
- }).then(function (migrations) {
- return this._findMigrationsUntilMatch(options.to, migrations);
- }).then(function (migrationFiles) {
- return this._run(method, {
- migrations: migrationFiles
- });
- });
- }
- }
- /**
- * Lists pending/executed migrations depending on method from a given
- * migration excluding it.
- *
- * @param {String} from - Migration name to be searched.
- * @param {String} method - Either 'up' or 'down'. If method is 'up', only
- * pending migrations will be accepted. Otherwise only executed migrations
- * will be accepted.
- * @returns {Promise.<Migration[]>}
- * @private
- */
- _findMigrationsFromMatch(from, method) {
- // We'll fetch all migrations and work our way from start to finish
- return this._findMigrations().bind(this).then(migrations => {
- let found = false;
- return migrations.filter(migration => {
- if (migration.testFileName(from)) {
- found = true;
- return false;
- }
- return found;
- });
- }).filter(function (fromMigration) {
- // now check if they need to be run based on status and method
- return this._wasExecuted(fromMigration).then(() => {
- if (method === 'up') {
- return false;
- } else {
- return true;
- }
- }).catch(() => {
- if (method === 'up') {
- return true;
- } else {
- return false;
- }
- });
- });
- }
- /**
- * Pass message to logger if logging is enabled.
- *
- * @param {*} message - Message to be logged.
- */
- log(message) {
- if (this.options.logging) {
- this.options.logging(message);
- }
- }
- /**
- * Try to require and initialize storage.
- *
- * @returns {*|SequelizeStorage|JSONStorage|MongoDBStorage|Storage}
- * @private
- */
- _initStorage() {
- if (typeof this.options.storage !== 'string') {
- return this.options.storage;
- }
- let StorageClass;
- try {
- StorageClass = this._getStorageClass();
- } catch (e) {
- throw new Error('Unable to resolve the storage: ' + this.options.storage + ', ' + e);
- }
- let storage = new StorageClass(this.options.storageOptions);
- if (storage && storage.options && storage.options.storageOptions) {
- console.warn('Deprecated: Umzug Storage constructor has changed!', 'old syntax: new Storage({ storageOptions: { ... } })', 'new syntax: new Storage({ ... })', 'where ... represents the same storageOptions passed to Umzug constructor.', 'For more information: https://github.com/sequelize/umzug/pull/137');
- storage = new StorageClass(this.options);
- }
- return storage;
- }
- _getStorageClass() {
- switch (this.options.storage) {
- case 'none':
- return _Storage.default;
- case 'json':
- return _JSONStorage.default;
- case 'mongodb':
- return _MongoDBStorage.default;
- case 'sequelize':
- return _SequelizeStorage.default;
- default:
- return require(this.options.storage);
- }
- }
- /**
- * Loads all migrations in ascending order.
- *
- * @returns {Promise.<Migration[]>}
- * @private
- */
- _findMigrations(migrationPath) {
- if (Array.isArray(this.options.migrations)) {
- return _bluebird.default.resolve(this.options.migrations);
- }
- const isRoot = !migrationPath;
- if (isRoot) {
- migrationPath = this.options.migrations.path;
- }
- return _bluebird.default.promisify(_fs.default.readdir)(migrationPath).bind(this).map(function (file) {
- const filePath = _path.default.resolve(migrationPath, file);
- if (this.options.migrations.traverseDirectories) {
- if (_fs.default.lstatSync(filePath).isDirectory()) {
- return this._findMigrations(filePath).then(migrations => migrations);
- }
- }
- if (this.options.migrations.pattern.test(file)) {
- return new _migration2.default(filePath, this.options);
- }
- return file;
- }).reduce((a, b) => a.concat(b), []) // flatten the result to an array
- .filter(file => file instanceof _migration2.default // only care about Migration
- ).then(migrations => {
- if (isRoot) {
- // only sort if its root
- return migrations.sort((a, b) => {
- if (a.file > b.file) {
- return 1;
- } else if (a.file < b.file) {
- return -1;
- } else {
- return 0;
- }
- });
- }
- return migrations;
- });
- }
- /**
- * Gets a migration with a given name.
- *
- * @param {String} needle - Name of the migration.
- * @returns {Promise.<Migration>}
- * @private
- */
- _findMigration(needle) {
- return this._findMigrations().then(migrations => migrations.filter(migration => migration.testFileName(needle))[0]).then(migration => {
- if (migration) {
- return migration;
- } else {
- return _bluebird.default.reject(new Error('Unable to find migration: ' + needle));
- }
- });
- }
- /**
- * Checks if migration is executed. It will success if and only if there is
- * an executed migration with a given name.
- *
- * @param {String} _migration - Name of migration to be checked.
- * @returns {Promise}
- * @private
- */
- _wasExecuted(_migration) {
- return this.executed().filter(migration => migration.testFileName(_migration.file)).then(migrations => {
- if (migrations[0]) {
- return _bluebird.default.resolve();
- } else {
- return _bluebird.default.reject(new Error('Migration was not executed: ' + _migration.file));
- }
- });
- }
- /**
- * Checks if a list of migrations are all executed. It will success if and
- * only if there is an executed migration for each given name.
- *
- * @param {String[]} migrationNames - List of migration names to be checked.
- * @returns {Promise}
- * @private
- */
- _wereExecuted(migrationNames) {
- return _bluebird.default.resolve(migrationNames).bind(this).map(function (migration) {
- return this._wasExecuted(migration);
- });
- }
- /**
- * Checks if migration is pending. It will success if and only if there is
- * a pending migration with a given name.
- *
- * @param {String} _migration - Name of migration to be checked.
- * @returns {Promise}
- * @private
- */
- _isPending(_migration) {
- return this.pending().filter(migration => migration.testFileName(_migration.file)).then(migrations => {
- if (migrations[0]) {
- return _bluebird.default.resolve();
- } else {
- return _bluebird.default.reject(new Error('Migration is not pending: ' + _migration.file));
- }
- });
- }
- /**
- * Checks if a list of migrations are all pending. It will success if and only
- * if there is a pending migration for each given name.
- *
- * @param {String[]} migrationNames - List of migration names to be checked.
- * @returns {Promise}
- * @private
- */
- _arePending(migrationNames) {
- return _bluebird.default.resolve(migrationNames).bind(this).map(function (migration) {
- return this._isPending(migration);
- });
- }
- /**
- * Skip migrations in a given migration list after `to` migration.
- *
- * @param {String} to - The last one migration to be accepted.
- * @param {Migration[]} migrations - Migration list to be filtered.
- * @returns {Promise.<String>} - List of migrations before `to`.
- * @private
- */
- _findMigrationsUntilMatch(to, migrations) {
- return _bluebird.default.resolve(migrations).map(migration => migration.file).reduce((acc, migration) => {
- if (acc.add) {
- acc.migrations.push(migration);
- if (to && migration.indexOf(to) === 0) {
- // Stop adding the migrations once the final migration
- // has been added.
- acc.add = false;
- }
- }
- return acc;
- }, {
- migrations: [],
- add: true
- }).get('migrations');
- }
- };
- module.exports.migrationsList = _migrationsList.default;
|