@nestjs-mod/flyway
Version:
Flyway - utility for working with database migrations (official site: https://flywaydb.org, preview version only for Postgres)
234 lines (231 loc) • 12.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FlywayInfrastructureUpdaterService = void 0;
const tslib_1 = require("tslib");
const common_1 = require("@nestjs-mod/common");
const common_2 = require("@nestjs/common");
const case_anything_1 = require("case-anything");
const connection_string_1 = require("connection-string");
const fs_1 = require("fs");
const path_1 = require("path");
const flyway_errors_1 = require("../flyway-errors");
const flyway_configuration_1 = require("../flyway.configuration");
const flyway_config_file_service_1 = require("./flyway-config-file.service");
const flyway_infrastructure_constants_1 = require("./flyway-infrastructure.constants");
let FlywayInfrastructureUpdaterService = class FlywayInfrastructureUpdaterService {
constructor(packageJsonService, nxProjectJsonService, flywayConfiguration, flywayConfigFileService, wrapApplicationOptionsService) {
this.packageJsonService = packageJsonService;
this.nxProjectJsonService = nxProjectJsonService;
this.flywayConfiguration = flywayConfiguration;
this.flywayConfigFileService = flywayConfigFileService;
this.wrapApplicationOptionsService = wrapApplicationOptionsService;
}
onModuleInit() {
this.update();
}
update() {
this.updatePackageJsonFile();
this.updateProjectJsonFile();
this.updateFlywayConfigFile();
this.createFirstMigrations();
}
updatePackageJsonFile() {
const projectJson = this.nxProjectJsonService.read(this.flywayConfiguration.nxProjectJsonFile);
if (projectJson) {
const projectName = projectJson.name;
const packageJson = this.packageJsonService.read();
if (packageJson) {
this.packageJsonService.addScripts(flyway_infrastructure_constants_1.FLYWAY_SCRIPTS_CATEGORY_NAME, {
[`flyway:create:${projectName}`]: {
commands: [`./node_modules/.bin/nx run ${projectName}:flyway-create-migration`],
comments: [`Command to create new empty migration for ${projectName}, for set name pass name to --args, example: npm run flyway:create:appname --args=Init`],
},
[`flyway:migrate:${projectName}`]: {
commands: [`./node_modules/.bin/nx run ${projectName}:flyway-migrate`],
comments: [`Applying migrations for ${projectName}`],
},
'flyway:migrate': {
commands: ['./node_modules/.bin/nx run-many -t=flyway-migrate'],
comments: ['Applying migrations of all applications and modules'],
},
}, packageJson);
this.packageJsonService.write(packageJson);
}
}
}
updateProjectJsonFile() {
if (!this.flywayConfiguration.configFile) {
throw new flyway_errors_1.FlywayError('flywayConfigFile not set');
}
const projectJson = this.nxProjectJsonService.read(this.flywayConfiguration.nxProjectJsonFile);
const packageJsonFilePath = this.packageJsonService.getPackageJsonFilePath();
const nxProjectJsonFilePath = this.flywayConfiguration.nxProjectJsonFile || this.nxProjectJsonService.getNxProjectJsonFilePath();
if (projectJson && packageJsonFilePath && nxProjectJsonFilePath) {
const flywayConfigFilePath = this.flywayConfiguration.configFile.replace((0, path_1.dirname)(packageJsonFilePath), '');
const flywayMigrationsPath = this.flywayConfiguration.migrationsFolder.replace((0, path_1.dirname)(packageJsonFilePath), '');
const { databaseName } = this.getDbConnectionEnvKeys();
// new migration
this.nxProjectJsonService.addRunCommands([`echo 'select 1;' > .${flywayMigrationsPath}/V\`date +%Y%m%d%H%M\`__\${npm_config_args:-NewMigration}.sql`], 'flyway-create-migration', undefined, this.flywayConfiguration.nxProjectJsonFile);
// migrate
this.nxProjectJsonService.addRunCommands([
`export DATABASE_URL=\${${databaseName}} && export DATABASE_MIGRATIONS_TABLE=${projectJson.name} && export DATABASE_MIGRATIONS_LOCATIONS=.${flywayMigrationsPath} && ./node_modules/.bin/flyway -c .${flywayConfigFilePath} migrate`,
], 'flyway-migrate', undefined, this.flywayConfiguration.nxProjectJsonFile);
// info
this.nxProjectJsonService.addRunCommands([
`export DATABASE_URL=\${${databaseName}} && export DATABASE_MIGRATIONS_TABLE=${projectJson.name} && export DATABASE_MIGRATIONS_LOCATIONS=.${flywayMigrationsPath} && ./node_modules/.bin/flyway -c .${flywayConfigFilePath} info`,
], 'flyway-info', undefined, this.flywayConfiguration.nxProjectJsonFile);
// baseline
this.nxProjectJsonService.addRunCommands([
`export DATABASE_URL=\${${databaseName}} && export DATABASE_MIGRATIONS_TABLE=${projectJson.name} && export DATABASE_MIGRATIONS_LOCATIONS=.${flywayMigrationsPath} && ./node_modules/.bin/flyway -c .${flywayConfigFilePath} baseline`,
], 'flyway-baseline', undefined, this.flywayConfiguration.nxProjectJsonFile);
// validate
this.nxProjectJsonService.addRunCommands([
`export DATABASE_URL=\${${databaseName}} && export DATABASE_MIGRATIONS_TABLE=${projectJson.name} && export DATABASE_MIGRATIONS_LOCATIONS=.${flywayMigrationsPath} && ./node_modules/.bin/flyway -c .${flywayConfigFilePath} validate`,
], 'flyway-validate', undefined, this.flywayConfiguration.nxProjectJsonFile);
// repair
this.nxProjectJsonService.addRunCommands([
`export DATABASE_URL=\${${databaseName}} && export DATABASE_MIGRATIONS_TABLE=${projectJson.name} && export DATABASE_MIGRATIONS_LOCATIONS=.${flywayMigrationsPath} && ./node_modules/.bin/flyway -c .${flywayConfigFilePath} repair`,
], 'flyway-repair', undefined, this.flywayConfiguration.nxProjectJsonFile);
}
}
updateFlywayConfigFile() {
let flywayConfig = this.flywayConfigFileService.read();
if (!flywayConfig) {
flywayConfig = `
const { ConnectionString } = require('connection-string');
const cs = new ConnectionString(process.env.DATABASE_URL);
const {
user: USERNAME,
password: PASSWORD,
HOST = cs.host,
DATABASE = cs.path && cs.path[0],
SCHEMA = cs.params && cs.params.schema,
SCHEMAS = cs.params && cs.params.schemas,
} = cs;
module.exports = {
flywayArgs: {
url: \`jdbc:postgresql://\${HOST}/\${DATABASE}\`,
schemas: SCHEMAS || SCHEMA,
defaultSchema: SCHEMA,
locations: \`filesystem:\${process.env.DATABASE_MIGRATIONS_LOCATIONS || 'migrations'}\`,
user: USERNAME,
password: PASSWORD,
table: process.env.DATABASE_MIGRATIONS_TABLE ? \`__migrations_\${process.env.DATABASE_MIGRATIONS_TABLE}\` : '__migrations',
sqlMigrationSuffixes: '.sql',
baselineOnMigrate: true
},
// Use to configure environment variables used by flyway
env: {
JAVA_ARGS: '-Djava.util.logging.config.file=./conf/logging.properties',
},
version: '10.1.0', // optional, empty or missing will download the latest
mavinPlugins: [
{
// optional, use to add any plugins (ie. logging)
groupId: 'org.slf4j',
artifactId: 'slf4j-api',
version: '1.7.36',
// This can be a specifc url to download that may be different then the auto generated url.
downloadUrl:
'https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar',
},
{
groupId: 'org.slf4j',
artifactId: 'slf4j-jdk14',
version: '1.7.36',
},
],
downloads: {
storageDirectory: \`\${__dirname}/tmp\`, // optional, the specific directory to store the flyway downloaded files. The directory must be writable by the node app process' user.
expirationTimeInMs: -1, // optional, -1 will never check for updates, defaults to 1 day.
},
};
`;
this.flywayConfigFileService.write(flywayConfig);
}
}
createFirstMigrations() {
const flywayFeatureName = this.flywayConfiguration.featureName
? (0, case_anything_1.upperCamelCase)(this.flywayConfiguration.featureName)
: '';
const constantCaseFlywayFeatureName = this.flywayConfiguration.featureName
? (0, case_anything_1.constantCase)(this.flywayConfiguration.featureName)
: '';
const migrationFileName = `V202401212130__Create${flywayFeatureName}User.sql`;
const packageJsonFilePath = this.packageJsonService.getPackageJsonFilePath();
const firstMigrationFilePath = (0, path_1.join)(this.flywayConfiguration.migrationsFolder, migrationFileName);
if (packageJsonFilePath) {
try {
if (!this.flywayConfiguration.migrationsFolder && !(0, fs_1.existsSync)(this.flywayConfiguration.migrationsFolder)) {
(0, fs_1.mkdirSync)(this.flywayConfiguration.migrationsFolder, { recursive: true });
const firstMigration = `-- CreateTable
CREATE TABLE "${flywayFeatureName}User" (
"id" UUID NOT NULL DEFAULT uuid_generate_v4(),
"externalUserId" UUID NOT NULL,
"createdAt" TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "PK_${constantCaseFlywayFeatureName}_USER" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "UQ_${constantCaseFlywayFeatureName}_USER" ON "${flywayFeatureName}User"("externalUserId");
`;
if (!firstMigrationFilePath) {
return;
}
const fileDir = (0, path_1.dirname)(firstMigrationFilePath);
if (fileDir) {
if (!(0, fs_1.existsSync)(fileDir)) {
(0, fs_1.mkdirSync)(fileDir, { recursive: true });
}
(0, fs_1.writeFileSync)(firstMigrationFilePath, firstMigration);
}
}
}
catch (err) {
//
}
}
}
getDbConnectionEnvKeys() {
const concatedDatabaseName = [
this.wrapApplicationOptionsService.project?.name,
this.flywayConfiguration.featureName,
'DATABASE_URL',
]
.filter(Boolean)
.join('_');
const databaseName = this.flywayConfiguration.featureName
? `${(0, case_anything_1.constantCase)(concatedDatabaseName)}`
: `DATABASE_URL`;
return { databaseName };
}
parseDatabaseUrl(databaseUrl) {
if (!databaseUrl) {
return {};
}
try {
const cs = new connection_string_1.ConnectionString(databaseUrl);
const USERNAME = cs.user;
const PASSWORD = cs.password;
const PORT = cs.port;
const HOST = cs.hosts && cs.hosts[0].toString();
const DATABASE = cs.path && cs.path[0];
const SCHEMA = cs.params && cs.params['schema'];
const SCHEMAS = cs.params && cs.params['schemas'];
return { USERNAME, PASSWORD, HOST, DATABASE, SCHEMA, SCHEMAS, PORT, PROTOCOL: cs.protocol };
}
catch (error) {
return {};
}
}
};
exports.FlywayInfrastructureUpdaterService = FlywayInfrastructureUpdaterService;
exports.FlywayInfrastructureUpdaterService = FlywayInfrastructureUpdaterService = tslib_1.__decorate([
(0, common_2.Injectable)(),
tslib_1.__metadata("design:paramtypes", [common_1.PackageJsonService,
common_1.NxProjectJsonService,
flyway_configuration_1.FlywayConfiguration,
flyway_config_file_service_1.FlywayConfigFileService,
common_1.WrapApplicationOptionsService])
], FlywayInfrastructureUpdaterService);
//# sourceMappingURL=flyway-infrastructure-updater.service.js.map