mysql-migration 1.2.5 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -11
- package/index.d.ts +92 -0
- package/index.js +17 -12
- package/package.json +26 -7
- package/src/commands/back.js +69 -60
- package/src/commands/batch.js +47 -42
- package/src/commands/create.js +68 -51
- package/src/commands/init.js +31 -24
- package/src/commands/run.js +203 -131
- package/src/commands/to-cjs.js +20 -13
- package/src/commands/to-esm.js +20 -13
- package/src/utils/config.js +66 -0
- package/src/utils/connectionManager.js +102 -0
- package/src/utils/functions.js +94 -7
- package/src/utils/moduleLoader.js +0 -1
- package/.prettierrc.json +0 -10
package/README.md
CHANGED
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
- ⏱️ **Timestamped migration files** — Generated with a single command
|
|
19
19
|
- ⚡ **Forward and backward execution** — Run or roll back batches confidently
|
|
20
20
|
- 🔧 **Scriptable CLI** — Plugs into CI/CD pipelines via standard Node.js tooling
|
|
21
|
-
-
|
|
21
|
+
- 🔐 **Transactional migrations** — Automatic rollback on failure
|
|
22
|
+
- 👁️ **Dry-run mode** — Preview migrations without executing
|
|
23
|
+
- 📘 **TypeScript support** — Full type definitions included
|
|
22
24
|
|
|
23
25
|
## 📋 Prerequisites
|
|
24
26
|
|
|
@@ -56,20 +58,23 @@ Edit the generated `migrations/mysql-migration.config.json` file with your datab
|
|
|
56
58
|
npx mysql-migration create add_users_table main-db
|
|
57
59
|
```
|
|
58
60
|
|
|
59
|
-
**4️⃣
|
|
61
|
+
**4️⃣ Preview migrations (optional)**
|
|
60
62
|
|
|
61
63
|
```bash
|
|
62
|
-
npx mysql-migration run main-db
|
|
64
|
+
npx mysql-migration run main-db --dry-run
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**5️⃣ Apply pending migrations**
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx mysql-migration run main-db --transaction
|
|
63
71
|
```
|
|
64
72
|
|
|
65
73
|
## ⚙️ Configuration
|
|
66
74
|
|
|
67
|
-
The CLI reads settings from `mysql-migration.config.json`. Define each database you manage inside the `databases` object.
|
|
75
|
+
The CLI reads settings from `mysql-migration.config.json`. Define each database you manage inside the `databases` object.
|
|
68
76
|
|
|
69
|
-
|
|
70
|
-
- `database`: Database schema name.
|
|
71
|
-
- `user`: User with migration privileges.
|
|
72
|
-
- `password`: Corresponding password.
|
|
77
|
+
### Basic Configuration
|
|
73
78
|
|
|
74
79
|
```json
|
|
75
80
|
{
|
|
@@ -84,8 +89,6 @@ The CLI reads settings from `mysql-migration.config.json`. Define each database
|
|
|
84
89
|
}
|
|
85
90
|
```
|
|
86
91
|
|
|
87
|
-
Add as many database entries as you need. You can then target each one via the CLI commands below.
|
|
88
|
-
|
|
89
92
|
## 📖 Usage
|
|
90
93
|
|
|
91
94
|
### 📝 Available Commands
|
|
@@ -96,6 +99,8 @@ Add as many database entries as you need. You can then target each one via the C
|
|
|
96
99
|
| `npx mysql-migration init` | 🎬 Scaffold migrations directory and config |
|
|
97
100
|
| `npx mysql-migration create <name> <dbName>` | ✏️ Scaffold a timestamped migration file |
|
|
98
101
|
| `npx mysql-migration run [dbName]` | ▶️ Execute all pending migrations |
|
|
102
|
+
| `npx mysql-migration run [dbName] --dry-run` | 👁️ Preview migrations without executing |
|
|
103
|
+
| `npx mysql-migration run [dbName] --transaction` | 🔐 Run migrations with automatic rollback on error |
|
|
99
104
|
| `npx mysql-migration rollback <dbName> <batch>` | ⏪ Roll back migrations to specified batch |
|
|
100
105
|
| `npx mysql-migration batch <dbName>` | 📊 Display recorded batches |
|
|
101
106
|
| `npx mysql-migration to-cjs <dbName>` | 🔄 Convert migrations to CommonJS |
|
|
@@ -115,7 +120,51 @@ Scaffolds the `migrations/` directory and creates a default `mysql-migration.con
|
|
|
115
120
|
npx mysql-migration create migration-name database-name
|
|
116
121
|
```
|
|
117
122
|
|
|
118
|
-
A new file appears in the `migrations/` directory, timestamped and ready for your SQL `up` and `down` statements.
|
|
123
|
+
A new file appears in the `migrations/` directory, timestamped and ready for your SQL `up` and `down` statements. The generated migration uses modern async/await syntax:
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
module.exports = {
|
|
127
|
+
/**
|
|
128
|
+
* Run the migration
|
|
129
|
+
* @param {import('mysql2').Connection} connection
|
|
130
|
+
*/
|
|
131
|
+
up: async (connection) => {
|
|
132
|
+
const query = "CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255))";
|
|
133
|
+
await connection.promise().query(query);
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Rollback the migration
|
|
138
|
+
* @param {import('mysql2').Connection} connection
|
|
139
|
+
*/
|
|
140
|
+
down: async (connection) => {
|
|
141
|
+
const query = "DROP TABLE users";
|
|
142
|
+
await connection.promise().query(query);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 👁️ Dry-Run Mode
|
|
148
|
+
|
|
149
|
+
Preview migrations without executing them:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
npx mysql-migration run main-db --dry-run
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
This is useful for CI/CD pipelines or production deployments where you want to verify what will change before applying it.
|
|
156
|
+
|
|
157
|
+
### 🔐 Transactional Migrations
|
|
158
|
+
|
|
159
|
+
Run migrations with automatic rollback on failure:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
npx mysql-migration run main-db --transaction
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
If any migration fails, all migrations in the current batch will be automatically rolled back, keeping your database in a consistent state.
|
|
166
|
+
|
|
167
|
+
**Note:** Transactions work best with migrations that don't include DDL statements that cause implicit commits (like `CREATE TABLE`, `DROP TABLE`, etc. in MySQL).
|
|
119
168
|
|
|
120
169
|
### ▶️ Run Pending Migrations
|
|
121
170
|
|
|
@@ -146,20 +195,50 @@ View the recorded batches to understand which migrations were executed together.
|
|
|
146
195
|
If you need to switch your project between CommonJS (`require`) and ES Modules (`import/export`), you can batch convert your existing migration files.
|
|
147
196
|
|
|
148
197
|
**Convert to CommonJS:**
|
|
198
|
+
|
|
149
199
|
```bash
|
|
150
200
|
npx mysql-migration to-cjs database-name
|
|
151
201
|
```
|
|
152
202
|
|
|
153
203
|
**Convert to ES Modules:**
|
|
204
|
+
|
|
154
205
|
```bash
|
|
155
206
|
npx mysql-migration to-esm database-name
|
|
156
207
|
```
|
|
157
208
|
|
|
209
|
+
## 📘 TypeScript Support
|
|
210
|
+
|
|
211
|
+
The package includes full TypeScript type definitions. Import types in your project:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import type { Migration, Connection } from 'mysql-migration';
|
|
215
|
+
|
|
216
|
+
// Your migration file can use these types
|
|
217
|
+
const myMigration: Migration = {
|
|
218
|
+
up: async (connection: Connection) => {
|
|
219
|
+
// ...
|
|
220
|
+
},
|
|
221
|
+
down: async (connection: Connection) => {
|
|
222
|
+
// ...
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
For IDE autocomplete support, ensure you have the package installed and your TypeScript configuration includes `node` types.
|
|
228
|
+
|
|
158
229
|
## 🔧 Troubleshooting
|
|
159
230
|
|
|
160
231
|
- **Authentication errors**: Verify credentials in `mysql-migration.config.json` match your MySQL user.
|
|
161
232
|
- **Connection refused**: Ensure the MySQL server accepts remote connections from your host and the port is open.
|
|
162
233
|
- **Missing migrations folder**: Run `npx mysql-migration init` to scaffold the `migrations/` directory and configuration file.
|
|
234
|
+
- **Connection leaks**: The tool now automatically manages connections with proper cleanup, even on errors.
|
|
235
|
+
|
|
236
|
+
## 🔒 Security Best Practices
|
|
237
|
+
|
|
238
|
+
1. **Limit access** to the machine or CI secrets storage that holds your config file
|
|
239
|
+
2. **Never commit** `mysql-migration.config.json` with real passwords to version control
|
|
240
|
+
3. **Use dry-run mode** before running migrations in production
|
|
241
|
+
4. **Use transactional migrations** for safer deployments
|
|
163
242
|
|
|
164
243
|
## 💬 Support
|
|
165
244
|
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Connection } from "mysql2";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Database configuration for migrations
|
|
5
|
+
*/
|
|
6
|
+
export interface DatabaseConfig {
|
|
7
|
+
host: string;
|
|
8
|
+
user: string;
|
|
9
|
+
password: string;
|
|
10
|
+
database: string;
|
|
11
|
+
port?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Migration configuration file structure
|
|
16
|
+
*/
|
|
17
|
+
export interface MigrationConfig {
|
|
18
|
+
databases: Record<string, DatabaseConfig>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Migration file interface
|
|
23
|
+
*/
|
|
24
|
+
export interface Migration {
|
|
25
|
+
/**
|
|
26
|
+
* Run the migration
|
|
27
|
+
* @param connection - MySQL connection
|
|
28
|
+
*/
|
|
29
|
+
up(connection: Connection): Promise<void>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Rollback the migration
|
|
33
|
+
* @param connection - MySQL connection
|
|
34
|
+
*/
|
|
35
|
+
down(connection: Connection): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Migration record from database
|
|
40
|
+
*/
|
|
41
|
+
export interface MigrationRecord {
|
|
42
|
+
migration: string;
|
|
43
|
+
batch: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Connection manager for handling database connections
|
|
48
|
+
*/
|
|
49
|
+
export declare class ConnectionManager {
|
|
50
|
+
constructor();
|
|
51
|
+
createConnection(name: string, config: DatabaseConfig): Promise<Connection>;
|
|
52
|
+
getConnection(name: string): Connection | undefined;
|
|
53
|
+
closeConnection(name: string): Promise<void>;
|
|
54
|
+
closeAll(): Promise<void>;
|
|
55
|
+
withConnection<T>(
|
|
56
|
+
name: string,
|
|
57
|
+
config: DatabaseConfig,
|
|
58
|
+
callback: (connection: Connection) => Promise<T>
|
|
59
|
+
): Promise<T>;
|
|
60
|
+
withCleanup<T>(callback: () => Promise<T>): Promise<T>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Configuration utility functions
|
|
65
|
+
*/
|
|
66
|
+
export declare function loadConfig(configPath: string): MigrationConfig;
|
|
67
|
+
export declare function getDatabaseConfig(dbName: string, config: MigrationConfig): DatabaseConfig;
|
|
68
|
+
export declare function getDatabaseNames(config: MigrationConfig): string[];
|
|
69
|
+
export declare function isValidDatabase(dbName: string, config: MigrationConfig): boolean;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Database utility functions
|
|
73
|
+
*/
|
|
74
|
+
export declare function checkTableMigrations(connection: Connection): Promise<boolean>;
|
|
75
|
+
export declare function createTableMigrations(connection: Connection): Promise<boolean>;
|
|
76
|
+
export declare function getAllMigrations(connection: Connection, batch?: number | null): Promise<MigrationRecord[]>;
|
|
77
|
+
export declare function getCurrentBatch(connection: Connection): Promise<number>;
|
|
78
|
+
export declare function insertMigration(connection: Connection, migration: string, batch: number): Promise<boolean>;
|
|
79
|
+
export declare function deleteMigration(connection: Connection, migration: string, batch: number): Promise<boolean>;
|
|
80
|
+
export declare function getAllBatches(connection: Connection): Promise<MigrationRecord[]>;
|
|
81
|
+
export declare function beginTransaction(connection: Connection): Promise<void>;
|
|
82
|
+
export declare function commitTransaction(connection: Connection): Promise<void>;
|
|
83
|
+
export declare function rollbackTransaction(connection: Connection): Promise<void>;
|
|
84
|
+
export declare function withTransaction<T>(
|
|
85
|
+
connection: Connection,
|
|
86
|
+
callback: (connection: Connection) => Promise<T>
|
|
87
|
+
): Promise<T>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Module loader for CJS and ESM migrations
|
|
91
|
+
*/
|
|
92
|
+
export declare function loadModule(filePath: string): Promise<Migration>;
|
package/index.js
CHANGED
|
@@ -1,56 +1,61 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const { Command } = require("commander");
|
|
3
3
|
const program = new Command();
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
program
|
|
6
6
|
.command("help")
|
|
7
7
|
.description("Show all available commands")
|
|
8
8
|
.action(() => {
|
|
9
|
-
console.log(`\nUsage:
|
|
9
|
+
console.log(`\nUsage: mysql-migration <command> [options]\n`);
|
|
10
10
|
console.log(`Available commands:\n`);
|
|
11
11
|
console.log(` init Initialize migration`);
|
|
12
|
-
console.log(` run [dbName] Run migration`);
|
|
12
|
+
console.log(` run [dbName] Run migration (supports --dry-run, --transaction)`);
|
|
13
13
|
console.log(` rollback <dbName> <batch> Rollback migration`);
|
|
14
14
|
console.log(` create <name> <dbName> Create a new migration`);
|
|
15
15
|
console.log(` batch <dbName> Get the batched migrations`);
|
|
16
16
|
console.log(` to-esm <dbName> Convert migrations to ESM`);
|
|
17
17
|
console.log(` to-cjs <dbName> Convert migrations to CJS`);
|
|
18
18
|
console.log(` help Show this help message\n`);
|
|
19
|
+
console.log(`Run command options:\n`);
|
|
20
|
+
console.log(` --dry-run, -d Preview migrations without executing`);
|
|
21
|
+
console.log(` --transaction, -t Use transactions for migrations (auto rollback on error)\n`);
|
|
19
22
|
});
|
|
20
|
-
|
|
23
|
+
|
|
21
24
|
program
|
|
22
25
|
.command("init")
|
|
23
26
|
.description("Initialize migration")
|
|
24
27
|
.action(() => require("./src/commands/init"));
|
|
25
|
-
|
|
28
|
+
|
|
26
29
|
program
|
|
27
30
|
.command("run [dbName]")
|
|
28
31
|
.description("Run migration")
|
|
29
|
-
.
|
|
30
|
-
|
|
32
|
+
.option("-d, --dry-run", "Preview migrations without executing")
|
|
33
|
+
.option("-t, --transaction", "Use transactions for migrations (auto rollback on error)")
|
|
34
|
+
.action((dbName, options) => require("./src/commands/run")(dbName, options.dryRun, options.transaction));
|
|
35
|
+
|
|
31
36
|
program
|
|
32
37
|
.command("rollback <dbName> <batch>")
|
|
33
38
|
.description("Rollback migration")
|
|
34
39
|
.action((dbName, batch) => require("./src/commands/back")(dbName, batch));
|
|
35
|
-
|
|
40
|
+
|
|
36
41
|
program
|
|
37
42
|
.command("create <migrationName> <dbName>")
|
|
38
43
|
.description("Create a new migration")
|
|
39
44
|
.action((migrationName, dbName) => require("./src/commands/create")(migrationName, dbName));
|
|
40
|
-
|
|
45
|
+
|
|
41
46
|
program
|
|
42
47
|
.command("batch <dbName>")
|
|
43
48
|
.description("Get the batched migrations")
|
|
44
49
|
.action((dbName) => require("./src/commands/batch")(dbName));
|
|
45
|
-
|
|
50
|
+
|
|
46
51
|
program
|
|
47
52
|
.command("to-esm <dbName>")
|
|
48
53
|
.description("Convert migrations to ESM")
|
|
49
54
|
.action((dbName) => require("./src/commands/to-esm")(dbName));
|
|
50
|
-
|
|
55
|
+
|
|
51
56
|
program
|
|
52
57
|
.command("to-cjs <dbName>")
|
|
53
58
|
.description("Convert migrations to CJS")
|
|
54
59
|
.action((dbName) => require("./src/commands/to-cjs")(dbName));
|
|
55
|
-
|
|
60
|
+
|
|
56
61
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mysql-migration",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Migration for mysql database",
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "Migration for mysql database with TypeScript support, transactions, and environment variables",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
6
7
|
"bin": {
|
|
7
8
|
"mysql-migration": "./index.js"
|
|
8
9
|
},
|
|
@@ -21,13 +22,31 @@
|
|
|
21
22
|
"mysql2",
|
|
22
23
|
"database migration",
|
|
23
24
|
"mysql migration database",
|
|
24
|
-
"mysql migration tool"
|
|
25
|
+
"mysql migration tool",
|
|
26
|
+
"typescript",
|
|
27
|
+
"transactions",
|
|
28
|
+
"dry-run",
|
|
29
|
+
"environment variables"
|
|
25
30
|
],
|
|
26
31
|
"dependencies": {
|
|
27
|
-
"commander": "^14.0.
|
|
28
|
-
"dayjs": "^1.11.
|
|
29
|
-
"mysql2": "^3.
|
|
32
|
+
"commander": "^14.0.2",
|
|
33
|
+
"dayjs": "^1.11.19",
|
|
34
|
+
"mysql2": "^3.16.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^20.19.27",
|
|
38
|
+
"typescript": "^5.9.3"
|
|
30
39
|
},
|
|
31
40
|
"author": "SherKan",
|
|
32
|
-
"license": "SEE LICENSE IN LICENSE.md"
|
|
41
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18.0.0"
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"index.js",
|
|
47
|
+
"index.d.ts",
|
|
48
|
+
"src/",
|
|
49
|
+
"README.md",
|
|
50
|
+
"LICENSE.md"
|
|
51
|
+
]
|
|
33
52
|
}
|
package/src/commands/back.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
const fs = require("fs");
|
|
4
|
-
const mysql = require("mysql2");
|
|
5
4
|
const path = require("path");
|
|
6
|
-
|
|
5
|
+
|
|
7
6
|
const currentPath = process.cwd();
|
|
8
7
|
const configPath = path.join(currentPath, "migrations", "mysql-migration.config.json");
|
|
8
|
+
|
|
9
9
|
if (!fs.existsSync(configPath)) {
|
|
10
10
|
console.error(
|
|
11
11
|
"\x1b[31m%s\x1b[0m",
|
|
@@ -13,7 +13,9 @@ if (!fs.existsSync(configPath)) {
|
|
|
13
13
|
);
|
|
14
14
|
process.exit(1);
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
const ConnectionManager = require("../utils/connectionManager");
|
|
18
|
+
const { loadConfig, getDatabaseConfig, isValidDatabase } = require("../utils/config");
|
|
17
19
|
const {
|
|
18
20
|
checkTableMigrations,
|
|
19
21
|
createTableMigrations,
|
|
@@ -22,68 +24,75 @@ const {
|
|
|
22
24
|
deleteMigration,
|
|
23
25
|
} = require("../utils/functions");
|
|
24
26
|
const { loadModule } = require("../utils/moduleLoader");
|
|
25
|
-
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Roll back previously applied migrations for a database.
|
|
30
|
+
* @param {string} dbName - Target database name.
|
|
31
|
+
* @param {string|number} batch - Batch number threshold for rollback.
|
|
32
|
+
* @returns {Promise<void>}
|
|
33
|
+
*/
|
|
26
34
|
async function back_migration(dbName, batch) {
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
if (!dbName) {
|
|
36
|
+
console.error("\x1b[31m%s\x1b[0m", `Error: Database name is required.`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
const batchNumber = parseInt(batch);
|
|
41
|
+
if (isNaN(batchNumber)) {
|
|
42
|
+
console.error("\x1b[31m%s\x1b[0m", `Error: Invalid batch number.`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const config = loadConfig(configPath);
|
|
47
|
+
const connectionManager = new ConnectionManager();
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
if (!isValidDatabase(dbName, config)) {
|
|
39
51
|
console.error("\x1b[31m%s\x1b[0m", `Error: Invalid database name "${dbName}".`);
|
|
40
52
|
process.exit(1);
|
|
41
53
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
`Migration "${file.migration}" has been successfully rolled back.`
|
|
79
|
-
);
|
|
80
|
-
} catch (err) {
|
|
81
|
-
console.warn("\x1b[33m%s\x1b[0m", `Warning: "${err}" in migration "${file.migration}".`);
|
|
54
|
+
|
|
55
|
+
const dbConfig = getDatabaseConfig(dbName, config);
|
|
56
|
+
const migrationsDir = path.join(currentPath, "migrations", `${dbName}_db`);
|
|
57
|
+
|
|
58
|
+
await connectionManager.withConnection(dbName, dbConfig, async (connection) => {
|
|
59
|
+
const tableMigrations = await checkTableMigrations(connection);
|
|
60
|
+
if (!tableMigrations) await createTableMigrations(connection);
|
|
61
|
+
|
|
62
|
+
const currentBatch = await getCurrentBatch(connection);
|
|
63
|
+
if (batchNumber >= currentBatch) {
|
|
64
|
+
console.error("\x1b[31m%s\x1b[0m", `Error: Invalid batch number, the current batch is "${currentBatch}".`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const migrations = await getAllMigrations(connection, batchNumber);
|
|
69
|
+
if (migrations.length === 0) {
|
|
70
|
+
console.log("\x1b[32m%s\x1b[0m", `Nothing to rollback for batch greater than ${batchNumber}.`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for (let file of migrations) {
|
|
75
|
+
const migrationFile = path.join(migrationsDir, `${file.migration}.js`);
|
|
76
|
+
if (!fs.existsSync(migrationFile)) {
|
|
77
|
+
console.warn("\x1b[33m%s\x1b[0m", `Warning: Migration "${file.migration}" not found.`);
|
|
78
|
+
} else {
|
|
79
|
+
const migration = await loadModule(migrationFile);
|
|
80
|
+
try {
|
|
81
|
+
await migration.down(connection);
|
|
82
|
+
await deleteMigration(connection, file.migration, batchNumber);
|
|
83
|
+
console.log(
|
|
84
|
+
"\x1b[32m%s\x1b[0m",
|
|
85
|
+
`Migration "${file.migration}" has been successfully rolled back.`
|
|
86
|
+
);
|
|
87
|
+
} catch (err) {
|
|
88
|
+
console.warn("\x1b[33m%s\x1b[0m", `Warning: "${err}" in migration "${file.migration}".`);
|
|
89
|
+
}
|
|
82
90
|
}
|
|
83
91
|
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
});
|
|
93
|
+
} finally {
|
|
94
|
+
await connectionManager.closeAll();
|
|
95
|
+
}
|
|
87
96
|
}
|
|
88
|
-
|
|
97
|
+
|
|
89
98
|
module.exports = back_migration;
|
package/src/commands/batch.js
CHANGED
|
@@ -1,53 +1,58 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
2
|
+
|
|
3
|
+
const path = require("path");
|
|
4
|
+
|
|
5
5
|
const currentPath = process.cwd();
|
|
6
|
-
const
|
|
6
|
+
const configPath = path.join(currentPath, "migrations", "mysql-migration.config.json");
|
|
7
|
+
|
|
8
|
+
const ConnectionManager = require("../utils/connectionManager");
|
|
9
|
+
const { loadConfig, getDatabaseConfig, isValidDatabase } = require("../utils/config");
|
|
7
10
|
const { checkTableMigrations, createTableMigrations, getAllBatches, getCurrentBatch } = require("../utils/functions");
|
|
8
|
-
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Display migrations grouped by batch for a database.
|
|
14
|
+
* @param {string} dbName - Target database name.
|
|
15
|
+
* @returns {Promise<void>}
|
|
16
|
+
*/
|
|
9
17
|
async function show_batched_migrations(dbName) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
if (!dbName) {
|
|
19
|
+
console.error("\x1b[31m%s\x1b[0m", `Error: Database name is required.`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const config = loadConfig(configPath);
|
|
24
|
+
const connectionManager = new ConnectionManager();
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
if (!isValidDatabase(dbName, config)) {
|
|
15
28
|
console.error("\x1b[31m%s\x1b[0m", `Error: Invalid database name "${dbName}".`);
|
|
16
29
|
process.exit(1);
|
|
17
30
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
|
|
32
|
+
const dbConfig = getDatabaseConfig(dbName, config);
|
|
33
|
+
|
|
34
|
+
await connectionManager.withConnection(dbName, dbConfig, async (connection) => {
|
|
35
|
+
const tableMigrations = await checkTableMigrations(connection);
|
|
36
|
+
if (!tableMigrations) await createTableMigrations(connection);
|
|
37
|
+
|
|
38
|
+
const currentBatch = await getCurrentBatch(connection);
|
|
39
|
+
const migrations = await getAllBatches(connection);
|
|
40
|
+
|
|
41
|
+
if (migrations.length > 0) {
|
|
42
|
+
console.log("\x1b[32m%s\x1b[0m", `Batched migrations for database "${dbName}":`);
|
|
43
|
+
migrations.forEach((migration) => {
|
|
44
|
+
const migrationName = migration.migration.split("_").slice(4).join("_");
|
|
45
|
+
console.log(`[Batch ${migration.batch}] - ${migrationName}`);
|
|
46
|
+
});
|
|
47
|
+
} else {
|
|
48
|
+
console.log("\x1b[32m%s\x1b[0m", `No batched migrations for database "${dbName}".`);
|
|
24
49
|
}
|
|
50
|
+
|
|
51
|
+
console.log("\x1b[36m%s\x1b[0m", `Current batch for database "${dbName}": ${currentBatch}`);
|
|
25
52
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
//---------------------------------------
|
|
30
|
-
const currentBatch = await getCurrentBatch(connection[dbName]);
|
|
31
|
-
//---------------------------------------
|
|
32
|
-
getAllBatches(connection[dbName])
|
|
33
|
-
.then((migrations) => {
|
|
34
|
-
if (migrations.length > 0) {
|
|
35
|
-
console.log("\x1b[32m%s\x1b[0m", `Batched migrations for database "${dbName}":`);
|
|
36
|
-
migrations.forEach((migration) => {
|
|
37
|
-
const migrationName = migration.migration.split("_").slice(4).join("_");
|
|
38
|
-
console.log(`[Batch ${migration.batch}] - ${migrationName}`);
|
|
39
|
-
});
|
|
40
|
-
} else console.log("\x1b[32m%s\x1b[0m", `No batched migrations for database "${dbName}".`);
|
|
41
|
-
connection[dbName].end();
|
|
42
|
-
})
|
|
43
|
-
.catch((err) => {
|
|
44
|
-
console.error("\x1b[31m%s\x1b[0m", `Error: ${err}`);
|
|
45
|
-
connection[dbName].end();
|
|
46
|
-
})
|
|
47
|
-
.finally(() => {
|
|
48
|
-
console.log("\x1b[36m%s\x1b[0m", `Current batch for database "${dbName}": ${currentBatch}`);
|
|
49
|
-
});
|
|
50
|
-
} else console.error("\x1b[31m%s\x1b[0m", `Error: Database name is empty !`);
|
|
53
|
+
} finally {
|
|
54
|
+
await connectionManager.closeAll();
|
|
55
|
+
}
|
|
51
56
|
}
|
|
52
|
-
|
|
57
|
+
|
|
53
58
|
module.exports = show_batched_migrations;
|