├── .gitignore ├── .gitattributes ├── media └── logotype.png ├── fixtures ├── sql │ └── 1.sql ├── unsafe │ ├── 1-create-type.sql │ └── 2-alter-type.sql └── js │ ├── 1.js │ └── 2.js ├── .editorconfig ├── .travis.yml ├── package.json ├── license ├── cli.js ├── test.js ├── index.js └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.js text eol=lf 3 | -------------------------------------------------------------------------------- /media/logotype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/floatdrop/migratio/HEAD/media/logotype.png -------------------------------------------------------------------------------- /fixtures/sql/1.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | CREATE TABLE test2 ( 4 | id serial PRIMARY KEY 5 | ); 6 | 7 | -- +migrate Down 8 | 9 | DROP TABLE IF EXISTS test2; 10 | -------------------------------------------------------------------------------- /fixtures/unsafe/1-create-type.sql: -------------------------------------------------------------------------------- 1 | -- +migrate Up 2 | 3 | CREATE TYPE action_type AS ENUM ( 4 | 'download', 5 | 'delete', 6 | 'upload' 7 | ); 8 | 9 | -- +migrate Down 10 | 11 | DROP TYPE IF EXISTS action_type; 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [{package.json,*.yml}] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: required 3 | dist: trusty 4 | addons: 5 | postgresql: "9.6" 6 | services: 7 | - postgresql 8 | before_script: 9 | - psql -c 'create database test;' -U postgres 10 | node_js: 11 | - '7' 12 | - '6' 13 | - '5' 14 | - '4' 15 | -------------------------------------------------------------------------------- /fixtures/js/1.js: -------------------------------------------------------------------------------- 1 | exports.up = async function (db) { 2 | await db.query(` 3 | CREATE TABLE test ( 4 | id serial PRIMARY KEY 5 | ) 6 | `); 7 | }; 8 | 9 | exports.down = async function (db) { 10 | await db.query(` 11 | DROP TABLE IF EXISTS test; 12 | `); 13 | }; 14 | -------------------------------------------------------------------------------- /fixtures/js/2.js: -------------------------------------------------------------------------------- 1 | exports.up = async function (db) { 2 | await db.query(` 3 | CREATE TABLE test2 ( 4 | id serial PRIMARY KEY, 5 | test int REFERENCES test (id) 6 | ) 7 | `); 8 | }; 9 | 10 | exports.down = async function (db) { 11 | await db.query(` 12 | DROP TABLE IF EXISTS test2; 13 | `); 14 | }; 15 | -------------------------------------------------------------------------------- /fixtures/unsafe/2-alter-type.sql: -------------------------------------------------------------------------------- 1 | -- +migrate NoTransaction 2 | -- +migrate Up 3 | 4 | ALTER TYPE action_type ADD VALUE 'restore'; 5 | 6 | -- +migrate Down 7 | 8 | -- Removing value from type is not supported in postgres 9 | -- See: http://stackoverflow.com/questions/25811017/how-to-delete-an-enum-type-in-postgres 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "migratio", 3 | "version": "2.0.3", 4 | "description": "Postgres migrations", 5 | "license": "MIT", 6 | "repository": "floatdrop/migratio", 7 | "author": { 8 | "name": "Vsevolod Strukchinsky", 9 | "email": "floatdrop@gmail.com", 10 | "url": "github.com/floatdrop" 11 | }, 12 | "bin": "cli.js", 13 | "engines": { 14 | "node": ">=4" 15 | }, 16 | "scripts": { 17 | "test": "xo && ava" 18 | }, 19 | "files": [ 20 | "index.js", 21 | "cli.js" 22 | ], 23 | "keywords": [ 24 | "postgres", 25 | "migration", 26 | "migratio", 27 | "cli" 28 | ], 29 | "dependencies": { 30 | "async-to-gen": "^1.3.2", 31 | "bluebird": "^3.4.7", 32 | "chalk": "^1.1.3", 33 | "is-async-supported": "^1.2.0", 34 | "meow": "^3.7.0", 35 | "pg-promise": "^7", 36 | "pkg-conf": "^1.1.3", 37 | "require-from-string": "^1.2.1" 38 | }, 39 | "devDependencies": { 40 | "ava": "*", 41 | "xo": "*" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Vsevolod Strukchinsky (github.com/floatdrop) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | const meow = require('meow'); 4 | const chalk = require('chalk'); 5 | const migratio = require('./'); 6 | 7 | const cli = meow(` 8 | Usage 9 | migratio [command] [options] 10 | 11 | Options 12 | -d, --directory Directory with migrations files [Default: ./migrations] 13 | -c, --connection Connection string to Postgres [Default: $DATABASE_URL] 14 | -r, --revision Specify revision to up/down to 15 | -t, --tableName Table name for metadata [Default: migratio] 16 | -s, --schema Schema name for table with metadata [Default: public] 17 | --unsafe Skip transaction and table locking 18 | 19 | Commands 20 | up Applies all migrations from current to latest 21 | down Rollbacks all migrations in current batch 22 | current Shows migrations in current batch 23 | 24 | Examples 25 | $ migratio 26 | 27 | Current batch: 28 | 000005-images.sql (batch:3) 29 | 000004-files.sql (batch:3) 30 | 000005-images.sql (batch:3) 31 | 32 | $ migratio down 33 | 34 | ↓ 000005-images.sql (batch:3) 35 | ↓ 000004-files.sql (batch:3) 36 | ↓ 000003-stats.sql (batch:3) 37 | 38 | $ migratio up 39 | 40 | ↑ 000003-stats.sql (batch:3) 41 | ↑ 000004-files.sql (batch:3) 42 | ↑ 000005-images.sql (batch:3) 43 | ↑ 000006-posts.sql (batch:3) 44 | `, { 45 | alias: { 46 | d: 'directory', 47 | c: 'connection', 48 | r: 'revision', 49 | t: 'tableName', 50 | s: 'schema', 51 | h: 'help' 52 | } 53 | // Do not set defaults, it will unset values in package.json 54 | }); 55 | 56 | const command = cli.input[0] || 'current'; 57 | 58 | console.log(); 59 | 60 | function error(err) { 61 | console.error(); 62 | console.error(` 💥 ${chalk.red(err.message)}`); 63 | console.error(); 64 | console.error(chalk.gray(err.stack)); 65 | console.error(); 66 | process.exit(1); 67 | } 68 | 69 | const options = cli.flags; 70 | options.verbose = true; 71 | 72 | if (command === 'current') { 73 | console.log(` ${chalk.gray('Current batch:')}`); 74 | migratio.current(options).catch(error); 75 | } else if (command === 'up') { 76 | migratio.up(options).catch(error); 77 | } else if (command === 'down') { 78 | migratio.down(options).catch(error); 79 | } 80 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import migratio from './'; 3 | 4 | process.env.DATABASE_URL = 'postgres://localhost:5432/test'; 5 | 6 | test.serial('up to revision', async t => { 7 | await migratio.up({ 8 | directory: './fixtures/js', 9 | revision: 1 10 | }); 11 | 12 | const batch = await migratio.current(); 13 | t.is(batch.length, 1); 14 | 15 | await migratio.down({ 16 | directory: './fixtures/js' 17 | }); 18 | }); 19 | 20 | test.serial('down to revision', async t => { 21 | await migratio.up({ 22 | directory: './fixtures/js' 23 | }); 24 | 25 | let batch = await migratio.current(); 26 | t.is(batch.length, 2); 27 | 28 | t.is(batch[0].batch, 1); 29 | t.is(batch[1].batch, 1); 30 | 31 | await migratio.down({ 32 | directory: './fixtures/js', 33 | revision: 1 34 | }); 35 | 36 | batch = await migratio.current(); 37 | t.is(batch.length, 1); 38 | 39 | await migratio.down({ 40 | directory: './fixtures/js' 41 | }); 42 | }); 43 | 44 | test.serial('js', async t => { 45 | await migratio.up({ 46 | directory: './fixtures/js' 47 | }); 48 | 49 | let batch = await migratio.current(); 50 | t.is(batch.length, 2); 51 | 52 | t.is(batch[0].batch, 1); 53 | t.is(batch[1].batch, 1); 54 | 55 | await migratio.down({ 56 | directory: './fixtures/js' 57 | }); 58 | 59 | batch = await migratio.current(); 60 | t.is(batch.length, 0); 61 | }); 62 | 63 | test.serial('sql', async t => { 64 | await migratio.up({ 65 | directory: './fixtures/sql' 66 | }); 67 | 68 | let batch = await migratio.current(); 69 | t.is(batch.length, 1); 70 | 71 | await migratio.down({ 72 | directory: './fixtures/sql' 73 | }); 74 | 75 | batch = await migratio.current(); 76 | t.is(batch.length, 0); 77 | }); 78 | 79 | test.serial('unsafe', async t => { 80 | await migratio.up({ 81 | directory: './fixtures/unsafe', 82 | revision: 1 83 | }); 84 | 85 | await migratio.up({ 86 | directory: './fixtures/unsafe', 87 | revision: 2, 88 | unsafe: true 89 | }); 90 | 91 | let batch = await migratio.current(); 92 | t.is(batch.length, 1); 93 | t.is(batch[0].batch, 2); 94 | 95 | await migratio.down({ 96 | directory: './fixtures/unsafe' 97 | }); 98 | 99 | batch = await migratio.current(); 100 | t.is(batch.length, 1); 101 | 102 | await migratio.down({ 103 | directory: './fixtures/unsafe' 104 | }); 105 | 106 | batch = await migratio.current(); 107 | t.is(batch.length, 0); 108 | }); 109 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | const coroutine = require('bluebird').coroutine; 6 | const pkgConf = require('pkg-conf'); 7 | const isAsyncSupported = require('is-async-supported'); 8 | const requireFromString = require('require-from-string'); 9 | 10 | function parseSql(str) { 11 | const lines = str.split('\n'); 12 | 13 | const result = { 14 | up: '', 15 | down: '', 16 | trash: '' 17 | }; 18 | 19 | let current = 'trash'; 20 | 21 | for (const line of lines) { 22 | if (line.indexOf('-- +migrate Up') === 0) { 23 | current = 'up'; 24 | continue; 25 | } 26 | 27 | if (line.indexOf('-- +migrate Down') === 0) { 28 | current = 'down'; 29 | continue; 30 | } 31 | 32 | result[current] = result[current] + line + '\n'; 33 | } 34 | 35 | return result; 36 | } 37 | 38 | function readMigration(filePath) { 39 | const ext = path.extname(filePath); 40 | let content = fs.readFileSync(filePath, 'utf8'); 41 | 42 | if (ext === '.js') { 43 | if (!isAsyncSupported()) { 44 | const asyncToGen = require('async-to-gen'); 45 | content = asyncToGen(content).toString(); 46 | } 47 | 48 | return requireFromString(content, filePath); 49 | } 50 | 51 | if (ext === '.sql') { 52 | const migration = parseSql(content); 53 | const up = migration.up; 54 | const down = migration.down; 55 | migration.up = t => t.query(up); 56 | migration.down = t => t.query(down); 57 | return migration; 58 | } 59 | } 60 | 61 | function ensureTable(db, options) { 62 | return db.query(`CREATE SCHEMA IF NOT EXISTS $1~;`, [options.schema]) 63 | .then(() => db.query(`SET search_path TO $1~;`, [options.schema])) 64 | .then(() => db.query(`CREATE TABLE IF NOT EXISTS $1~ ( 65 | id serial PRIMARY KEY, 66 | name text, 67 | revision integer, 68 | migration_time timestamp with time zone DEFAULT timezone('msk'::text, now()) NOT NULL, 69 | batch integer 70 | );`, [options.tableName])); 71 | } 72 | 73 | function lockup(db, options) { 74 | return db.query(`LOCK TABLE $1~;`, [options.tableName]); 75 | } 76 | 77 | function transactio(work) { 78 | return function (options) { 79 | options = Object.assign({ 80 | connection: process.env.DATABASE_URL, 81 | directory: './migrations', 82 | tableName: 'migratio', 83 | schema: 'public', 84 | unsafe: false 85 | }, pkgConf.sync('migratio'), options); 86 | 87 | let db = options.db; 88 | let pgp; 89 | 90 | if (db === undefined) { 91 | pgp = require('pg-promise')({noWarnings: true}); 92 | db = pgp(options.connection); 93 | } 94 | 95 | if (options.unsafe === true) { 96 | return ensureTable(db, options) 97 | .then(() => work(db, options)); 98 | } 99 | 100 | return db.tx(t => ensureTable(t, options) 101 | .then(() => lockup(t, options)) 102 | .then(() => work(t, options))); 103 | }; 104 | } 105 | 106 | function validFileName(file) { 107 | const ext = path.extname(file); 108 | if (ext !== '.js' && ext !== '.sql') { 109 | return false; 110 | } 111 | 112 | return /^\d+/.test(file); 113 | } 114 | 115 | function byRevision(a, b) { 116 | const aRev = parseInt(a, 10); 117 | const bRev = parseInt(b, 10); 118 | 119 | return aRev - bRev; 120 | } 121 | 122 | const current = coroutine(function * (t, options) { 123 | let migrations; 124 | 125 | if (options.revision === undefined) { 126 | const lastBatch = (yield t.one(`SELECT coalesce(MAX(batch), 0) AS max FROM $1~`, [options.tableName])).max; 127 | migrations = yield t.query('SELECT * FROM $1~ WHERE batch = $2 ORDER BY id ASC', [options.tableName, lastBatch]); 128 | } else { 129 | migrations = yield t.query('SELECT * FROM $1~ WHERE revision >= $2 ORDER BY id ASC', [options.tableName, options.revision]); 130 | } 131 | 132 | if (options.verbose) { 133 | migrations.forEach(m => console.log(` ${m.name} (batch:${m.batch})`)); 134 | 135 | if (migrations.length === 0) { 136 | console.log(` No migrations were applied`); 137 | } 138 | } 139 | 140 | return migrations; 141 | }); 142 | 143 | const up = coroutine(function * (t, options) { 144 | const latestMigration = (yield current(t, Object.assign({}, options, { 145 | revision: undefined, 146 | verbose: false 147 | }))).pop() || {}; 148 | const latestRevision = latestMigration.revision === undefined ? -1 : latestMigration.revision; 149 | const latestBatch = latestMigration.batch || 0; 150 | const currentBatch = latestBatch + 1; 151 | 152 | const files = fs.readdirSync(options.directory) 153 | .filter(validFileName) 154 | .filter(file => parseInt(file, 10) > latestRevision) 155 | .filter(file => parseInt(file, 10) <= (options.revision || Infinity)) 156 | .sort(byRevision); 157 | 158 | if (files.length === 0 && options.verbose) { 159 | console.log(` Database is up to date`); 160 | } 161 | 162 | for (const file of files) { 163 | const filePath = path.resolve(path.join(options.directory, file)); 164 | const revision = parseInt(file, 10); 165 | 166 | if (options.verbose) { 167 | console.log(` ↑ ${file} (batch:${currentBatch})`); 168 | } 169 | 170 | const migration = readMigration(filePath); 171 | yield migration.up(t); 172 | 173 | yield t.query(`INSERT INTO $1~ (name, revision, batch) VALUES ($2, $3, $4)`, [options.tableName, file, revision, currentBatch]); 174 | } 175 | }); 176 | 177 | const down = coroutine(function * (t, options) { 178 | const currentBatch = yield current(t, Object.assign({}, options, {verbose: false})); 179 | 180 | if (currentBatch.length === 0 && options.verbose) { 181 | console.log(` No migrations found in database`); 182 | } 183 | 184 | if (options.revision !== undefined) { 185 | // Remove migration with revision from be removed 186 | currentBatch.shift(); 187 | } 188 | 189 | for (const migration of currentBatch.reverse()) { 190 | const filePath = path.resolve(path.join(options.directory, migration.name)); 191 | 192 | if (options.verbose) { 193 | console.log(` ↓ ${migration.name} (batch:${migration.batch})`); 194 | } 195 | 196 | const currentMigration = readMigration(filePath); 197 | yield currentMigration.down(t); 198 | 199 | yield t.query('DELETE FROM $1~ WHERE id = $2', [options.tableName, migration.id]); 200 | } 201 | }); 202 | 203 | module.exports.up = transactio(up); 204 | module.exports.down = transactio(down); 205 | module.exports.current = transactio(current); 206 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |

2 |
3 | migratio 4 |
5 |
6 |
7 |

8 | 9 | > Automated migrations for Postgres 10 | 11 | [![Build Status](https://travis-ci.org/floatdrop/migratio.svg?branch=master)](https://travis-ci.org/floatdrop/migratio) 12 | 13 | ## Install 14 | 15 | ``` 16 | $ npm install --save migratio 17 | ``` 18 | 19 | 20 | ## Usage 21 | 22 | Create directory `migrations` with [migrations](#migrations-format) and use migratio: 23 | 24 | ```js 25 | const migratio = require('migratio'); 26 | 27 | await migratio.current({ 28 | connection: 'postgres://localhost/db', 29 | verbose: true 30 | }); 31 | // 000005-images.sql (batch:3) 32 | // 000004-files.sql (batch:3) 33 | // 000003-stats.sql (batch:3) 34 | 35 | await migratio.up({ 36 | connection: 'postgres://localhost/db', 37 | verbose: true 38 | }); 39 | // ↑ 000006-posts.sql (batch:4) 40 | 41 | await migratio.down({ 42 | connection: 'postgres://localhost/db', 43 | verbose: true 44 | }); 45 | // ↓ 000005-images.sql (batch:3) 46 | // ↓ 000004-files.sql (batch:3) 47 | // ↓ 000003-stats.sql (batch:3) 48 | ``` 49 | 50 | ## Migrations format 51 | 52 | All migrations files should start with _revision_ (digits) followed by `-` and name of migration. For example `000001-init.js` and `000002-users.sql` is valid file names. 53 | 54 | Migrations will be applied in order of numbers in front of filename. 55 | 56 | Migration process is running in transaction with lock on `migrations` table. If one of migrations failed – all batch will be reverted. 57 | 58 | ### JavaScript format 59 | 60 | Migration file with extension `.js` is treated as module, that exports two functions: 61 | 62 | - `up` – contains code to apply migration 63 | - `down` – contains code to revert migration 64 | 65 | These functions must return Promise. If these functions are generators, they will be wrapped in `co`. 66 | 67 | ```js 68 | exports.up = async function (db) { 69 | await db.query(` 70 | CREATE TABLE test ( 71 | id serial PRIMARY KEY 72 | ) 73 | `); 74 | }; 75 | 76 | exports.down = async function (db) { 77 | await db.query(` 78 | DROP TABLE IF EXISTS test; 79 | `); 80 | }; 81 | ``` 82 | 83 | ### SQL format 84 | 85 | Migration file with extension `.sql` is treated as file with SQL instructions. Instructions to apply migration should be placed after `-- +migrate Up` and instructions to revert migration should be placed after `-- +migrate Down`. 86 | 87 | ```sql 88 | -- +migrate Up 89 | 90 | CREATE TABLE test ( 91 | id serial PRIMARY KEY 92 | ); 93 | 94 | -- +migrate Down 95 | 96 | DROP TABLE IF EXISTS test; 97 | ``` 98 | 99 | ## Configuring defaults 100 | 101 | Migratio supports overriding default values with `migraio` section in `package.json`: 102 | 103 | ```js 104 | { 105 | "migratio": { 106 | "directory": "migrations", 107 | "tableName": "migrations" 108 | } 109 | } 110 | ``` 111 | 112 | ## API 113 | 114 | ### up(options) 115 | 116 | Applies all migrations from current to latest available. 117 | 118 | #### options 119 | 120 | ##### connection 121 | 122 | Type: `string`
123 | Default: `process.env.DATABASE_URL` 124 | 125 | Connection string to Postgres database. 126 | 127 | 128 | ##### db 129 | 130 | Type: `Database` 131 | 132 | [Database](http://vitaly-t.github.io/pg-promise/Database.html) object. Will be used _instead_ of `connection`. 133 | 134 | 135 | ##### directory 136 | 137 | Type: `string`
138 | Default: `./migrations` 139 | 140 | Directory with migrations. 141 | 142 | ##### revision 143 | 144 | Type: `Number`
145 | Default: `Infinity` 146 | 147 | Latest revision to up to. 148 | 149 | ##### unsafe 150 | 151 | Type: `Boolean`
152 | Default: `false` 153 | 154 | Disables meta-table locking. 155 | 156 | ##### verbose 157 | 158 | Type: `boolean`
159 | Default: `false` 160 | 161 | Enables output. 162 | 163 | ##### tableName 164 | 165 | Type: `string`
166 | Default: `migratio` 167 | 168 | Table in which migratio will store metadata. 169 | 170 | ### down(options) 171 | 172 | Rollbacks migrations in current batch. 173 | 174 | #### options 175 | 176 | ##### connection 177 | 178 | Type: `string`
179 | Default: `process.env.DATABASE_URL` 180 | 181 | Connection string to Postgres database. 182 | 183 | ##### directory 184 | 185 | Type: `string`
186 | Default: `./migrations` 187 | 188 | Directory with migrations. 189 | 190 | ##### unsafe 191 | 192 | Type: `Boolean`
193 | Default: `false` 194 | 195 | Disables meta-table locking. 196 | 197 | ##### verbose 198 | 199 | Type: `boolean`
200 | Default: `false` 201 | 202 | Enables output. 203 | 204 | ##### tableName 205 | 206 | Type: `string`
207 | Default: `migratio` 208 | 209 | Table in which migratio will store metadata. 210 | 211 | ### current(options) 212 | 213 | Shows current batch. 214 | 215 | ##### connection 216 | 217 | Type: `string`
218 | Default: `process.env.DATABASE_URL` 219 | 220 | Connection string to Postgres database. 221 | 222 | ##### unsafe 223 | 224 | Type: `Boolean`
225 | Default: `false` 226 | 227 | Disables meta-table locking. 228 | 229 | ##### verbose 230 | 231 | Type: `boolean`
232 | Default: `false` 233 | 234 | Enables output. 235 | 236 | ##### revision 237 | 238 | Type: `Number`
239 | Default: `Infinity` 240 | 241 | First revision to show info about. 242 | 243 | ##### tableName 244 | 245 | Type: `string`
246 | Default: `migratio` 247 | 248 | Table in which migratio will store metadata. 249 | 250 | ## CLI 251 | 252 | ``` 253 | $ npm install --global migratio 254 | ``` 255 | 256 | ``` 257 | $ migratio --help 258 | 259 | Usage 260 | migratio [command] [options] 261 | 262 | Options 263 | -d, --directory Directory with migrations files [Default: ./migrations] 264 | -c, --connection Connection string to Postgres [Default: $DATABASE_URL] 265 | -r, --revision Specify revision to up/down to 266 | -t, --table Table name for metadata [Default: migratio] 267 | -s, --schema Schema name for table with metadata [Default: public] 268 | --unsafe Skip transaction and table locking 269 | 270 | Commands 271 | 272 | up Applies all migrations from current to latest 273 | down Rollbacks all migrations in current batch 274 | current Shows migrations in current batch 275 | 276 | Examples 277 | $ migratio 278 | 279 | Current batch: 280 | 000005-images.sql (batch:3) 281 | 000004-files.sql (batch:3) 282 | 000003-stats.sql (batch:3) 283 | 284 | $ migratio down 285 | 286 | ↓ 000005-images.sql (batch:3) 287 | ↓ 000004-files.sql (batch:3) 288 | ↓ 000003-stats.sql (batch:3) 289 | 290 | $ migratio up 291 | 292 | ↑ 000003-stats.sql (batch:3) 293 | ↑ 000004-files.sql (batch:3) 294 | ↑ 000005-images.sql (batch:3) 295 | ↑ 000006-posts.sql (batch:3) 296 | ``` 297 | 298 | 299 | ## License 300 | 301 | MIT © [Vsevolod Strukchinsky](http://github.com/floatdrop) 302 | --------------------------------------------------------------------------------