keycloak-demo/bin/db-migrate.js

115 lines
2.9 KiB
JavaScript

const pg = require('pg');
const fs = require('fs');
const path = require('path');
const config = require('src/config/index.js');
// schema file name format ######_name.sql
const schemaDir = path.resolve(__dirname, '..', 'schemas');
const db = new pg.Client({
host: config.database.host,
port: config.database.port,
user: config.database.user,
password: config.database.password,
database: config.database.dbname,
});
(async () => {
await db.connect();
await db.query(`select now();`);
let version = -1;
// check migrate record table exists
const checkTable = await db.query(
`
select exists(
select 1
from "information_schema"."tables"
where
"table_schema" = $1
and "table_name" = $2
) as exists
`,
['public', 'migrate_log']
);
if (checkTable.rowCount > 0 && checkTable.rows[0].exists === true) {
// version table exists
const maxVersion = await db.query(`select max("version")::integer as version from "public"."migrate_log"`);
if (maxVersion.rowCount > 0 && maxVersion.rows[0] && maxVersion.rows[0].version !== null) version = maxVersion.rows[0].version; // eslint-disable-line
} else {
// create version table
await db.query(`create table "public"."migrate_log" (
"version" integer not null primary key,
"created_time" timestamptz not null default now()
);`);
}
console.info(`Database Now Version: ${version}`);
// read all schema files
const schemaList = await fs.promises.readdir(schemaDir);
/**
* @type {{[x: number]: boolean}}
*/
const checkDuplicate = {};
/**
* @type {{version: number, filename: string}[]}
*/
const versionList = schemaList
.map(file => {
const strs = file.split('_');
const v = parseInt(strs[0], 10);
if (isNaN(version)) throw new Error(`schema filename format error (######_name.sql)`); // eslint-disable-line
if (v in checkDuplicate) throw new Error(`schema file version (${v}) is duplicate`);
checkDuplicate[v] = true;
return { version: v, filename: file };
})
.filter(t => t && t.version > version)
.sort((a, b) => a.version - b.version);
// 沒有需要更新的檔案
if (versionList.length === 0) return;
await db.query('begin');
try {
const vers = [];
// write all schema file
for (const it of versionList) {
vers.push(`(${it.version})`);
console.info(`Write Version: ${it.version}`);
const fileContent = await fs.promises.readFile(path.resolve(schemaDir, it.filename), 'utf-8');
await db.query(fileContent);
}
await db.query(`insert into "public"."migrate_log" ("version") values ${vers.join(',')}`);
await db.query('commit');
} catch (err) {
await db.query('rollback');
throw err;
}
})()
.then(() => {
console.info('Database Migrate Finish');
})
.catch(err => {
console.error('Database Migrate Failed, ', err);
process.exit(1);
})
.finally(() => {
db.end();
});