@adinsure-ops/ops-cli
Version:
Operations CLI for working with AdInsure
349 lines (348 loc) • 15.7 kB
JavaScript
import { __awaiter } from "tslib";
import { Args, Flags } from '@oclif/core';
import axios from 'axios';
import chalk from 'chalk';
import fs from 'fs-extra';
import inquirer from 'inquirer';
import _ from 'lodash';
import path from 'path';
import semver from 'semver';
import CommandBase from '../command.base.js';
import { capitalizeFirstLetter } from '../lib/helper.js';
class Sql extends CommandBase {
constructor() {
super(...arguments);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this._moduleTypes = {
acc: 'Accounting',
claims: 'Claims',
core: 'Core',
pas: 'PAS',
reins: 'Reinsurance',
shared: 'Shared',
};
this._dbmsTypes = [
{
name: 'sql',
scriptLocation: undefined,
extendGenerator: this.sqlExtendScriptGeneration
},
{
name: 'oradc',
scriptLocation: undefined,
extendGenerator: this.oradcExtendScriptGeneration
},
{
name: 'postgres',
scriptLocation: undefined,
extendGenerator: this.postgresExtendScriptGeneration
}
];
}
/**
* Get unique Script ID zip by specified version
* @param {string} version The version of Identity Server
* @returns {Promise<AxiosResponse<any, any>>}
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getScriptId(version) {
return __awaiter(this, void 0, void 0, function* () {
return axios.get(`https://ops.adinsure.com/api/script/next?version=${version}`, {
headers: {
Authorization: 'Bearer ' + (yield this.security.getToken()),
},
});
});
}
/**
* Get unique scriptID by specified version
* @param {string} version Specified version
* @param {string} description Description
* @returns {Promise<string>} Promise to scriptID
*/
getOfflineScriptId(version, description) {
return __awaiter(this, void 0, void 0, function* () {
const prefix = '8.50';
const date = new Date();
const timestamp = date.getUTCFullYear() +
('0' + (date.getUTCMonth() + 1)).slice(-2) +
('0' + (date.getUTCDate())).slice(-2) +
('0' + (date.getUTCHours())).slice(-2) +
('0' + (date.getUTCMinutes())).slice(-2) +
('0' + (date.getUTCSeconds())).slice(-2);
const versionSplit = version.split('.');
let scriptId = prefix +
'_' + ('00' + versionSplit[0]).slice(-3) +
'.' + ('00' + versionSplit[1]).slice(-3) +
'.' + ('00' + versionSplit[2]).slice(-3) +
'_' + timestamp;
if (description) {
scriptId = scriptId + '_' + _.snakeCase(description).slice(0, 100);
}
return scriptId;
});
}
handleLayer(scriptDbmsFolder, scriptLayer, scriptType, dbmsFormat) {
return __awaiter(this, void 0, void 0, function* () {
const scriptFolder = path.resolve(scriptDbmsFolder, scriptLayer, scriptType);
const layerFolder = path.resolve(scriptDbmsFolder, scriptLayer);
if (!(yield fs.pathExists(layerFolder))) {
let layers = '';
// printout only layer folders
for (const layer of fs.readdirSync(scriptDbmsFolder)) {
if (layer.toLowerCase() !== 'schema' && layer.toLowerCase() !== 'data') {
layers = layers + '\n' + layer;
}
}
if (layers.length > 0) {
this.log(`Layer ${scriptLayer} for ${dbmsFormat} does not exist, did you mean: ${layers}`);
}
else {
this.log(`Layer ${scriptLayer} for ${dbmsFormat} does not exist.`);
}
}
return scriptFolder;
});
}
sqlExtendScriptGeneration(tableSchema, tableName, columnName, columnType) {
return __awaiter(this, void 0, void 0, function* () {
return `if exists (select * from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = '${tableSchema}' and TABLE_NAME = '${tableName}')
begin
if not exists (select * from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '${tableSchema}' and TABLE_NAME = '${tableName}' and COLUMN_NAME = '${columnName}')
begin
alter table ${tableSchema}.${tableName} add ${columnName} ${columnType};
end
end`;
});
}
oradcExtendScriptGeneration(tableSchema, tableName, columnName, columnType) {
return __awaiter(this, void 0, void 0, function* () {
return `DECLARE
v_column_exists number := 0;
v_table_exists number := 0;
BEGIN
Select count(*) into v_table_exists
from ALL_TAB_COLS
where upper(OWNER) = '${tableSchema}'
and upper(table_name) = '${tableName}';
if (v_table_exists > 0) then
select count(*) into v_column_exists
from ALL_TAB_COLS
where upper(OWNER) = ${tableSchema}
and upper(table_name) = '${tableName}';
and upper(column_name) = '${columnName}'
if (v_column_exists = 0) then
execute immediate alter table ${tableSchema}.${tableName} add ${columnName} ${columnType};
end if;
end if;
end;`;
});
}
postgresExtendScriptGeneration(tableSchema, tableName, columnName, columnType) {
return __awaiter(this, void 0, void 0, function* () {
return `ALTER TABLE IF EXISTS ${tableSchema}.${tableName}
ADD COLUMN IF NOT EXISTS ${columnName} ${columnType};
`;
});
}
checkExtendParameters() {
return __awaiter(this, void 0, void 0, function* () {
const { flags } = yield this.parse(Sql);
const arrayOfParameters = [];
if (flags['table-schema'] === undefined) {
arrayOfParameters.push('table-schema');
}
if (flags['table-name'] === undefined) {
arrayOfParameters.push('table-name');
}
if (flags['column-name'] === undefined) {
arrayOfParameters.push('column-name');
}
if (flags['column-type'] === undefined) {
arrayOfParameters.push('column-type');
}
return arrayOfParameters;
});
}
// eslint-disable-next-line complexity
run() {
const _super = Object.create(null, {
run: { get: () => super.run }
});
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
_super.run.call(this);
const { args, flags } = yield this.parse(Sql);
const fullVersion = (_a = flags.version) !== null && _a !== void 0 ? _a : yield this.getVersion('SQL_SCRIPTS_VERSION', 'PLATFORM_VERSION', 'VERSION');
let version = semver.parse(fullVersion);
if (!version) {
this.error(`Version in incorrect format. Got version: '${fullVersion}'`);
}
else if (flags.major) {
version = semver.parse(`${version.major}.0.0`);
this.error(`--major flag used. Got version: '${version === null || version === void 0 ? void 0 : version.version}'`);
}
else if (((_b = version === null || version === void 0 ? void 0 : version.prerelease) === null || _b === void 0 ? void 0 : _b.length) && ((_c = version === null || version === void 0 ? void 0 : version.prerelease) === null || _c === void 0 ? void 0 : _c.length) > 0) {
this.warn(`Using prerelease version is not allowed. Got version: '${fullVersion}'.`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const responses = yield inquirer.prompt([{
name: 'version',
message: 'write version you want to use or write "yes" to revert to latest latest patch.',
type: 'input',
}]);
if (responses.version === 'yes' || responses.version === '') {
version = semver.parse(`${version.major}.0.0`);
if (!version) {
this.error(`Version in incorrect format. Got version: '${responses.version}'`);
}
}
else {
version = semver.parse(responses.version);
if (!version) {
this.error(`Version in incorrect format. Got version: '${responses.version}'`);
}
}
this.warn(`${version === null || version === void 0 ? void 0 : version.version} version will be used.`);
}
// Validation of input parameters
let scriptType = args.type;
if (!scriptType) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const responses = yield inquirer.prompt([{
name: 'type',
message: 'select a sql type',
type: 'list',
choices: [{ name: 'Schema' }, { name: 'Data' }, { name: 'Migration' }, { name: 'Extend' }],
}]);
scriptType = responses.type;
}
scriptType = scriptType === 'Migration' ? scriptType.toLowerCase() : capitalizeFirstLetter(scriptType);
let scriptModule = args.module;
if (!scriptModule && scriptType === 'data') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const responses = yield inquirer.prompt([{
name: 'module',
message: 'select a sql module for data type',
type: 'list',
choices: [{ name: 'acc' }, { name: 'claims' }, { name: 'core' }, { name: 'pas' }, { name: 'reins' }, { name: 'shared' }],
}]);
scriptModule = responses.module;
}
// If scriptType is Extend, then check input parameters for extending the db columns
if (scriptType === 'Extend') {
const arrayOfMissingParameters = yield this.checkExtendParameters();
if (arrayOfMissingParameters.length > 0) {
this.error(`The script type Extend requires the following parameters to be specified: ${arrayOfMissingParameters.join(', ')}`);
}
}
const scriptLayer = flags.layer;
this.log(`Generating on SQL script layer:'${scriptLayer}'`);
const databaseFolder = flags.dwh ? 'database-dwh' : 'database';
const scriptsRootFolder = path.resolve(yield this.getGitRoot(), databaseFolder);
if (!(yield fs.pathExists(scriptsRootFolder))) {
this.error(`Could not resolve database scripts folder: ${scriptsRootFolder}`);
}
for (const dbmsFormat of this._dbmsTypes) {
const scriptDbmsFolder = path.resolve(scriptsRootFolder, dbmsFormat.name);
if (yield fs.pathExists(scriptDbmsFolder)) {
let scriptFolder = path.resolve(scriptDbmsFolder, scriptType);
if (scriptLayer !== undefined) {
scriptFolder = yield this.handleLayer(scriptDbmsFolder, scriptLayer, scriptType, dbmsFormat.name);
}
if (scriptModule !== undefined) {
scriptFolder = path.resolve(scriptFolder, this._moduleTypes[scriptModule]);
}
if (!(yield fs.pathExists(scriptFolder))) {
this.warn(`Could not resolve existing database scripts folder. Creating folder: ${scriptFolder}`);
yield fs.mkdir(scriptFolder);
}
dbmsFormat.scriptLocation = scriptFolder;
}
}
// Validation of parameters succeed. Requesting new SQL script ID and creating file.
this.log(`Requesting new id for '${version}'`);
let scriptId = '';
if (flags.offline) {
scriptId = yield this.getOfflineScriptId(version.version, flags.description);
this.log(`Generation script: '${chalk.green(scriptId + '.sql')}'`);
}
else {
scriptId = (yield this.getScriptId(version.version)).data;
this.log(`Got: '${chalk.green(scriptId)}'`);
}
const usedDbmsTypes = this._dbmsTypes.filter(it => it.scriptLocation !== undefined);
for (const usedDbmsType of usedDbmsTypes) {
const scriptsFilePath = path.resolve(usedDbmsType.scriptLocation, `${scriptId}.sql`);
const content = scriptType === 'Extend' ? yield usedDbmsType.extendGenerator(flags['table-schema'], flags['table-name'], flags['column-name'], flags['column-type']) : '';
yield fs.writeFile(scriptsFilePath, content);
this.log(`${chalk.yellow(scriptsFilePath)}`);
}
});
}
}
Sql.description = 'creates a new database script';
Sql.usage = 'sql <type> <module> [flags]';
Sql.examples = [
`$ ops sql schema`,
`$ ops sql schema --dwh`,
`$ ops sql data acc`,
`$ ops sql data acc --dwh`,
`$ ops sql data shared --layer basic`,
`$ ops sql data shared --dwh --layer basic`,
`$ ops sql data shared --major`,
`$ ops sql data shared --offline --description "this is script description"`,
];
Sql.args = {
type: Args.string({
description: 'Type of database scripts',
required: true,
options: ['schema', 'data', 'migration', 'extend', 'Schema', 'Data', 'Migration', 'Extend'],
}),
module: Args.string({
description: 'Module of data database scripts',
options: ['acc', 'claims', 'core', 'pas', 'reins', 'shared'],
}),
};
Sql.flags = {
version: Flags.string({
char: 'v',
description: 'version for which you\'re generating database script',
}),
layer: Flags.string({
char: 'l',
description: 'name of the configuration layer for which you are generating database script',
}),
offline: Flags.boolean({
char: 'o',
description: 'generate database script with timestamp',
default: false,
}),
description: Flags.string({
char: 'd',
description: 'description of script to be used in filename for offline',
dependsOn: ['offline'],
}),
major: Flags.boolean({
char: 'm',
description: 'generate script for major version',
default: false,
}),
// Used only for generating scripts to extend existing db tables with new column
'table-schema': Flags.string({
description: 'name of the existing table schema',
}),
'table-name': Flags.string({
description: 'name of the existing table',
}),
'column-name': Flags.string({
description: 'name the new column to be added',
}),
'column-type': Flags.string({
description: 'type of the new column to be added',
}),
'dwh': Flags.boolean({
description: 'create database scripts for DWH',
default: false
}),
};
export default Sql;