mysql-migration 1.2.3 → 1.2.5

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 CHANGED
@@ -1,25 +1,75 @@
1
- # MySQL Migration Database
1
+ <div align="center">
2
2
 
3
- A simple command-line tool for generating and running database migrations for MySQL.
3
+ # 🗄️ MySQL Migration Database
4
4
 
5
- ## Installation
5
+ **A command-line companion that helps you manage versioned MySQL schema changes from your Node.js projects.**
6
6
 
7
- You can install `mysql-migration` using npm: `npm install mysql-migration`
7
+ [![npm version](https://img.shields.io/npm/v/mysql-migration.svg?style=flat-square)](https://www.npmjs.com/package/mysql-migration)&nbsp;&nbsp;
8
+ [![License](https://img.shields.io/badge/license-Custom-blue.svg?style=flat-square)](LICENSE.md)&nbsp;&nbsp;
9
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg?style=flat-square)](https://nodejs.org/)
8
10
 
9
- ### Initialize the migrations table
11
+ </div>
10
12
 
11
- If you have not yet run any migrations, you need to initialize the migrations table by running the following command: `npx mysql-migration init`
13
+ ---
12
14
 
13
- <br>
15
+ ## ✨ Features
14
16
 
15
- ## Configuration
17
+ - 🎯 **Multi-database support** — Orchestrate migrations across different environments
18
+ - ⏱️ **Timestamped migration files** — Generated with a single command
19
+ - ⚡ **Forward and backward execution** — Run or roll back batches confidently
20
+ - 🔧 **Scriptable CLI** — Plugs into CI/CD pipelines via standard Node.js tooling
21
+ - 📦 **Zero dependencies** — Lightweight and fast
16
22
 
17
- The configuration file `mysql-migration.config.json` should export an object with the following properties:
23
+ ## 📋 Prerequisites
18
24
 
19
- - `host`: the MySQL server host
20
- - `database`: the name of the database to migrate
21
- - `user`: the MySQL user name
22
- - `password`: the MySQL user password
25
+ - **Node.js** v18 or later.
26
+ - **MySQL** instance reachable from where you run the CLI.
27
+ - A project workspace where you can store migration files and configuration.
28
+
29
+ ## 📦 Installation
30
+
31
+ Install locally within your project:
32
+
33
+ ```bash
34
+ npm install --save-dev mysql-migration
35
+ ```
36
+
37
+ Or run ad hoc without installing by prefixing commands with `npx`.
38
+
39
+ ## 🚀 Quick Start
40
+
41
+ **1️⃣ Initialize the project**
42
+
43
+ Run the init command to scaffold the `migrations/` directory and create a default configuration file:
44
+
45
+ ```bash
46
+ npx mysql-migration init
47
+ ```
48
+
49
+ **2️⃣ Configure your database**
50
+
51
+ Edit the generated `migrations/mysql-migration.config.json` file with your database credentials.
52
+
53
+ **3️⃣ Generate your first migration**
54
+
55
+ ```bash
56
+ npx mysql-migration create add_users_table main-db
57
+ ```
58
+
59
+ **4️⃣ Apply pending migrations**
60
+
61
+ ```bash
62
+ npx mysql-migration run main-db
63
+ ```
64
+
65
+ ## ⚙️ Configuration
66
+
67
+ The CLI reads settings from `mysql-migration.config.json`. Define each database you manage inside the `databases` object. Every entry requires the connection credentials documented below:
68
+
69
+ - `host`: MySQL server host name or IP.
70
+ - `database`: Database schema name.
71
+ - `user`: User with migration privileges.
72
+ - `password`: Corresponding password.
23
73
 
24
74
  ```json
25
75
  {
@@ -34,29 +84,95 @@ The configuration file `mysql-migration.config.json` should export an object wit
34
84
  }
35
85
  ```
36
86
 
37
- <br>
87
+ Add as many database entries as you need. You can then target each one via the CLI commands below.
88
+
89
+ ## 📖 Usage
90
+
91
+ ### 📝 Available Commands
92
+
93
+ | Command | Description |
94
+ |---------|-------------|
95
+ | `npx mysql-migration help` | 📚 Show all available commands |
96
+ | `npx mysql-migration init` | 🎬 Scaffold migrations directory and config |
97
+ | `npx mysql-migration create <name> <dbName>` | ✏️ Scaffold a timestamped migration file |
98
+ | `npx mysql-migration run [dbName]` | ▶️ Execute all pending migrations |
99
+ | `npx mysql-migration rollback <dbName> <batch>` | ⏪ Roll back migrations to specified batch |
100
+ | `npx mysql-migration batch <dbName>` | 📊 Display recorded batches |
101
+ | `npx mysql-migration to-cjs <dbName>` | 🔄 Convert migrations to CommonJS |
102
+ | `npx mysql-migration to-esm <dbName>` | 🔄 Convert migrations to ESM |
103
+
104
+ ### 🎬 Initialize Project
38
105
 
39
- ## Usage
106
+ ```bash
107
+ npx mysql-migration init
108
+ ```
109
+
110
+ Scaffolds the `migrations/` directory and creates a default `mysql-migration.config.json` file. Run this once when setting up the tool in a new project.
111
+
112
+ ### ✏️ Create a New Migration
113
+
114
+ ```bash
115
+ npx mysql-migration create migration-name database-name
116
+ ```
117
+
118
+ A new file appears in the `migrations/` directory, timestamped and ready for your SQL `up` and `down` statements.
119
+
120
+ ### ▶️ Run Pending Migrations
121
+
122
+ ```bash
123
+ npx mysql-migration run database-name
124
+ ```
125
+
126
+ All migrations that have not yet been applied will run sequentially for the selected database.
127
+
128
+ ### ⏪ Roll Back Migrations
129
+
130
+ ```bash
131
+ npx mysql-migration rollback database-name batch
132
+ ```
133
+
134
+ Use this when you need to revert the database state to the specified batch number.
135
+
136
+ ### 📊 Inspect Batches
137
+
138
+ ```bash
139
+ npx mysql-migration batch database-name
140
+ ```
141
+
142
+ View the recorded batches to understand which migrations were executed together.
143
+
144
+ ### 🔄 Convert Module System
145
+
146
+ If you need to switch your project between CommonJS (`require`) and ES Modules (`import/export`), you can batch convert your existing migration files.
147
+
148
+ **Convert to CommonJS:**
149
+ ```bash
150
+ npx mysql-migration to-cjs database-name
151
+ ```
152
+
153
+ **Convert to ES Modules:**
154
+ ```bash
155
+ npx mysql-migration to-esm database-name
156
+ ```
40
157
 
41
- ### Create a new migration
158
+ ## 🔧 Troubleshooting
42
159
 
43
- To create a new migration, run the following command:\
44
- &emsp;`npx mysql-migration create migration-name database-name`
160
+ - **Authentication errors**: Verify credentials in `mysql-migration.config.json` match your MySQL user.
161
+ - **Connection refused**: Ensure the MySQL server accepts remote connections from your host and the port is open.
162
+ - **Missing migrations folder**: Run `npx mysql-migration init` to scaffold the `migrations/` directory and configuration file.
45
163
 
46
- This will create a new migration file in the `migrations` directory with a timestamp and the name `migration-name`.
164
+ ## 💬 Support
47
165
 
48
- ### Running migrations
166
+ Use `npx mysql-migration help` to review commands, or open an issue on the repository if you encounter bugs or have enhancement ideas.
49
167
 
50
- To run pending migrations, run the following command:\
51
- &emsp;`npx mysql-migration run database-name(optional)`
168
+ ---
52
169
 
53
- This will run all migrations that have not yet been run.
170
+ <div align="center">
54
171
 
55
- ### Rolling back migrations
172
+ ### 📄 License
56
173
 
57
- To roll back the last migration, run the following command:\
58
- &emsp;`npx mysql-migration rollback database-name batch`
174
+ This project is distributed under a **custom non-commercial license**. Please review [`LICENSE.md`](LICENSE.md) for the full terms before using the software.
59
175
 
60
- This will roll back migrations to the given batch number.
176
+ Made with ❤️ by [SherKan](https://github.com/SherKan-n)
61
177
 
62
- > **Copyright (c) 2023-present [𝐒𝐡𝐞𝐫𝐊𝐚𝐧](https://github.com/SherKan-n). All Rights Reserved.**
178
+ </div>
package/index.js CHANGED
@@ -13,6 +13,8 @@ program
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
+ console.log(` to-esm <dbName> Convert migrations to ESM`);
17
+ console.log(` to-cjs <dbName> Convert migrations to CJS`);
16
18
  console.log(` help Show this help message\n`);
17
19
  });
18
20
  //---------------------------------------
@@ -41,4 +43,14 @@ program
41
43
  .description("Get the batched migrations")
42
44
  .action((dbName) => require("./src/commands/batch")(dbName));
43
45
  //---------------------------------------
46
+ program
47
+ .command("to-esm <dbName>")
48
+ .description("Convert migrations to ESM")
49
+ .action((dbName) => require("./src/commands/to-esm")(dbName));
50
+ //---------------------------------------
51
+ program
52
+ .command("to-cjs <dbName>")
53
+ .description("Convert migrations to CJS")
54
+ .action((dbName) => require("./src/commands/to-cjs")(dbName));
55
+ //---------------------------------------
44
56
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mysql-migration",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "description": "Migration for mysql database",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -21,6 +21,7 @@ const {
21
21
  getCurrentBatch,
22
22
  deleteMigration,
23
23
  } = require("../utils/functions");
24
+ const { loadModule } = require("../utils/moduleLoader");
24
25
  //==============================================================================
25
26
  async function back_migration(dbName, batch) {
26
27
  const connection = {};
@@ -68,7 +69,7 @@ async function back_migration(dbName, batch) {
68
69
  console.warn("\x1b[33m%s\x1b[0m", `Warning: Migration "${file.migration}" not found.`);
69
70
  } else {
70
71
  const migrationPath = `${currentPath}/migrations/${dbName}_db/${file.migration}`;
71
- const migration = require(migrationPath);
72
+ const migration = await loadModule(migrationPath);
72
73
  try {
73
74
  await migration.down(connection[dbName]);
74
75
  await deleteMigration(connection[dbName], file.migration, batchNumber);
@@ -78,8 +79,6 @@ async function back_migration(dbName, batch) {
78
79
  );
79
80
  } catch (err) {
80
81
  console.warn("\x1b[33m%s\x1b[0m", `Warning: "${err}" in migration "${file.migration}".`);
81
- } finally {
82
- delete require.cache[require.resolve(migrationPath)];
83
82
  }
84
83
  }
85
84
  }
@@ -2,6 +2,7 @@
2
2
  //---------------------------------------
3
3
  const fs = require("fs");
4
4
  const dayjs = require("dayjs");
5
+ const path = require("path");
5
6
  //---------------------------------------
6
7
  const currentPath = process.cwd();
7
8
  const config = require(`${currentPath}/migrations/mysql-migration.config.json`);
@@ -29,7 +30,22 @@ function create_migration(migrationName, dbName) {
29
30
  if (fs.existsSync(filePath))
30
31
  console.warn("\x1b[33m%s\x1b[0m", `Warning: File "${fileName}" already exists in the "migrations" directory.`);
31
32
  else {
32
- const dataText = `module.exports = {
33
+ let isEsm = false;
34
+ try {
35
+ const packageJsonPath = path.join(currentPath, "package.json");
36
+ if (fs.existsSync(packageJsonPath)) {
37
+ const packageJson = require(packageJsonPath);
38
+ if (packageJson.type === "module") {
39
+ isEsm = true;
40
+ }
41
+ }
42
+ } catch (e) {
43
+ // Ignore error, default to CJS
44
+ }
45
+
46
+ const exportPrefix = isEsm ? "export default" : "module.exports =";
47
+
48
+ const dataText = `${exportPrefix} {
33
49
  up: (connection) => {
34
50
  const query = "";
35
51
 
@@ -21,6 +21,7 @@ const {
21
21
  getCurrentBatch,
22
22
  insertMigration,
23
23
  } = require("../utils/functions");
24
+ const { loadModule } = require("../utils/moduleLoader");
24
25
  //==============================================================================
25
26
  async function run_migration(dbName) {
26
27
  const connection = {},
@@ -66,15 +67,13 @@ async function run_migration(dbName) {
66
67
  //---------------------------------------
67
68
  for (let file of pendingMigrations) {
68
69
  const migrationPath = `${currentPath}/migrations/${dbName}_db/${file}`;
69
- const migration = require(migrationPath);
70
+ const migration = await loadModule(migrationPath);
70
71
  try {
71
72
  await migration.up(connection[dbName]);
72
73
  await insertMigration(connection[dbName], file.replace(".js", ""), batch);
73
74
  console.log("\x1b[36m%s\x1b[0m", `Migrated: "${file}" successfully.`);
74
75
  } catch (err) {
75
76
  console.warn("\x1b[33m%s\x1b[0m", `Warning: "${err}" in migration "${file}".`);
76
- } finally {
77
- delete require.cache[require.resolve(migrationPath)];
78
77
  }
79
78
  }
80
79
  console.log("\x1b[32m%s\x1b[0m", "All migrations have been completed successfully.\n");
@@ -115,15 +114,13 @@ async function run_migration(dbName) {
115
114
  //---------------------------------------
116
115
  for (let [file, key, batch] of migrations) {
117
116
  const migrationPath = `${currentPath}/migrations/${key}_db/${file}`;
118
- const migration = require(migrationPath);
117
+ const migration = await loadModule(migrationPath);
119
118
  try {
120
119
  await migration.up(connection[key]);
121
120
  await insertMigration(connection[key], file.replace(".js", ""), batch);
122
121
  console.log("\x1b[36m%s\x1b[0m", `Migrated: "${file}" in database "${key}" successfully.`);
123
122
  } catch (err) {
124
123
  console.warn("\x1b[33m%s\x1b[0m", `Warning: "${err}" in migration "${file}" in database "${key}".`);
125
- } finally {
126
- delete require.cache[require.resolve(migrationPath)];
127
124
  }
128
125
  }
129
126
  console.log("\x1b[32m%s\x1b[0m", "All migrations have been completed successfully.\n");
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ //---------------------------------------
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ //---------------------------------------
6
+ const currentPath = process.cwd();
7
+ const config = require(`${currentPath}/migrations/mysql-migration.config.json`);
8
+ //---------------------------------------
9
+ function convert_to_cjs(dbName) {
10
+ //---------------------------------------
11
+ const databases = Object.keys(config.databases);
12
+ //---------------------------------------
13
+ if (!databases.includes(dbName)) {
14
+ console.error("\x1b[31m%s\x1b[0m", `Error: Invalid database name "${dbName}" can be: ${databases.join(", ")}.`);
15
+ process.exit(1);
16
+ }
17
+ //---------------------------------------
18
+ const migrationsDir = `${currentPath}/migrations/${dbName}_db`;
19
+ if (!fs.existsSync(migrationsDir)) {
20
+ console.error("\x1b[31m%s\x1b[0m", `Error: Migrations directory for "${dbName}" not found.`);
21
+ process.exit(1);
22
+ }
23
+ //---------------------------------------
24
+ const files = fs.readdirSync(migrationsDir);
25
+ let convertedCount = 0;
26
+
27
+ for (const file of files) {
28
+ if (file.endsWith(".js")) {
29
+ const filePath = path.join(migrationsDir, file);
30
+ let content = fs.readFileSync(filePath, "utf8");
31
+
32
+ // Simple check and replace for export default
33
+ if (content.includes("export default")) {
34
+ content = content.replace("export default", "module.exports =");
35
+ fs.writeFileSync(filePath, content);
36
+ console.log("\x1b[32m%s\x1b[0m", `Converted: "${file}" to CJS.`);
37
+ convertedCount++;
38
+ }
39
+ }
40
+ }
41
+
42
+ if (convertedCount === 0) {
43
+ console.log("\x1b[33m%s\x1b[0m", "No files needed conversion.");
44
+ } else {
45
+ console.log("\x1b[32m%s\x1b[0m", `\nSuccessfully converted ${convertedCount} files to CJS.`);
46
+ }
47
+ }
48
+ //---------------------------------------
49
+ module.exports = convert_to_cjs;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ //---------------------------------------
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ //---------------------------------------
6
+ const currentPath = process.cwd();
7
+ const config = require(`${currentPath}/migrations/mysql-migration.config.json`);
8
+ //---------------------------------------
9
+ function convert_to_esm(dbName) {
10
+ //---------------------------------------
11
+ const databases = Object.keys(config.databases);
12
+ //---------------------------------------
13
+ if (!databases.includes(dbName)) {
14
+ console.error("\x1b[31m%s\x1b[0m", `Error: Invalid database name "${dbName}" can be: ${databases.join(", ")}.`);
15
+ process.exit(1);
16
+ }
17
+ //---------------------------------------
18
+ const migrationsDir = `${currentPath}/migrations/${dbName}_db`;
19
+ if (!fs.existsSync(migrationsDir)) {
20
+ console.error("\x1b[31m%s\x1b[0m", `Error: Migrations directory for "${dbName}" not found.`);
21
+ process.exit(1);
22
+ }
23
+ //---------------------------------------
24
+ const files = fs.readdirSync(migrationsDir);
25
+ let convertedCount = 0;
26
+
27
+ for (const file of files) {
28
+ if (file.endsWith(".js")) {
29
+ const filePath = path.join(migrationsDir, file);
30
+ let content = fs.readFileSync(filePath, "utf8");
31
+
32
+ // Simple check and replace for module.exports
33
+ if (content.includes("module.exports =")) {
34
+ content = content.replace("module.exports =", "export default");
35
+ fs.writeFileSync(filePath, content);
36
+ console.log("\x1b[32m%s\x1b[0m", `Converted: "${file}" to ESM.`);
37
+ convertedCount++;
38
+ }
39
+ }
40
+ }
41
+
42
+ if (convertedCount === 0) {
43
+ console.log("\x1b[33m%s\x1b[0m", "No files needed conversion.");
44
+ } else {
45
+ console.log("\x1b[32m%s\x1b[0m", `\nSuccessfully converted ${convertedCount} files to ESM.`);
46
+ }
47
+ }
48
+ //---------------------------------------
49
+ module.exports = convert_to_esm;
@@ -0,0 +1,29 @@
1
+ const path = require("path");
2
+ const { pathToFileURL } = require("url");
3
+
4
+ /**
5
+ * Loads a module from the specified file path using dynamic import.
6
+ * Handles both CommonJS and ES Modules.
7
+ *
8
+ * @param {string} filePath - The absolute path to the file.
9
+ * @returns {Promise<any>} - The loaded module content.
10
+ */
11
+ async function loadModule(filePath) {
12
+ try {
13
+ // Convert path to file URL for Windows compatibility with dynamic import
14
+ const fileUrl = pathToFileURL(filePath).href;
15
+ const module = await import(fileUrl);
16
+
17
+ // If it's a CJS module loaded via import(), the default export holds the module.exports
18
+ // If it's an ESM module, we return the module namespace object or specific exports
19
+ // For this migration tool, we expect the migration object to be the default export or the module itself
20
+ if (module.default) {
21
+ return module.default;
22
+ }
23
+ return module;
24
+ } catch (error) {
25
+ throw new Error(`Failed to load module at ${filePath}: ${error.message}`);
26
+ }
27
+ }
28
+
29
+ module.exports = { loadModule };