major refactoring
This commit is contained in:
parent
620d00ba02
commit
4b9e445f0d
4
.gitignore
vendored
Executable file
4
.gitignore
vendored
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
.idea
|
||||||
|
node_modules
|
||||||
|
logs_directory
|
||||||
|
temporary_directory
|
|
@ -44,11 +44,11 @@ from MySQL to PostgreSQL as easy and smooth as possible.</p>
|
||||||
<b>Sample:</b><br />
|
<b>Sample:</b><br />
|
||||||
<pre>$ cd /path/to/nmig</pre><br />
|
<pre>$ cd /path/to/nmig</pre><br />
|
||||||
<pre>$ npm install</pre><br />
|
<pre>$ npm install</pre><br />
|
||||||
<pre>$ node nmig.js</pre><br />
|
<pre>$ npm start</pre><br />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p><b>5.</b> If a disaster took place during migration (for what ever reason) - simply restart the process
|
<p><b>5.</b> If a disaster took place during migration (for what ever reason) - simply restart the process
|
||||||
<code>$ node nmig.js</code><br> NMIG will restart from the point it was stopped at.
|
<code>$ npm start</code><br> NMIG will restart from the point it was stopped at.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p><b>6.</b> At the end of migration check log files, if necessary.<br />
|
<p><b>6.</b> At the end of migration check log files, if necessary.<br />
|
||||||
|
@ -61,7 +61,7 @@ from MySQL to PostgreSQL as easy and smooth as possible.</p>
|
||||||
<a href="mailto:anatolyuss@gmail.com?subject=NMIG">anatolyuss@gmail.com</a></p>
|
<a href="mailto:anatolyuss@gmail.com?subject=NMIG">anatolyuss@gmail.com</a></p>
|
||||||
|
|
||||||
<h3>VERSION</h3>
|
<h3>VERSION</h3>
|
||||||
<p>Current version is 2.6.1<br />
|
<p>Current version is 3.0.0<br />
|
||||||
(major version . improvements . bug fixes)</p>
|
(major version . improvements . bug fixes)</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,115 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is a part of "NMIG" - the database migration tool.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2016 - present, Anatoly Khaytovich <anatolyuss@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program (please see the "LICENSE.md" file).
|
|
||||||
* If not, see <http://www.gnu.org/licenses/gpl.txt>.
|
|
||||||
*
|
|
||||||
* @author Anatoly Khaytovich <anatolyuss@gmail.com>
|
|
||||||
*/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const readDataTypesMap = require('./DataTypesMapReader');
|
|
||||||
const log = require('./Logger');
|
|
||||||
const generateError = require('./ErrorGenerator');
|
|
||||||
const Conversion = require('./Conversion');
|
|
||||||
const migrationStateManager = require('./MigrationStateManager');
|
|
||||||
const createSchema = require('./SchemaProcessor');
|
|
||||||
const cleanup = require('./CleanupProcessor');
|
|
||||||
const dataPoolManager = require('./DataPoolManager');
|
|
||||||
const directoriesManager = require('./DirectoriesManager');
|
|
||||||
const loadStructureToMigrate = require('./StructureLoader');
|
|
||||||
const pipeData = require('./DataPipeManager');
|
|
||||||
const boot = require('./BootProcessor');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs migration according to user's configuration.
|
|
||||||
*
|
|
||||||
* @param {Object} config
|
|
||||||
*
|
|
||||||
* @returns {undefined}
|
|
||||||
*/
|
|
||||||
module.exports = config => {
|
|
||||||
const self = new Conversion(config);
|
|
||||||
|
|
||||||
boot(self).then(() => {
|
|
||||||
return readDataTypesMap(self);
|
|
||||||
}).then(
|
|
||||||
() => {
|
|
||||||
return directoriesManager.createLogsDirectory(self);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
// Braces are essential. Without them promises-chain will continue execution.
|
|
||||||
console.log('\t--[Main] Failed to boot migration');
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
return directoriesManager.createTemporaryDirectory(self);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
// Braces are essential. Without them promises-chain will continue execution.
|
|
||||||
log(self, '\t--[Main] Logs directory was not created...');
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
return createSchema(self);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
const msg = '\t--[Main] The temporary directory [' + self._tempDirPath + '] already exists...'
|
|
||||||
+ '\n\t Please, remove this directory and rerun NMIG...';
|
|
||||||
|
|
||||||
log(self, msg);
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
return migrationStateManager.createStateLogsTable(self);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
generateError(self, '\t--[Main] Cannot create new DB schema...');
|
|
||||||
return cleanup(self);
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
return dataPoolManager.createDataPoolTable(self);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
generateError(self, '\t--[Main] Cannot create execution_logs table...');
|
|
||||||
return cleanup(self);
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
return loadStructureToMigrate(self);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
generateError(self, '\t--[Main] Cannot create data-pool...');
|
|
||||||
return cleanup(self);
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
return dataPoolManager.readDataPool(self);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
generateError(self, '\t--[Main] NMIG cannot load source database structure...');
|
|
||||||
return cleanup(self);
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
pipeData(self);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
generateError(self, '\t--[Main] NMIG failed to load Data-Units pool...');
|
|
||||||
return cleanup(self);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
89
nmig.js
89
nmig.js
|
@ -1,89 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is a part of "NMIG" - the database migration tool.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2016 - present, Anatoly Khaytovich <anatolyuss@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program (please see the "LICENSE.md" file).
|
|
||||||
* If not, see <http://www.gnu.org/licenses/gpl.txt>.
|
|
||||||
*
|
|
||||||
* @author Anatoly Khaytovich <anatolyuss@gmail.com>
|
|
||||||
*/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const main = require('./migration/fmtp/Main');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the configuration file.
|
|
||||||
*
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
const readConfig = () => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const strPathToConfig = path.join(__dirname, 'config.json');
|
|
||||||
|
|
||||||
fs.readFile(strPathToConfig, (error, data) => {
|
|
||||||
if (error) {
|
|
||||||
reject('\n\t--Cannot run migration\nCannot read configuration info from ' + strPathToConfig);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
const config = JSON.parse(data.toString());
|
|
||||||
config.tempDirPath = path.join(__dirname, 'temporary_directory');
|
|
||||||
config.logsDirPath = path.join(__dirname, 'logs_directory');
|
|
||||||
config.dataTypesMapAddr = path.join(__dirname, 'DataTypesMap.json');
|
|
||||||
resolve(config);
|
|
||||||
} catch (err) {
|
|
||||||
reject('\n\t--Cannot parse JSON from ' + strPathToConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the extra configuration file, if necessary.
|
|
||||||
*
|
|
||||||
* @param {Object} config
|
|
||||||
*
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
const readExtraConfig = config => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (config.enable_extra_config !== true) {
|
|
||||||
config.extraConfig = null;
|
|
||||||
return resolve(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
const strPathToExtraConfig = path.join(__dirname, 'extra_config.json');
|
|
||||||
|
|
||||||
fs.readFile(strPathToExtraConfig, (error, data) => {
|
|
||||||
if (error) {
|
|
||||||
reject('\n\t--Cannot run migration\nCannot read configuration info from ' + strPathToExtraConfig);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
config.extraConfig = JSON.parse(data.toString());
|
|
||||||
resolve(config);
|
|
||||||
} catch (err) {
|
|
||||||
reject('\n\t--Cannot parse JSON from ' + strPathToExtraConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
readConfig()
|
|
||||||
.then(readExtraConfig)
|
|
||||||
.then(config => main(config))
|
|
||||||
.catch(error => console.log(error));
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "nmig",
|
"name": "nmig",
|
||||||
"version": "2.6.1",
|
"version": "3.0.0",
|
||||||
"description": "The database migration app",
|
"description": "The database migration app",
|
||||||
"author": "Anatoly Khaytovich<anatolyuss@gmail.com>",
|
"author": "Anatoly Khaytovich<anatolyuss@gmail.com>",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
|
@ -12,5 +12,8 @@
|
||||||
"mysql": "*",
|
"mysql": "*",
|
||||||
"pg": "*",
|
"pg": "*",
|
||||||
"pg-copy-streams": "*"
|
"pg-copy-streams": "*"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "node ./src/Main.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ module.exports = self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stdin.indexOf('Y') !== -1) {
|
if (stdin.indexOf('Y') !== -1) {
|
||||||
resolve();
|
resolve(self);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -33,11 +33,11 @@ const generateError = require('./ErrorGenerator');
|
||||||
*/
|
*/
|
||||||
module.exports.createDataPoolTable = self => {
|
module.exports.createDataPoolTable = self => {
|
||||||
return connect(self).then(() => {
|
return connect(self).then(() => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(resolve => {
|
||||||
self._pg.connect((error, client, done) => {
|
self._pg.connect((error, client, done) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
generateError(self, '\t--[DataPoolManager.createDataPoolTable] Cannot connect to PostgreSQL server...\n' + error);
|
generateError(self, '\t--[DataPoolManager.createDataPoolTable] Cannot connect to PostgreSQL server...\n' + error);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
const sql = 'CREATE TABLE IF NOT EXISTS "' + self._schema + '"."data_pool_' + self._schema + self._mySqlDbName
|
const sql = 'CREATE TABLE IF NOT EXISTS "' + self._schema + '"."data_pool_' + self._schema + self._mySqlDbName
|
||||||
+ '"("id" BIGSERIAL, "json" TEXT, "is_started" BOOLEAN);';
|
+ '"("id" BIGSERIAL, "json" TEXT, "is_started" BOOLEAN);';
|
||||||
|
@ -47,10 +47,10 @@ module.exports.createDataPoolTable = self => {
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
generateError(self, '\t--[DataPoolManager.createDataPoolTable] ' + err, sql);
|
generateError(self, '\t--[DataPoolManager.createDataPoolTable] ' + err, sql);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
log(self, '\t--[DataPoolManager.createDataPoolTable] table "' + self._schema + '"."data_pool_' + self._schema + self._mySqlDbName + '" is created...');
|
log(self, '\t--[DataPoolManager.createDataPoolTable] table "' + self._schema + '"."data_pool_' + self._schema + self._mySqlDbName + '" is created...');
|
||||||
resolve();
|
resolve(self);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -102,11 +102,11 @@ module.exports.dropDataPoolTable = self => {
|
||||||
*/
|
*/
|
||||||
module.exports.readDataPool = self => {
|
module.exports.readDataPool = self => {
|
||||||
return connect(self).then(() => {
|
return connect(self).then(() => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(resolve => {
|
||||||
self._pg.connect((error, client, done) => {
|
self._pg.connect((error, client, done) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
generateError(self, '\t--[DataPoolManager.readDataPool] Cannot connect to PostgreSQL server...\n' + error);
|
generateError(self, '\t--[DataPoolManager.readDataPool] Cannot connect to PostgreSQL server...\n' + error);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
const sql = 'SELECT id AS id, json AS json FROM "' + self._schema + '"."data_pool_' + self._schema + self._mySqlDbName + '";';
|
const sql = 'SELECT id AS id, json AS json FROM "' + self._schema + '"."data_pool_' + self._schema + self._mySqlDbName + '";';
|
||||||
client.query(sql, (err, arrDataPool) => {
|
client.query(sql, (err, arrDataPool) => {
|
||||||
|
@ -114,7 +114,7 @@ module.exports.readDataPool = self => {
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
generateError(self, '\t--[DataPoolManager.readDataPool] ' + err, sql);
|
generateError(self, '\t--[DataPoolManager.readDataPool] ' + err, sql);
|
||||||
return reject();
|
process.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < arrDataPool.rows.length; ++i) {
|
for (let i = 0; i < arrDataPool.rows.length; ++i) {
|
||||||
|
@ -124,7 +124,7 @@ module.exports.readDataPool = self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
log(self, '\t--[DataPoolManager.readDataPool] Data-Pool is loaded...');
|
log(self, '\t--[DataPoolManager.readDataPool] Data-Pool is loaded...');
|
||||||
resolve();
|
resolve(self);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -31,21 +31,16 @@ const fs = require('fs');
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
module.exports = self => {
|
module.exports = self => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(resolve => {
|
||||||
fs.readFile(self._dataTypesMapAddr, (error, data) => {
|
fs.readFile(self._dataTypesMapAddr, (error, data) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.log('\t--[readDataTypesMap] Cannot read "DataTypesMap" from ' + self._dataTypesMapAddr);
|
console.log('\t--[readDataTypesMap] Cannot read "DataTypesMap" from ' + self._dataTypesMapAddr);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
self._dataTypesMap = JSON.parse(data.toString());
|
|
||||||
console.log('\t--[readDataTypesMap] Data Types Map is loaded...');
|
|
||||||
resolve();
|
|
||||||
} catch (err) {
|
|
||||||
console.log('\t--[readDataTypesMap] Cannot parse JSON from' + self._dataTypesMapAddr);
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self._dataTypesMap = JSON.parse(data);
|
||||||
|
console.log('\t--[readDataTypesMap] Data Types Map is loaded...');
|
||||||
|
resolve(self);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
|
@ -32,7 +32,7 @@ const log = require('./Logger');
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
module.exports.createTemporaryDirectory = self => {
|
module.exports.createTemporaryDirectory = self => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(resolve => {
|
||||||
log(self, '\t--[DirectoriesManager.createTemporaryDirectory] Creating temporary directory...');
|
log(self, '\t--[DirectoriesManager.createTemporaryDirectory] Creating temporary directory...');
|
||||||
fs.stat(self._tempDirPath, (directoryDoesNotExist, stat) => {
|
fs.stat(self._tempDirPath, (directoryDoesNotExist, stat) => {
|
||||||
if (directoryDoesNotExist) {
|
if (directoryDoesNotExist) {
|
||||||
|
@ -42,17 +42,17 @@ module.exports.createTemporaryDirectory = self => {
|
||||||
+ '"temporary_directory": ' + self._tempDirPath;
|
+ '"temporary_directory": ' + self._tempDirPath;
|
||||||
|
|
||||||
log(self, msg);
|
log(self, msg);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
log(self, '\t--[DirectoriesManager.createTemporaryDirectory] Temporary directory is created...');
|
log(self, '\t--[DirectoriesManager.createTemporaryDirectory] Temporary directory is created...');
|
||||||
resolve();
|
resolve(self);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (!stat.isDirectory()) {
|
} else if (!stat.isDirectory()) {
|
||||||
log(self, '\t--[DirectoriesManager.createTemporaryDirectory] Cannot perform a migration due to unexpected error');
|
log(self, '\t--[DirectoriesManager.createTemporaryDirectory] Cannot perform a migration due to unexpected error');
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
resolve();
|
resolve(self);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -113,7 +113,7 @@ module.exports.removeTemporaryDirectory = self => {
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
module.exports.createLogsDirectory = self => {
|
module.exports.createLogsDirectory = self => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(resolve => {
|
||||||
console.log('\t--[DirectoriesManager.createLogsDirectory] Creating logs directory...');
|
console.log('\t--[DirectoriesManager.createLogsDirectory] Creating logs directory...');
|
||||||
fs.stat(self._logsDirPath, (directoryDoesNotExist, stat) => {
|
fs.stat(self._logsDirPath, (directoryDoesNotExist, stat) => {
|
||||||
if (directoryDoesNotExist) {
|
if (directoryDoesNotExist) {
|
||||||
|
@ -123,18 +123,18 @@ module.exports.createLogsDirectory = self => {
|
||||||
+ '"logs_directory": ' + self._logsDirPath;
|
+ '"logs_directory": ' + self._logsDirPath;
|
||||||
|
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
log(self, '\t--[DirectoriesManager.createLogsDirectory] Logs directory is created...');
|
log(self, '\t--[DirectoriesManager.createLogsDirectory] Logs directory is created...');
|
||||||
resolve();
|
resolve(self);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (!stat.isDirectory()) {
|
} else if (!stat.isDirectory()) {
|
||||||
console.log('\t--[DirectoriesManager.createLogsDirectory] Cannot perform a migration due to unexpected error');
|
console.log('\t--[DirectoriesManager.createLogsDirectory] Cannot perform a migration due to unexpected error');
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
log(self, '\t--[DirectoriesManager.createLogsDirectory] Logs directory already exists...');
|
log(self, '\t--[DirectoriesManager.createLogsDirectory] Logs directory already exists...');
|
||||||
resolve();
|
resolve(self);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
114
src/Main.js
Normal file
114
src/Main.js
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* This file is a part of "NMIG" - the database migration tool.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 - present, Anatoly Khaytovich <anatolyuss@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program (please see the "LICENSE.md" file).
|
||||||
|
* If not, see <http://www.gnu.org/licenses/gpl.txt>.
|
||||||
|
*
|
||||||
|
* @author Anatoly Khaytovich <anatolyuss@gmail.com>
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const readDataTypesMap = require('./DataTypesMapReader');
|
||||||
|
const Conversion = require('./Conversion');
|
||||||
|
const createSchema = require('./SchemaProcessor');
|
||||||
|
const loadStructureToMigrate = require('./StructureLoader');
|
||||||
|
const pipeData = require('./DataPipeManager');
|
||||||
|
const boot = require('./BootProcessor');
|
||||||
|
const { createStateLogsTable } = require('./MigrationStateManager');
|
||||||
|
const { createDataPoolTable, readDataPool } = require('./DataPoolManager');
|
||||||
|
const { createLogsDirectory, createTemporaryDirectory } = require('./DirectoriesManager');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the configuration file.
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
const readConfig = () => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const strPathToConfig = path.join(__dirname, '..', 'config.json');
|
||||||
|
|
||||||
|
fs.readFile(strPathToConfig, (error, data) => {
|
||||||
|
if (error) {
|
||||||
|
console.log('\n\t--Cannot run migration\nCannot read configuration info from ' + strPathToConfig);
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = JSON.parse(data);
|
||||||
|
config.tempDirPath = path.join(__dirname, '..', 'temporary_directory');
|
||||||
|
config.logsDirPath = path.join(__dirname, '..', 'logs_directory');
|
||||||
|
config.dataTypesMapAddr = path.join(__dirname, '..', 'DataTypesMap.json');
|
||||||
|
resolve(config);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the extra configuration file, if necessary.
|
||||||
|
*
|
||||||
|
* @param {Object} config
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
const readExtraConfig = config => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if (config.enable_extra_config !== true) {
|
||||||
|
config.extraConfig = null;
|
||||||
|
return resolve(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
const strPathToExtraConfig = path.join(__dirname, '..', 'extra_config.json');
|
||||||
|
|
||||||
|
fs.readFile(strPathToExtraConfig, (error, data) => {
|
||||||
|
if (error) {
|
||||||
|
console.log('\n\t--Cannot run migration\nCannot read configuration info from ' + strPathToExtraConfig);
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
config.extraConfig = JSON.parse(data);
|
||||||
|
resolve(config);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Conversion instance.
|
||||||
|
*
|
||||||
|
* @param {Object} config
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
const initializeConversion = config => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
resolve(new Conversion(config));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
readConfig()
|
||||||
|
.then(readExtraConfig)
|
||||||
|
.then(initializeConversion)
|
||||||
|
.then(boot)
|
||||||
|
.then(readDataTypesMap)
|
||||||
|
.then(createLogsDirectory)
|
||||||
|
.then(createTemporaryDirectory)
|
||||||
|
.then(createSchema)
|
||||||
|
.then(createStateLogsTable)
|
||||||
|
.then(createDataPoolTable)
|
||||||
|
.then(loadStructureToMigrate)
|
||||||
|
.then(readDataPool)
|
||||||
|
.then(pipeData)
|
||||||
|
.catch(error => console.log(error));
|
|
@ -101,11 +101,11 @@ module.exports.set = (self, param) => {
|
||||||
*/
|
*/
|
||||||
module.exports.createStateLogsTable = self => {
|
module.exports.createStateLogsTable = self => {
|
||||||
return connect(self).then(() => {
|
return connect(self).then(() => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(resolve => {
|
||||||
self._pg.connect((error, client, done) => {
|
self._pg.connect((error, client, done) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
generateError(self, '\t--[createStateLogsTable] Cannot connect to PostgreSQL server...\n' + error);
|
generateError(self, '\t--[createStateLogsTable] Cannot connect to PostgreSQL server...\n' + error);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
let sql = 'CREATE TABLE IF NOT EXISTS "' + self._schema + '"."state_logs_' + self._schema + self._mySqlDbName
|
let sql = 'CREATE TABLE IF NOT EXISTS "' + self._schema + '"."state_logs_' + self._schema + self._mySqlDbName
|
||||||
+ '"('
|
+ '"('
|
||||||
|
@ -119,14 +119,14 @@ module.exports.createStateLogsTable = self => {
|
||||||
if (err) {
|
if (err) {
|
||||||
done();
|
done();
|
||||||
generateError(self, '\t--[createStateLogsTable] ' + err, sql);
|
generateError(self, '\t--[createStateLogsTable] ' + err, sql);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
sql = 'SELECT COUNT(1) AS cnt FROM "' + self._schema + '"."state_logs_' + self._schema + self._mySqlDbName + '";';
|
sql = 'SELECT COUNT(1) AS cnt FROM "' + self._schema + '"."state_logs_' + self._schema + self._mySqlDbName + '";';
|
||||||
client.query(sql, (errorCount, result) => {
|
client.query(sql, (errorCount, result) => {
|
||||||
if (errorCount) {
|
if (errorCount) {
|
||||||
done();
|
done();
|
||||||
generateError(self, '\t--[createStateLogsTable] ' + errorCount, sql);
|
generateError(self, '\t--[createStateLogsTable] ' + errorCount, sql);
|
||||||
reject();
|
process.exit();
|
||||||
} else if (+result.rows[0].cnt === 0) {
|
} else if (+result.rows[0].cnt === 0) {
|
||||||
sql = 'INSERT INTO "' + self._schema + '"."state_logs_' + self._schema + self._mySqlDbName
|
sql = 'INSERT INTO "' + self._schema + '"."state_logs_' + self._schema + self._mySqlDbName
|
||||||
+ '" VALUES(FALSE, FALSE, FALSE, FALSE);';
|
+ '" VALUES(FALSE, FALSE, FALSE, FALSE);';
|
||||||
|
@ -136,13 +136,13 @@ module.exports.createStateLogsTable = self => {
|
||||||
|
|
||||||
if (errorInsert) {
|
if (errorInsert) {
|
||||||
generateError(self, '\t--[createStateLogsTable] ' + errorInsert, sql);
|
generateError(self, '\t--[createStateLogsTable] ' + errorInsert, sql);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
const msg = '\t--[createStateLogsTable] table "' + self._schema + '"."state_logs_'
|
const msg = '\t--[createStateLogsTable] table "' + self._schema + '"."state_logs_'
|
||||||
+ self._schema + self._mySqlDbName + '" is created...';
|
+ self._schema + self._mySqlDbName + '" is created...';
|
||||||
|
|
||||||
log(self, msg);
|
log(self, msg);
|
||||||
resolve();
|
resolve(self);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -150,7 +150,7 @@ module.exports.createStateLogsTable = self => {
|
||||||
+ self._schema + self._mySqlDbName + '" is created...';
|
+ self._schema + self._mySqlDbName + '" is created...';
|
||||||
|
|
||||||
log(self, msg2);
|
log(self, msg2);
|
||||||
resolve();
|
resolve(self);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -33,18 +33,18 @@ const generateError = require('./ErrorGenerator');
|
||||||
*/
|
*/
|
||||||
module.exports = self => {
|
module.exports = self => {
|
||||||
return connect(self).then(() => {
|
return connect(self).then(() => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(resolve => {
|
||||||
self._pg.connect((error, client, done) => {
|
self._pg.connect((error, client, done) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
generateError(self, '\t--[createSchema] Cannot connect to PostgreSQL server...\n' + error);
|
generateError(self, '\t--[createSchema] Cannot connect to PostgreSQL server...\n' + error);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
let sql = "SELECT schema_name FROM information_schema.schemata WHERE schema_name = '" + self._schema + "';";
|
let sql = "SELECT schema_name FROM information_schema.schemata WHERE schema_name = '" + self._schema + "';";
|
||||||
client.query(sql, (err, result) => {
|
client.query(sql, (err, result) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
done();
|
done();
|
||||||
generateError(self, '\t--[createSchema] ' + err, sql);
|
generateError(self, '\t--[createSchema] ' + err, sql);
|
||||||
reject();
|
process.exit();
|
||||||
} else if (result.rows.length === 0) {
|
} else if (result.rows.length === 0) {
|
||||||
sql = 'CREATE SCHEMA "' + self._schema + '";';
|
sql = 'CREATE SCHEMA "' + self._schema + '";';
|
||||||
client.query(sql, err => {
|
client.query(sql, err => {
|
||||||
|
@ -52,13 +52,13 @@ module.exports = self => {
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
generateError(self, '\t--[createSchema] ' + err, sql);
|
generateError(self, '\t--[createSchema] ' + err, sql);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
resolve();
|
resolve(self);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
resolve();
|
resolve(self);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -96,12 +96,12 @@ const getMySqlVersion = self => {
|
||||||
module.exports = self => {
|
module.exports = self => {
|
||||||
return getMySqlVersion(self).then(() => {
|
return getMySqlVersion(self).then(() => {
|
||||||
return migrationStateManager.get(self, 'tables_loaded').then(haveTablesLoaded => {
|
return migrationStateManager.get(self, 'tables_loaded').then(haveTablesLoaded => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(resolve => {
|
||||||
self._mysql.getConnection((error, connection) => {
|
self._mysql.getConnection((error, connection) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
// The connection is undefined.
|
// The connection is undefined.
|
||||||
generateError(self, '\t--[loadStructureToMigrate] Cannot connect to MySQL server...\n' + error);
|
generateError(self, '\t--[loadStructureToMigrate] Cannot connect to MySQL server...\n' + error);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
const sql = 'SHOW FULL TABLES IN `' + self._mySqlDbName + '`;';
|
const sql = 'SHOW FULL TABLES IN `' + self._mySqlDbName + '`;';
|
||||||
connection.query(sql, (strErr, rows) => {
|
connection.query(sql, (strErr, rows) => {
|
||||||
|
@ -109,7 +109,7 @@ module.exports = self => {
|
||||||
|
|
||||||
if (strErr) {
|
if (strErr) {
|
||||||
generateError(self, '\t--[loadStructureToMigrate] ' + strErr, sql);
|
generateError(self, '\t--[loadStructureToMigrate] ' + strErr, sql);
|
||||||
reject();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
let tablesCnt = 0;
|
let tablesCnt = 0;
|
||||||
let viewsCnt = 0;
|
let viewsCnt = 0;
|
||||||
|
@ -141,9 +141,9 @@ module.exports = self => {
|
||||||
|
|
||||||
Promise.all(processTablePromises).then(
|
Promise.all(processTablePromises).then(
|
||||||
() => {
|
() => {
|
||||||
migrationStateManager.set(self, 'tables_loaded').then(() => resolve());
|
migrationStateManager.set(self, 'tables_loaded').then(() => resolve(self));
|
||||||
},
|
},
|
||||||
() => reject()
|
() => process.exit()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
Loading…
Reference in a new issue