import { type Kysely, type Migration, type MigrationProvider, Migrator, sql, } from "kysely"; import type { Database } from "./db.ts"; const migrations: Record = {}; const migrationProvider: MigrationProvider = { // deno-lint-ignore require-await async getMigrations() { return migrations; }, }; migrations["001"] = { async up(db: Kysely): Promise { await db.schema .createTable("virtual_machines") .addColumn("id", "varchar", (col) => col.primaryKey()) .addColumn("name", "varchar", (col) => col.notNull().unique()) .addColumn("bridge", "varchar") .addColumn("macAddress", "varchar", (col) => col.notNull().unique()) .addColumn("memory", "varchar", (col) => col.notNull()) .addColumn("cpus", "integer", (col) => col.notNull()) .addColumn("cpu", "varchar", (col) => col.notNull()) .addColumn("diskSize", "varchar", (col) => col.notNull()) .addColumn("drivePath", "varchar") .addColumn("version", "varchar", (col) => col.notNull()) .addColumn("diskFormat", "varchar") .addColumn("isoPath", "varchar") .addColumn("status", "varchar", (col) => col.notNull()) .addColumn("pid", "integer") .addColumn( "createdAt", "varchar", (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), ) .addColumn( "updatedAt", "varchar", (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), ) .execute(); }, async down(db: Kysely): Promise { await db.schema.dropTable("virtual_machines").execute(); }, }; migrations["002"] = { async up(db: Kysely): Promise { await db.schema .alterTable("virtual_machines") .addColumn("portForward", "varchar") .execute(); }, async down(db: Kysely): Promise { await db.schema .alterTable("virtual_machines") .dropColumn("portForward") .execute(); }, }; migrations["003"] = { async up(db: Kysely): Promise { await db.schema .createTable("images") .addColumn("id", "varchar", (col) => col.primaryKey()) .addColumn("repository", "varchar", (col) => col.notNull()) .addColumn("tag", "varchar", (col) => col.notNull()) .addColumn("size", "integer", (col) => col.notNull()) .addColumn("path", "varchar", (col) => col.notNull()) .addColumn("createdAt", "varchar", (col) => col.notNull()) .execute(); }, async down(db: Kysely): Promise { await db.schema.dropTable("images").execute(); }, }; migrations["004"] = { async up(db: Kysely): Promise { await db.schema .alterTable("images") .addColumn("format", "varchar", (col) => col.notNull().defaultTo("qcow2")) .execute(); }, async down(db: Kysely): Promise { await db.schema.alterTable("images").dropColumn("format").execute(); }, }; migrations["005"] = { async up(db: Kysely): Promise { await db.schema .createTable("images_new") .addColumn("id", "varchar", (col) => col.primaryKey()) .addColumn("repository", "varchar", (col) => col.notNull()) .addColumn("tag", "varchar", (col) => col.notNull()) .addColumn("size", "integer", (col) => col.notNull()) .addColumn("path", "varchar", (col) => col.notNull()) .addColumn("format", "varchar", (col) => col.notNull().defaultTo("qcow2")) .addColumn("createdAt", "varchar", (col) => col.notNull()) .addUniqueConstraint("images_repository_tag_unique", [ "repository", "tag", ]) .execute(); await sql` INSERT INTO images_new (id, repository, tag, size, path, format, createdAt) SELECT id, repository, tag, size, path, format, createdAt FROM images `.execute(db); await db.schema.dropTable("images").execute(); await sql`ALTER TABLE images_new RENAME TO images`.execute(db); }, async down(db: Kysely): Promise { await db.schema .createTable("images_old") .addColumn("id", "varchar", (col) => col.primaryKey()) .addColumn("repository", "varchar", (col) => col.notNull()) .addColumn("tag", "varchar", (col) => col.notNull()) .addColumn("size", "integer", (col) => col.notNull()) .addColumn("path", "varchar", (col) => col.notNull()) .addColumn("format", "varchar", (col) => col.notNull().defaultTo("qcow2")) .addColumn("createdAt", "varchar", (col) => col.notNull()) .execute(); await sql` INSERT INTO images_old (id, repository, tag, size, path, format, createdAt) SELECT id, repository, tag, size, path, format, createdAt FROM images `.execute(db); await db.schema.dropTable("images").execute(); await sql`ALTER TABLE images_old RENAME TO images`.execute(db); }, }; migrations["006"] = { async up(db: Kysely): Promise { await db.schema .createTable("images_new") .addColumn("id", "varchar", (col) => col.primaryKey()) .addColumn("repository", "varchar", (col) => col.notNull()) .addColumn("tag", "varchar", (col) => col.notNull()) .addColumn("size", "integer", (col) => col.notNull()) .addColumn("path", "varchar", (col) => col.notNull()) .addColumn("format", "varchar", (col) => col.notNull().defaultTo("qcow2")) .addColumn( "createdAt", "varchar", (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), ) .addUniqueConstraint("images_repository_tag_unique", [ "repository", "tag", ]) .execute(); await sql` INSERT INTO images_new (id, repository, tag, size, path, format, createdAt) SELECT id, repository, tag, size, path, format, createdAt FROM images `.execute(db); await db.schema.dropTable("images").execute(); await sql`ALTER TABLE images_new RENAME TO images`.execute(db); }, async down(db: Kysely): Promise { await db.schema .createTable("images_old") .addColumn("id", "varchar", (col) => col.primaryKey()) .addColumn("repository", "varchar", (col) => col.notNull()) .addColumn("tag", "varchar", (col) => col.notNull()) .addColumn("size", "integer", (col) => col.notNull()) .addColumn("path", "varchar", (col) => col.notNull()) .addColumn("format", "varchar", (col) => col.notNull().defaultTo("qcow2")) .addColumn("createdAt", "varchar", (col) => col.notNull()) .addUniqueConstraint("images_repository_tag_unique", [ "repository", "tag", ]) .execute(); await sql` INSERT INTO images_old (id, repository, tag, size, path, format, createdAt) SELECT id, repository, tag, size, path, format, createdAt FROM images `.execute(db); }, }; migrations["007"] = { async up(db: Kysely): Promise { await db.schema .alterTable("images") .addColumn("digest", "varchar") .execute(); }, async down(db: Kysely): Promise { await db.schema.alterTable("images").dropColumn("digest").execute(); }, }; migrations["008"] = { async up(db: Kysely): Promise { await db.schema .createTable("volumes") .addColumn("id", "varchar", (col) => col.primaryKey()) .addColumn("name", "varchar", (col) => col.notNull().unique()) .addColumn( "baseImageId", "varchar", (col) => col.notNull().references("images.id").onDelete("cascade"), ) .addColumn("path", "varchar", (col) => col.notNull()) .addColumn( "createdAt", "varchar", (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), ) .execute(); }, async down(db: Kysely): Promise { await db.schema.dropTable("volumes").execute(); }, }; migrations["009"] = { async up(db: Kysely): Promise { await db.schema .createTable("volumes_new") .addColumn("id", "varchar", (col) => col.primaryKey()) .addColumn("name", "varchar", (col) => col.notNull().unique()) .addColumn( "baseImageId", "varchar", (col) => col.notNull().references("images.id").onDelete("cascade"), ) .addColumn("path", "varchar", (col) => col.notNull()) .addColumn( "createdAt", "varchar", (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), ) .execute(); await sql` INSERT INTO volumes_new (id, name, baseImageId, path, createdAt) SELECT id, name, baseImageId, path, createdAt FROM volumes `.execute(db); await db.schema.dropTable("volumes").execute(); await sql`ALTER TABLE volumes_new RENAME TO volumes`.execute(db); }, async down(db: Kysely): Promise { await db.schema.dropTable("volumes").execute(); }, }; migrations["010"] = { async up(db: Kysely): Promise { await db.schema .alterTable("virtual_machines") .addColumn("volume", "varchar") .execute(); }, async down(db: Kysely): Promise { await db.schema .alterTable("virtual_machines") .dropColumn("volume") .execute(); }, }; migrations["011"] = { async up(db: Kysely): Promise { await db.schema .alterTable("virtual_machines") .addColumn("seed", "varchar") .execute(); }, async down(db: Kysely): Promise { await db.schema.alterTable("virtual_machines").dropColumn("seed").execute(); }, }; migrations["012"] = { async up(db: Kysely): Promise { // make version nullable await db.schema .createTable("virtual_machines_new") .addColumn("id", "varchar", (col) => col.primaryKey()) .addColumn("name", "varchar", (col) => col.notNull().unique()) .addColumn("bridge", "varchar") .addColumn("macAddress", "varchar", (col) => col.notNull().unique()) .addColumn("memory", "varchar", (col) => col.notNull()) .addColumn("cpus", "integer", (col) => col.notNull()) .addColumn("cpu", "varchar", (col) => col.notNull()) .addColumn("diskSize", "varchar", (col) => col.notNull()) .addColumn("drivePath", "varchar") .addColumn("version", "varchar") .addColumn("diskFormat", "varchar") .addColumn("isoPath", "varchar") .addColumn("portForward", "varchar") .addColumn("status", "varchar", (col) => col.notNull()) .addColumn("pid", "integer") .addColumn("volume", "varchar") .addColumn("seed", "varchar") .addColumn( "createdAt", "varchar", (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), ) .addColumn( "updatedAt", "varchar", (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), ) .execute(); await sql` INSERT INTO virtual_machines_new (id, name, bridge, macAddress, memory, cpus, cpu, diskSize, drivePath, version, diskFormat, isoPath, portForward, status, pid, volume, seed, createdAt, updatedAt) SELECT id, name, bridge, macAddress, memory, cpus, cpu, diskSize, drivePath, version, diskFormat, isoPath, portForward, status, pid, volume, seed, createdAt, updatedAt FROM virtual_machines `.execute(db); await db.schema.dropTable("virtual_machines").execute(); await sql`ALTER TABLE virtual_machines_new RENAME TO virtual_machines` .execute( db, ); }, async down(db: Kysely): Promise { // make version not nullable await db.schema .createTable("virtual_machines_old") .addColumn("id", "varchar", (col) => col.primaryKey()) .addColumn("name", "varchar", (col) => col.notNull().unique()) .addColumn("bridge", "varchar") .addColumn("macAddress", "varchar", (col) => col.notNull().unique()) .addColumn("memory", "varchar", (col) => col.notNull()) .addColumn("cpus", "integer", (col) => col.notNull()) .addColumn("cpu", "varchar", (col) => col.notNull()) .addColumn("diskSize", "varchar", (col) => col.notNull()) .addColumn("drivePath", "varchar") .addColumn("version", "varchar", (col) => col.notNull()) .addColumn("diskFormat", "varchar") .addColumn("isoPath", "varchar") .addColumn("portForward", "varchar") .addColumn("status", "varchar", (col) => col.notNull()) .addColumn("pid", "integer") .addColumn("volume", "varchar") .addColumn("seed", "varchar") .addColumn( "createdAt", "varchar", (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), ) .addColumn( "updatedAt", "varchar", (col) => col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`), ) .execute(); await sql` INSERT INTO virtual_machines_old (id, name, bridge, macAddress, memory, cpus, cpu, diskSize, drivePath, version, diskFormat, isoPath, portForward, status, pid, volume, seed, createdAt, updatedAt) SELECT id, name, bridge, macAddress, memory, cpus, cpu, diskSize, drivePath, version, diskFormat, isoPath, portForward, status, pid, volume, seed, createdAt, updatedAt FROM virtual_machines `.execute(db); await db.schema.dropTable("virtual_machines").execute(); await sql`ALTER TABLE virtual_machines_old RENAME TO virtual_machines` .execute( db, ); }, }; export const migrateToLatest = async (db: Database): Promise => { const migrator = new Migrator({ db, provider: migrationProvider }); const { error } = await migrator.migrateToLatest(); if (error) throw error; };