mysql-migration 1.2.2 → 1.2.3

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.
@@ -0,0 +1,10 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": false,
4
+ "tabWidth": 4,
5
+ "useTabs": false,
6
+ "trailingComma": "es5",
7
+ "printWidth": 120,
8
+ "arrowParens": "always",
9
+ "endOfLine": "lf"
10
+ }
package/index.js CHANGED
@@ -1,44 +1,44 @@
1
1
  #!/usr/bin/env node
2
- const { Command } = require('commander');
2
+ const { Command } = require("commander");
3
3
  const program = new Command();
4
4
  //---------------------------------------
5
5
  program
6
- .command('help')
7
- .description('Show all available commands')
8
- .action(() => {
9
- console.log(`\nUsage: cli-tool <command> [options]\n`);
10
- console.log(`Available commands:\n`);
11
- console.log(` init Initialize migration`);
12
- console.log(` run [dbName] Run migration`);
13
- console.log(` rollback <dbName> <batch> Rollback migration`);
14
- console.log(` create <name> <dbName> Create a new migration`);
15
- console.log(` batch <dbName> Get the batched migrations`);
16
- console.log(` help Show this help message\n`);
17
- });
6
+ .command("help")
7
+ .description("Show all available commands")
8
+ .action(() => {
9
+ console.log(`\nUsage: cli-tool <command> [options]\n`);
10
+ console.log(`Available commands:\n`);
11
+ console.log(` init Initialize migration`);
12
+ console.log(` run [dbName] Run migration`);
13
+ console.log(` rollback <dbName> <batch> Rollback migration`);
14
+ console.log(` create <name> <dbName> Create a new migration`);
15
+ console.log(` batch <dbName> Get the batched migrations`);
16
+ console.log(` help Show this help message\n`);
17
+ });
18
18
  //---------------------------------------
19
19
  program
20
- .command('init')
21
- .description('Initialize migration')
22
- .action(() => require('./src/commands/init'));
20
+ .command("init")
21
+ .description("Initialize migration")
22
+ .action(() => require("./src/commands/init"));
23
23
  //---------------------------------------
24
24
  program
25
- .command('run [dbName]')
26
- .description('Run migration')
27
- .action((dbName) => require('./src/commands/run')(dbName));
25
+ .command("run [dbName]")
26
+ .description("Run migration")
27
+ .action((dbName) => require("./src/commands/run")(dbName));
28
28
  //---------------------------------------
29
29
  program
30
- .command('rollback <dbName> <batch>')
31
- .description('Rollback migration')
32
- .action((dbName, batch) => require('./src/commands/back')(dbName, batch));
30
+ .command("rollback <dbName> <batch>")
31
+ .description("Rollback migration")
32
+ .action((dbName, batch) => require("./src/commands/back")(dbName, batch));
33
33
  //---------------------------------------
34
34
  program
35
- .command('create <migrationName> <dbName>')
36
- .description('Create a new migration')
37
- .action((migrationName, dbName) => require('./src/commands/create')(migrationName, dbName));
35
+ .command("create <migrationName> <dbName>")
36
+ .description("Create a new migration")
37
+ .action((migrationName, dbName) => require("./src/commands/create")(migrationName, dbName));
38
38
  //---------------------------------------
39
39
  program
40
- .command('batch <dbName>')
41
- .description('Get the batched migrations')
42
- .action((dbName) => require('./src/commands/batch')(dbName));
40
+ .command("batch <dbName>")
41
+ .description("Get the batched migrations")
42
+ .action((dbName) => require("./src/commands/batch")(dbName));
43
43
  //---------------------------------------
44
- program.parse(process.argv);
44
+ program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mysql-migration",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Migration for mysql database",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -16,13 +16,17 @@
16
16
  "keywords": [
17
17
  "mysql migration",
18
18
  "migration",
19
- "mysql"
19
+ "mysql",
20
+ "database",
21
+ "mysql2",
22
+ "database migration",
23
+ "mysql migration database",
24
+ "mysql migration tool"
20
25
  ],
21
26
  "dependencies": {
22
- "commander": "^13.1.0",
23
- "fs": "0.0.1-security",
24
- "moment": "^2.30.1",
25
- "mysql2": "^3.13.0"
27
+ "commander": "^14.0.1",
28
+ "dayjs": "^1.11.18",
29
+ "mysql2": "^3.15.3"
26
30
  },
27
31
  "author": "SherKan",
28
32
  "license": "SEE LICENSE IN LICENSE.md"
@@ -1,65 +1,90 @@
1
- 'use strict';
2
- //==============================================================================
3
- const fs = require('fs');
4
- const mysql = require('mysql2');
5
- //---------------------------------------
6
- const currentPath = process.cwd();
7
- const config = require(`${currentPath}/migrations/mysql-migration.config.json`);
8
- const { checkTableMigrations, createTableMigrations, getAllMigrations, getCurrentBatch, deleteMigration } = require("../utils/functions");
9
- //==============================================================================
10
- async function back_migration(dbName, batch) {
11
- const connection = {};
12
- const databases = config.databases;
13
- //---------------------------------------
14
- if (dbName) {
15
- const batchNumber = parseInt(batch);
16
- if (isNaN(batchNumber)) {
17
- console.error('\x1b[31m%s\x1b[0m', `Error: Invalid batch number.`);
18
- process.exit(1);
19
- }
20
- //---------------------------------------
21
- if (!databases[dbName]) {
22
- console.error('\x1b[31m%s\x1b[0m', `Error: Invalid database name "${dbName}".`);
23
- process.exit(1);
24
- }
25
- //---------------------------------------
26
- connection[dbName] = mysql.createConnection(databases[dbName]);
27
- connection[dbName].connect((err) => {
28
- if (err) {
29
- console.error('\x1b[31m%s\x1b[0m', `Error: Unable to connect to database "${dbName}".\n${err}`);
30
- process.exit(1);
31
- }
32
- });
33
- //---------------------------------------
34
- const tableMigrations = await checkTableMigrations(connection[dbName]);
35
- if (!tableMigrations) await createTableMigrations(connection[dbName]);
36
- //---------------------------------------
37
- const currentBatch = await getCurrentBatch(connection[dbName]);
38
- if (batchNumber >= currentBatch) {
39
- console.error('\x1b[31m%s\x1b[0m', `Error: Invalid batch number, the current batch is "${currentBatch}".`);
40
- process.exit(1);
41
- }
42
- const migrations = await getAllMigrations(connection[dbName], batchNumber);
43
- //---------------------------------------
44
- for (let file of migrations) {
45
- if (!fs.existsSync(`${currentPath}/migrations/${dbName}_db/${file.migration}.js`)) {
46
- console.warn('\x1b[33m%s\x1b[0m', `Warning: Migration "${file.migration}" not found.`);
47
- }
48
- else {
49
- const migration = require(`${currentPath}/migrations/${dbName}_db/${file.migration}`);
50
- try {
51
- await migration.down(connection[dbName]);
52
- await deleteMigration(connection[dbName], file.migration, batchNumber);
53
- console.log('\x1b[32m%s\x1b[0m', `Migration "${file.migration}" has been successfully rolled back.`);
54
- }
55
- catch (err) {
56
- console.warn('\x1b[33m%s\x1b[0m', `Warning: "${err}" in migration "${file.migration}".`);
57
- }
58
- }
59
- }
60
- connection[dbName].end();
61
- }
62
- else console.error('\x1b[31m%s\x1b[0m', `Error: Database name is empty !`);
63
- }
64
- //==============================================================================
65
- module.exports = back_migration;
1
+ "use strict";
2
+ //==============================================================================
3
+ const fs = require("fs");
4
+ const mysql = require("mysql2");
5
+ const path = require("path");
6
+ //---------------------------------------
7
+ const currentPath = process.cwd();
8
+ const configPath = path.join(currentPath, "migrations", "mysql-migration.config.json");
9
+ if (!fs.existsSync(configPath)) {
10
+ console.error(
11
+ "\x1b[31m%s\x1b[0m",
12
+ 'Error: Config file "mysql-migration.config.json" not found. Run "mysql-migration init" first.'
13
+ );
14
+ process.exit(1);
15
+ }
16
+ const config = require(configPath);
17
+ const {
18
+ checkTableMigrations,
19
+ createTableMigrations,
20
+ getAllMigrations,
21
+ getCurrentBatch,
22
+ deleteMigration,
23
+ } = require("../utils/functions");
24
+ //==============================================================================
25
+ async function back_migration(dbName, batch) {
26
+ const connection = {};
27
+ const databases = config.databases;
28
+
29
+ //---------------------------------------
30
+ if (dbName) {
31
+ const batchNumber = parseInt(batch);
32
+ if (isNaN(batchNumber)) {
33
+ console.error("\x1b[31m%s\x1b[0m", `Error: Invalid batch number.`);
34
+ process.exit(1);
35
+ }
36
+ //---------------------------------------
37
+ if (!databases[dbName]) {
38
+ console.error("\x1b[31m%s\x1b[0m", `Error: Invalid database name "${dbName}".`);
39
+ process.exit(1);
40
+ }
41
+ //---------------------------------------
42
+ connection[dbName] = mysql.createConnection(databases[dbName]);
43
+ try {
44
+ await connection[dbName].promise().connect();
45
+ } catch (err) {
46
+ console.error("\x1b[31m%s\x1b[0m", `Error: Unable to connect to database "${dbName}".\n${err}`);
47
+ process.exit(1);
48
+ }
49
+ //---------------------------------------
50
+ const tableMigrations = await checkTableMigrations(connection[dbName]);
51
+ if (!tableMigrations) await createTableMigrations(connection[dbName]);
52
+ //---------------------------------------
53
+ const currentBatch = await getCurrentBatch(connection[dbName]);
54
+ if (batchNumber >= currentBatch) {
55
+ console.error("\x1b[31m%s\x1b[0m", `Error: Invalid batch number, the current batch is "${currentBatch}".`);
56
+ await connection[dbName].promise().end();
57
+ process.exit(1);
58
+ }
59
+ const migrations = await getAllMigrations(connection[dbName], batchNumber);
60
+ if (migrations.length === 0) {
61
+ console.log("\x1b[32m%s\x1b[0m", `Nothing to rollback for batch greater than ${batchNumber}.`);
62
+ await connection[dbName].promise().end();
63
+ process.exit(0);
64
+ }
65
+ //---------------------------------------
66
+ for (let file of migrations) {
67
+ if (!fs.existsSync(`${currentPath}/migrations/${dbName}_db/${file.migration}.js`)) {
68
+ console.warn("\x1b[33m%s\x1b[0m", `Warning: Migration "${file.migration}" not found.`);
69
+ } else {
70
+ const migrationPath = `${currentPath}/migrations/${dbName}_db/${file.migration}`;
71
+ const migration = require(migrationPath);
72
+ try {
73
+ await migration.down(connection[dbName]);
74
+ await deleteMigration(connection[dbName], file.migration, batchNumber);
75
+ console.log(
76
+ "\x1b[32m%s\x1b[0m",
77
+ `Migration "${file.migration}" has been successfully rolled back.`
78
+ );
79
+ } catch (err) {
80
+ console.warn("\x1b[33m%s\x1b[0m", `Warning: "${err}" in migration "${file.migration}".`);
81
+ } finally {
82
+ delete require.cache[require.resolve(migrationPath)];
83
+ }
84
+ }
85
+ }
86
+ await connection[dbName].promise().end();
87
+ } else console.error("\x1b[31m%s\x1b[0m", `Error: Database name is empty !`);
88
+ }
89
+ //==============================================================================
90
+ module.exports = back_migration;
@@ -1,6 +1,6 @@
1
- 'use strict';
1
+ "use strict";
2
2
  //==============================================================================
3
- const mysql = require('mysql2');
3
+ const mysql = require("mysql2");
4
4
  //---------------------------------------
5
5
  const currentPath = process.cwd();
6
6
  const config = require(`${currentPath}/migrations/mysql-migration.config.json`);
@@ -12,14 +12,14 @@ async function show_batched_migrations(dbName) {
12
12
  //---------------------------------------
13
13
  if (dbName) {
14
14
  if (!databases[dbName]) {
15
- console.error('\x1b[31m%s\x1b[0m', `Error: Invalid database name "${dbName}".`);
15
+ console.error("\x1b[31m%s\x1b[0m", `Error: Invalid database name "${dbName}".`);
16
16
  process.exit(1);
17
17
  }
18
18
  //---------------------------------------
19
19
  connection[dbName] = mysql.createConnection(databases[dbName]);
20
20
  connection[dbName].connect((err) => {
21
21
  if (err) {
22
- console.error('\x1b[31m%s\x1b[0m', `Error: Unable to connect to database "${dbName}".\n${err}`);
22
+ console.error("\x1b[31m%s\x1b[0m", `Error: Unable to connect to database "${dbName}".\n${err}`);
23
23
  process.exit(1);
24
24
  }
25
25
  });
@@ -29,24 +29,25 @@ async function show_batched_migrations(dbName) {
29
29
  //---------------------------------------
30
30
  const currentBatch = await getCurrentBatch(connection[dbName]);
31
31
  //---------------------------------------
32
- getAllBatches(connection[dbName]).then((migrations) => {
33
- if (migrations.length > 0) {
34
- console.log('\x1b[32m%s\x1b[0m', `Batched migrations for database "${dbName}":`);
35
- migrations.forEach((migration) => {
36
- const migrationName = migration.migration.split('_').slice(4).join('_');
37
- console.log(`[Batch ${migration.batch}] - ${migrationName}`);
38
- });
39
- }
40
- else console.log('\x1b[32m%s\x1b[0m', `No batched migrations for database "${dbName}".`);
41
- connection[dbName].end();
42
- }).catch((err) => {
43
- console.error('\x1b[31m%s\x1b[0m', `Error: ${err}`);
44
- connection[dbName].end();
45
- }).finally(() => {
46
- console.log('\x1b[36m%s\x1b[0m', `Current batch for database "${dbName}": ${currentBatch}`);
47
- });
48
- }
49
- else console.error('\x1b[31m%s\x1b[0m', `Error: Database name is empty !`);
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 !`);
50
51
  }
51
52
  //==============================================================================
52
- module.exports = show_batched_migrations;
53
+ module.exports = show_batched_migrations;
@@ -1,31 +1,33 @@
1
- 'use strict';
1
+ "use strict";
2
2
  //---------------------------------------
3
- const fs = require('fs');
4
- const moment = require('moment');
3
+ const fs = require("fs");
4
+ const dayjs = require("dayjs");
5
5
  //---------------------------------------
6
6
  const currentPath = process.cwd();
7
7
  const config = require(`${currentPath}/migrations/mysql-migration.config.json`);
8
8
  //---------------------------------------
9
9
  function create_migration(migrationName, dbName) {
10
10
  if (!migrationName) {
11
- console.error('\x1b[31m%s\x1b[0m', `Error: Migration name is empty !`);
11
+ console.error("\x1b[31m%s\x1b[0m", `Error: Migration name is empty !`);
12
12
  process.exit(1);
13
13
  }
14
14
  //---------------------------------------
15
15
  const databases = Object.keys(config.databases);
16
16
  //---------------------------------------
17
17
  if (!databases.includes(dbName)) {
18
- console.error('\x1b[31m%s\x1b[0m', `Error: Invalid database name "${dbName}" can be: ${databases.join(', ')}.`);
18
+ console.error("\x1b[31m%s\x1b[0m", `Error: Invalid database name "${dbName}" can be: ${databases.join(", ")}.`);
19
19
  process.exit(1);
20
20
  }
21
21
  //---------------------------------------
22
- if (!fs.existsSync(`${currentPath}/migrations/${dbName}_db`)) fs.mkdirSync(`${currentPath}/migrations/${dbName}_db`);
22
+ if (!fs.existsSync(`${currentPath}/migrations/${dbName}_db`))
23
+ fs.mkdirSync(`${currentPath}/migrations/${dbName}_db`);
23
24
  //---------------------------------------
24
- const currentDate = moment().format('YYYY_MM_DD_HHmmss');
25
+ const currentDate = dayjs().format("YYYY_MM_DD_HHmmss");
25
26
  const fileName = `${currentDate}_${migrationName}.js`;
26
27
  const filePath = `${currentPath}/migrations/${dbName}_db/${fileName}`;
27
28
  //---------------------------------------
28
- if (fs.existsSync(filePath)) console.warn('\x1b[33m%s\x1b[0m', `Warning: File "${fileName}" already exists in the "migrations" directory.`);
29
+ if (fs.existsSync(filePath))
30
+ console.warn("\x1b[33m%s\x1b[0m", `Warning: File "${fileName}" already exists in the "migrations" directory.`);
29
31
  else {
30
32
  const dataText = `module.exports = {
31
33
  up: (connection) => {
@@ -51,10 +53,10 @@ function create_migration(migrationName, dbName) {
51
53
  });
52
54
  });
53
55
  }
54
- };`
56
+ };`;
55
57
  fs.writeFileSync(filePath, dataText);
56
- console.log('\x1b[32m%s\x1b[0m', `Created migration file: "${fileName}".`);
58
+ console.log("\x1b[32m%s\x1b[0m", `Created migration file: "${fileName}".`);
57
59
  }
58
60
  }
59
61
  //---------------------------------------
60
- module.exports = create_migration;
62
+ module.exports = create_migration;
@@ -1,18 +1,29 @@
1
- 'use strict';
1
+ "use strict";
2
2
  //---------------------------------------
3
- const fs = require('fs');
3
+ const fs = require("fs");
4
4
  //---------------------------------------
5
5
  const currentPath = process.cwd();
6
6
  //---------------------------------------
7
7
  if (!fs.existsSync(`${currentPath}/migrations`)) fs.mkdirSync(`${currentPath}/migrations`);
8
- if (!fs.existsSync(`${currentPath}/migrations/mysql-migration.config.json`)) fs.writeFileSync(`${currentPath}/migrations/mysql-migration.config.json`, JSON.stringify({
9
- "databases": {
10
- "db_name": {
11
- "host": "db_host",
12
- "user": "db_user",
13
- "password": "db_password",
14
- "database": "db_name"
15
- }
16
- }
17
- }, null, 3));
18
- console.log('\x1b[32m%s\x1b[0m', `Created migration config file: "mysql-migration.config.json" in the "migrations" directory.`);
8
+ if (!fs.existsSync(`${currentPath}/migrations/mysql-migration.config.json`))
9
+ fs.writeFileSync(
10
+ `${currentPath}/migrations/mysql-migration.config.json`,
11
+ JSON.stringify(
12
+ {
13
+ databases: {
14
+ db_name: {
15
+ host: "db_host",
16
+ user: "db_user",
17
+ password: "db_password",
18
+ database: "db_name",
19
+ },
20
+ },
21
+ },
22
+ null,
23
+ 3
24
+ )
25
+ );
26
+ console.log(
27
+ "\x1b[32m%s\x1b[0m",
28
+ `Created migration config file: "mysql-migration.config.json" in the "migrations" directory.`
29
+ );
@@ -1,103 +1,134 @@
1
- 'use strict';
2
- //==============================================================================
3
- const fs = require('fs');
4
- const mysql = require('mysql2');
5
- //---------------------------------------
6
- const currentPath = process.cwd();
7
- const config = require(`${currentPath}/migrations/mysql-migration.config.json`);
8
- const { checkTableMigrations, createTableMigrations, getAllMigrations, getCurrentBatch, insertMigration } = require("../utils/functions");
9
- //==============================================================================
10
- async function run_migration(dbName) {
11
- const connection = {}, migrations = [];
12
- const databases = config.databases;
13
- //---------------------------------------
14
- if (dbName) {
15
- if (!databases[dbName]) {
16
- console.error('\x1b[31m%s\x1b[0m', `Error: Invalid database name "${dbName}".`);
17
- process.exit(1);
18
- }
19
- //---------------------------------------
20
- connection[dbName] = mysql.createConnection(databases[dbName]);
21
- connection[dbName].connect((err) => {
22
- if (err) {
23
- console.error('\x1b[31m%s\x1b[0m', `Error: Unable to connect to database "${dbName}".\n${err}`);
24
- process.exit(1);
25
- }
26
- });
27
- //---------------------------------------
28
- const tableMigrations = await checkTableMigrations(connection[dbName]);
29
- if (!tableMigrations) await createTableMigrations(connection[dbName]);
30
- //---------------------------------------
31
- const batch = await getCurrentBatch(connection[dbName]) + 1;
32
- const allMigrations = await getAllMigrations(connection[dbName]);
33
- const migration = fs.readdirSync(`${currentPath}/migrations/${dbName}_db`);
34
- //---------------------------------------
35
- const migrations = migration.filter(val => !allMigrations.some(val2 => val.includes(val2.migration)));
36
- //---------------------------------------
37
- if (migrations.length === 0) {
38
- console.log('\x1b[32m%s\x1b[0m', 'Nothing to migrate.\n');
39
- connection[dbName].end();
40
- process.exit(1);
41
- }
42
- //---------------------------------------
43
- for (let file of migrations) {
44
- const migration = require(`${currentPath}/migrations/${dbName}_db/${file}`);
45
- try {
46
- await migration.up(connection[dbName]);
47
- await insertMigration(connection[dbName], file.replace('.js', ''), batch);
48
- console.log('\x1b[36m%s\x1b[0m', `Migrated: "${file}" successfully.`);
49
- }
50
- catch (err) {
51
- console.warn('\x1b[33m%s\x1b[0m', `Warning: "${err}" in migration "${file}".`);
52
- }
53
- }
54
- console.log('\x1b[32m%s\x1b[0m', 'All migrations have been completed successfully.\n');
55
- connection[dbName].end();
56
- }
57
- else {
58
- for (let key in databases) {
59
- connection[key] = mysql.createConnection(databases[key]);
60
- connection[key].connect((err) => {
61
- if (err) {
62
- console.error('\x1b[31m%s\x1b[0m', `Error: Unable to connect to database "${key}".`);
63
- process.exit(1);
64
- }
65
- });
66
- //---------------------------------------
67
- const tableMigrations = await checkTableMigrations(connection[key]);
68
- if (!tableMigrations) await createTableMigrations(connection[key]);
69
- //---------------------------------------
70
- const batch = await getCurrentBatch(connection[key]) + 1;
71
- const allMigrations = await getAllMigrations(connection[key]);
72
- //---------------------------------------
73
- if (!fs.existsSync(`${currentPath}/migrations/${key}_db`)) continue;
74
- const migration = fs.readdirSync(`${currentPath}/migrations/${key}_db`);
75
- //---------------------------------------
76
- const diffMigrations = migration.filter(val => !allMigrations.some(val2 => val.includes(val2.migration)));
77
- //---------------------------------------
78
- for (let m of diffMigrations) migrations.push([m, key, batch]);
79
- }
80
- //---------------------------------------
81
- if (migrations.length === 0) {
82
- console.log('\x1b[32m%s\x1b[0m', 'Nothing to migrate.\n');
83
- for (let key in connection) connection[key].end();
84
- process.exit(1);
85
- }
86
- //---------------------------------------
87
- for (let [file, key, batch] of migrations) {
88
- const migration = require(`${currentPath}/migrations/${key}_db/${file}`);
89
- try {
90
- await migration.up(connection[key]);
91
- await insertMigration(connection[key], file.replace('.js', ''), batch);
92
- console.log('\x1b[36m%s\x1b[0m', `Migrated: "${file}" in database "${key}" successfully.`);
93
- }
94
- catch (err) {
95
- console.warn('\x1b[33m%s\x1b[0m', `Warning: "${err}" in migration "${file}" in database "${key}".`);
96
- }
97
- }
98
- console.log('\x1b[32m%s\x1b[0m', 'All migrations have been completed successfully.\n');
99
- for (let key in connection) connection[key].end();
100
- }
101
- }
102
- //==============================================================================
103
- module.exports = run_migration;
1
+ "use strict";
2
+ //==============================================================================
3
+ const fs = require("fs");
4
+ const mysql = require("mysql2");
5
+ const path = require("path");
6
+ //---------------------------------------
7
+ const currentPath = process.cwd();
8
+ const configPath = path.join(currentPath, "migrations", "mysql-migration.config.json");
9
+ if (!fs.existsSync(configPath)) {
10
+ console.error(
11
+ "\x1b[31m%s\x1b[0m",
12
+ 'Error: Config file "mysql-migration.config.json" not found. Run "mysql-migration init" first.'
13
+ );
14
+ process.exit(1);
15
+ }
16
+ const config = require(configPath);
17
+ const {
18
+ checkTableMigrations,
19
+ createTableMigrations,
20
+ getAllMigrations,
21
+ getCurrentBatch,
22
+ insertMigration,
23
+ } = require("../utils/functions");
24
+ //==============================================================================
25
+ async function run_migration(dbName) {
26
+ const connection = {},
27
+ migrations = [];
28
+ const databases = config.databases;
29
+ //---------------------------------------
30
+ if (dbName) {
31
+ if (!databases[dbName]) {
32
+ console.error("\x1b[31m%s\x1b[0m", `Error: Invalid database name "${dbName}".`);
33
+ process.exit(1);
34
+ }
35
+ //---------------------------------------
36
+ connection[dbName] = mysql.createConnection(databases[dbName]);
37
+ try {
38
+ await connection[dbName].promise().connect();
39
+ } catch (err) {
40
+ console.error("\x1b[31m%s\x1b[0m", `Error: Unable to connect to database "${dbName}".\n${err}`);
41
+ process.exit(1);
42
+ }
43
+ //---------------------------------------
44
+ const tableMigrations = await checkTableMigrations(connection[dbName]);
45
+ if (!tableMigrations) await createTableMigrations(connection[dbName]);
46
+ //---------------------------------------
47
+ const batch = (await getCurrentBatch(connection[dbName])) + 1;
48
+ const allMigrations = await getAllMigrations(connection[dbName]);
49
+ const migrationsDir = `${currentPath}/migrations/${dbName}_db`;
50
+ if (!fs.existsSync(migrationsDir)) {
51
+ console.log("\x1b[32m%s\x1b[0m", "Nothing to migrate.\n");
52
+ await connection[dbName].promise().end();
53
+ process.exit(0);
54
+ }
55
+ const migrationFiles = fs.readdirSync(migrationsDir);
56
+ //---------------------------------------
57
+ const pendingMigrations = migrationFiles.filter(
58
+ (val) => !allMigrations.some((val2) => val.includes(val2.migration))
59
+ );
60
+ //---------------------------------------
61
+ if (pendingMigrations.length === 0) {
62
+ console.log("\x1b[32m%s\x1b[0m", "Nothing to migrate.\n");
63
+ await connection[dbName].promise().end();
64
+ process.exit(0);
65
+ }
66
+ //---------------------------------------
67
+ for (let file of pendingMigrations) {
68
+ const migrationPath = `${currentPath}/migrations/${dbName}_db/${file}`;
69
+ const migration = require(migrationPath);
70
+ try {
71
+ await migration.up(connection[dbName]);
72
+ await insertMigration(connection[dbName], file.replace(".js", ""), batch);
73
+ console.log("\x1b[36m%s\x1b[0m", `Migrated: "${file}" successfully.`);
74
+ } catch (err) {
75
+ console.warn("\x1b[33m%s\x1b[0m", `Warning: "${err}" in migration "${file}".`);
76
+ } finally {
77
+ delete require.cache[require.resolve(migrationPath)];
78
+ }
79
+ }
80
+ console.log("\x1b[32m%s\x1b[0m", "All migrations have been completed successfully.\n");
81
+ await connection[dbName].promise().end();
82
+ } else {
83
+ for (let key in databases) {
84
+ connection[key] = mysql.createConnection(databases[key]);
85
+ try {
86
+ await connection[key].promise().connect();
87
+ } catch (err) {
88
+ console.error("\x1b[31m%s\x1b[0m", `Error: Unable to connect to database "${key}".`);
89
+ process.exit(1);
90
+ }
91
+ //---------------------------------------
92
+ const tableMigrations = await checkTableMigrations(connection[key]);
93
+ if (!tableMigrations) await createTableMigrations(connection[key]);
94
+ //---------------------------------------
95
+ const batch = (await getCurrentBatch(connection[key])) + 1;
96
+
97
+ const allMigrations = await getAllMigrations(connection[key]);
98
+ //---------------------------------------
99
+ if (!fs.existsSync(`${currentPath}/migrations/${key}_db`)) continue;
100
+ const migration = fs.readdirSync(`${currentPath}/migrations/${key}_db`);
101
+ //---------------------------------------
102
+ const diffMigrations = migration.filter(
103
+ (val) => !allMigrations.some((val2) => val.includes(val2.migration))
104
+ );
105
+ //---------------------------------------
106
+ for (let m of diffMigrations) migrations.push([m, key, batch]);
107
+ }
108
+
109
+ //---------------------------------------
110
+ if (migrations.length === 0) {
111
+ console.log("\x1b[32m%s\x1b[0m", "Nothing to migrate.\n");
112
+ for (let key in connection) await connection[key].promise().end();
113
+ process.exit(0);
114
+ }
115
+ //---------------------------------------
116
+ for (let [file, key, batch] of migrations) {
117
+ const migrationPath = `${currentPath}/migrations/${key}_db/${file}`;
118
+ const migration = require(migrationPath);
119
+ try {
120
+ await migration.up(connection[key]);
121
+ await insertMigration(connection[key], file.replace(".js", ""), batch);
122
+ console.log("\x1b[36m%s\x1b[0m", `Migrated: "${file}" in database "${key}" successfully.`);
123
+ } catch (err) {
124
+ 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
+ }
128
+ }
129
+ console.log("\x1b[32m%s\x1b[0m", "All migrations have been completed successfully.\n");
130
+ for (let key in connection) await connection[key].promise().end();
131
+ }
132
+ }
133
+ //==============================================================================
134
+ module.exports = run_migration;
@@ -1,79 +1,66 @@
1
- function checkTableMigrations(connection) {
2
- return new Promise((resolve) => {
3
- connection.query("SELECT `id` FROM `migrations` LIMIT 1;", (error) => {
4
- if (error) resolve(false);
5
- else resolve(true);
6
- });
7
- });
8
- }
9
- //---------------------------------------
10
- function createTableMigrations(connection) {
11
- return new Promise((resolve) => {
12
- const query = "CREATE TABLE `migrations` (\
13
- `id` INT NOT NULL AUTO_INCREMENT,\
14
- `migration` VARCHAR(255) NOT NULL,\
15
- `batch` INT NOT NULL DEFAULT 1,\
16
- `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\
17
- PRIMARY KEY (`id`));"
18
- connection.query(query, (error) => {
19
- if (error) throw error;
20
- resolve(true);
21
- });
22
- });
23
- }
24
- //---------------------------------------
25
- function getAllMigrations(connection, batch = null) {
26
- return new Promise((resolve) => {
27
- let query = "SELECT `migration` FROM `migrations`";
28
- if (batch) query += " WHERE `batch` > ?;";
29
- connection.query(query, [batch], (error, results) => {
30
- if (error) throw error;
31
- if (results?.length > 0) resolve(results);
32
- else resolve([]);
33
- });
34
- });
35
- }
36
- //---------------------------------------
37
- function getCurrentBatch(connection) {
38
- return new Promise((resolve) => {
39
- connection.query("SELECT `batch` FROM `migrations` ORDER BY `batch` DESC LIMIT 1;", (error, results) => {
40
- if (error) throw error;
41
- if (results?.length > 0) resolve(results[0].batch);
42
- else resolve(0);
43
- });
44
- });
45
- }
46
- //---------------------------------------
47
- function insertMigration(connection, migration, batch) {
48
- return new Promise((resolve) => {
49
- const query = `INSERT INTO \`migrations\` (\`migration\`, \`batch\`) VALUES ('${migration}', '${batch}');`
50
- connection.query(query, (error) => {
51
- if (error) throw error;
52
- resolve(true);
53
- });
54
- });
55
- }
56
- //---------------------------------------
57
- function deleteMigration(connection, migration, batch) {
58
- return new Promise((resolve) => {
59
- const query = `DELETE FROM \`migrations\` WHERE \`migration\` = '${migration}' AND \`batch\` > '${batch}';`
60
- connection.query(query, (error) => {
61
- if (error) throw error;
62
- resolve(true);
63
- });
64
- });
65
- }
66
- //---------------------------------------
67
- function getAllBatches(connection) {
68
- return new Promise((resolve) => {
69
- connection.query("SELECT `batch`, `migration` FROM `migrations`;", (error, results) => {
70
- if (error) throw error;
71
- resolve(results?.length > 0 ? results : []);
72
- });
73
- });
74
- }
75
- //---------------------------------------
76
- module.exports = {
77
- checkTableMigrations, createTableMigrations, getAllMigrations, getCurrentBatch, insertMigration, deleteMigration,
78
- getAllBatches
79
- }
1
+ async function checkTableMigrations(connection) {
2
+ try {
3
+ await connection.promise().query("SELECT `id` FROM `migrations` LIMIT 1;");
4
+ return true;
5
+ } catch (error) {
6
+ if (error && error.code === "ER_NO_SUCH_TABLE") return false;
7
+ throw error;
8
+ }
9
+ }
10
+ //---------------------------------------
11
+ async function createTableMigrations(connection) {
12
+ const query =
13
+ "CREATE TABLE `migrations` (\
14
+ `id` INT NOT NULL AUTO_INCREMENT,\
15
+ `migration` VARCHAR(255) NOT NULL,\
16
+ `batch` INT NOT NULL DEFAULT 1,\
17
+ `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\
18
+ PRIMARY KEY (`id`));";
19
+ await connection.promise().query(query);
20
+ return true;
21
+ }
22
+ //---------------------------------------
23
+ async function getAllMigrations(connection, batch = null) {
24
+ let query = "SELECT `migration` FROM `migrations`";
25
+ const params = [];
26
+ if (batch !== null && batch !== undefined) {
27
+ query += " WHERE `batch` > ?";
28
+ params.push(batch);
29
+ }
30
+ const [results] = await connection.promise().query(`${query};`, params);
31
+ return Array.isArray(results) ? results : [];
32
+ }
33
+ //---------------------------------------
34
+ async function getCurrentBatch(connection) {
35
+ const [results] = await connection
36
+ .promise()
37
+ .query("SELECT `batch` FROM `migrations` ORDER BY `batch` DESC LIMIT 1;");
38
+ return Array.isArray(results) && results.length > 0 ? results[0].batch : 0;
39
+ }
40
+ //---------------------------------------
41
+ async function insertMigration(connection, migration, batch) {
42
+ const query = "INSERT INTO `migrations` (`migration`, `batch`) VALUES (?, ?);";
43
+ await connection.promise().query(query, [migration, batch]);
44
+ return true;
45
+ }
46
+ //---------------------------------------
47
+ async function deleteMigration(connection, migration, batch) {
48
+ const query = "DELETE FROM `migrations` WHERE `migration` = ? AND `batch` > ?;";
49
+ await connection.promise().query(query, [migration, batch]);
50
+ return true;
51
+ }
52
+ //---------------------------------------
53
+ async function getAllBatches(connection) {
54
+ const [results] = await connection.promise().query("SELECT `batch`, `migration` FROM `migrations`;");
55
+ return Array.isArray(results) ? results : [];
56
+ }
57
+ //---------------------------------------
58
+ module.exports = {
59
+ checkTableMigrations,
60
+ createTableMigrations,
61
+ getAllMigrations,
62
+ getCurrentBatch,
63
+ insertMigration,
64
+ deleteMigration,
65
+ getAllBatches,
66
+ };