mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 16:02:14 +00:00
feat: add datatable migrate new command to scaffold migrations
This commit is contained in:
@@ -10,6 +10,7 @@ import { runCatalogQuery } from "../../utils/catalog.ts";
|
||||
import { psql as psqlDatatable } from "./psql.ts";
|
||||
import { serve as serveDatatable } from "./serve.ts";
|
||||
import {
|
||||
createMigration,
|
||||
rollbackMigrations,
|
||||
runMigrations,
|
||||
} from "../datatable_migrations.ts";
|
||||
@@ -45,6 +46,13 @@ async function run(
|
||||
await runCatalogQuery(opts, "datatable", name, sql);
|
||||
}
|
||||
|
||||
function migrateNew(
|
||||
opts: GlobalOptions & { datatable?: string },
|
||||
name: string,
|
||||
) {
|
||||
createMigration(opts.datatable ?? DEFAULT_DATATABLE_NAME, name);
|
||||
}
|
||||
|
||||
async function migrateUp(opts: GlobalOptions, name?: string) {
|
||||
const workspace = await resolveWorkspace(opts);
|
||||
await requireLogin(opts);
|
||||
@@ -58,7 +66,14 @@ async function migrateDown(opts: GlobalOptions, name?: string) {
|
||||
}
|
||||
|
||||
const migrateCommand = new Command()
|
||||
.description("apply or roll back datatable migrations")
|
||||
.description("manage datatable migrations")
|
||||
.command("new", "scaffold a new migration (.up.sql / .down.sql files)")
|
||||
.arguments("<name:string>")
|
||||
.option(
|
||||
"-d --datatable <datatable:string>",
|
||||
"Target datatable (default: main)",
|
||||
)
|
||||
.action(migrateNew as any)
|
||||
.command("up", "apply all pending migrations to a datatable")
|
||||
.arguments("[name:string]")
|
||||
.action(migrateUp as any)
|
||||
|
||||
@@ -11,6 +11,47 @@ import { Confirm } from "@cliffy/prompt/confirm";
|
||||
// target data table, as `<timestamp>_<name>.up.sql` (and optional `.down.sql`).
|
||||
const MIGRATIONS_DIR = "datatable_migrations";
|
||||
|
||||
// Migration names map directly onto file names and the DB `name` column.
|
||||
const MIGRATION_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
||||
|
||||
/** Current UTC time as a YYYYMMDDHHMMSS migration version. */
|
||||
function migrationTimestamp(): string {
|
||||
const d = new Date();
|
||||
const p = (n: number) => String(n).padStart(2, "0");
|
||||
return (
|
||||
`${d.getUTCFullYear()}${p(d.getUTCMonth() + 1)}${p(d.getUTCDate())}` +
|
||||
`${p(d.getUTCHours())}${p(d.getUTCMinutes())}${p(d.getUTCSeconds())}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scaffold a new migration under datatable_migrations/<datatable>/ as empty
|
||||
* `<timestamp>_<name>.up.sql` and `.down.sql` files. Purely local — no network.
|
||||
*/
|
||||
export function createMigration(datatable: string, name: string): void {
|
||||
if (!MIGRATION_NAME_RE.test(name)) {
|
||||
throw new Error(
|
||||
`Invalid migration name '${name}': use only letters, digits, '_' and '-'`,
|
||||
);
|
||||
}
|
||||
const dir = path.join(process.cwd(), MIGRATIONS_DIR, datatable);
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
|
||||
const timestamp = migrationTimestamp();
|
||||
const base = `${timestamp}_${name}`;
|
||||
const up = path.join(dir, `${base}.up.sql`);
|
||||
const down = path.join(dir, `${base}.down.sql`);
|
||||
fs.writeFileSync(up, `-- up migration: ${name}\n`, "utf-8");
|
||||
fs.writeFileSync(down, `-- down migration: ${name}\n`, "utf-8");
|
||||
|
||||
log.info(
|
||||
colors.green(`Created migration ${base} in ${MIGRATIONS_DIR}/${datatable}/`),
|
||||
);
|
||||
for (const f of [up, down]) {
|
||||
log.info(colors.gray(` ${path.relative(process.cwd(), f)}`));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the workspace's pending migrations to a data table (forwards migrations
|
||||
* recorded in `_wm_migrations`). Mirrors `wmill datatable migrate up`.
|
||||
|
||||
Reference in New Issue
Block a user