[feat] Init code
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
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();
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const readline = require('readline');
|
||||
const { padLeft } = require('src/utils/index.js');
|
||||
|
||||
const schemaDir = path.resolve(__dirname, '..', 'schemas');
|
||||
|
||||
(async () => {
|
||||
const args = process.argv.slice(2);
|
||||
let filename = args[0] || '';
|
||||
if (args.length === 0) {
|
||||
// use readline
|
||||
filename = await new Promise(resolve => {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
rl.prompt();
|
||||
rl.question('schema filename: ', ans => {
|
||||
resolve(ans.replace(' ', '_'));
|
||||
|
||||
rl.close();
|
||||
});
|
||||
|
||||
rl.once('close', resolve);
|
||||
});
|
||||
}
|
||||
|
||||
if (filename === '') throw new Error('no schema filename');
|
||||
|
||||
const schemaFiles = await fs.promises.readdir(schemaDir);
|
||||
let version = 0;
|
||||
|
||||
schemaFiles.forEach(name => {
|
||||
if (!name.endsWith('.sql')) return;
|
||||
|
||||
const strInt = name.split(/_/g)[0];
|
||||
const v = parseInt(strInt, 10);
|
||||
if (isNaN(v)) return; // eslint-disable-line
|
||||
|
||||
if (v > version) version = v;
|
||||
});
|
||||
|
||||
// 版本要比最後一筆加一
|
||||
version += 1;
|
||||
|
||||
const schemaName = `${padLeft(`${version}`, 6, '0')}_${filename}.sql`;
|
||||
|
||||
const schemaText = `-- Created Time ${new Date().toISOString()}`;
|
||||
|
||||
await fs.promises.writeFile(path.resolve(schemaDir, schemaName), schemaText, 'utf-8');
|
||||
|
||||
console.info(`File: ${path.resolve(schemaDir, schemaName)} Created!`);
|
||||
})().catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user