Dealer_Onboarding_Backend/scripts/create-migration.ts

107 lines
3.1 KiB
TypeScript

/**
* Scaffold a new migration file under `scripts/migrations/`.
*
* Usage: npm run migrate:create -- <snake_case_description>
* e.g.: npm run migrate:create -- add_finance_kyc_column
*
* The file is named `<YYYYMMDDHHMMSS>_<description>.ts` (UTC timestamp).
* Author then edits `up()` to implement the schema change.
*/
import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const SCRIPTS_DIR = path.dirname(fileURLToPath(import.meta.url));
const MIGRATIONS_DIR = path.join(SCRIPTS_DIR, 'migrations');
function pad(n: number, width = 2): string {
return String(n).padStart(width, '0');
}
function utcTimestamp(): string {
const d = new Date();
return (
d.getUTCFullYear().toString() +
pad(d.getUTCMonth() + 1) +
pad(d.getUTCDate()) +
pad(d.getUTCHours()) +
pad(d.getUTCMinutes()) +
pad(d.getUTCSeconds())
);
}
function sanitizeName(input: string): string {
const cleaned = input
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, '_')
.replace(/^_+|_+$/g, '');
if (!cleaned) {
throw new Error('Migration name is empty after sanitisation.');
}
if (cleaned.length > 80) {
throw new Error(
`Migration name "${cleaned}" is too long (${cleaned.length}). Keep it under 80 chars.`
);
}
return cleaned;
}
async function main(): Promise<void> {
const rawName = process.argv.slice(2).join('_');
if (!rawName) {
console.error('Missing migration name.');
console.error('Usage: npm run migrate:create -- <snake_case_description>');
process.exit(1);
}
const name = sanitizeName(rawName);
const ts = utcTimestamp();
const filename = `${ts}_${name}.ts`;
const target = path.join(MIGRATIONS_DIR, filename);
const body = `/**
* Migration: ${name.replace(/_/g, ' ')}
*
* Generated at ${new Date().toISOString()}.
* Implement up() with idempotent DDL where possible.
*/
import type { QueryInterface, Sequelize, Transaction } from 'sequelize';
export interface MigrationContext {
queryInterface: QueryInterface;
sequelize: Sequelize;
transaction: Transaction;
}
const migration = {
async up({ sequelize, transaction }: MigrationContext): Promise<void> {
// TODO: implement the schema change.
// Example:
// await sequelize.query(\`
// ALTER TABLE "applications"
// ADD COLUMN IF NOT EXISTS "kycReviewedAt" TIMESTAMPTZ NULL;
// \`, { transaction });
throw new Error('Migration ${filename} has no up() implementation yet.');
}
};
export default migration;
`;
await fs.mkdir(MIGRATIONS_DIR, { recursive: true });
await fs.writeFile(target, body, { flag: 'wx' });
console.log(`Created ${path.relative(process.cwd(), target)}`);
console.log('Next:');
console.log(' 1. Edit the file and implement up().');
console.log(' 2. Update the matching Sequelize model.');
console.log(' 3. Run: npm run migrate:up');
}
main().catch((err) => {
console.error('create-migration failed:', err?.message || err);
process.exit(1);
});