2025-06-04 12:02:07 -04:00
|
|
|
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
|
|
|
import { db } from "../db/pg";
|
2024-12-25 15:49:35 -05:00
|
|
|
import semver from "semver";
|
2025-06-04 12:02:07 -04:00
|
|
|
import { versionMigrations } from "../db/pg";
|
2025-02-03 21:18:16 -05:00
|
|
|
import { __DIRNAME, APP_PATH, APP_VERSION } from "@server/lib/consts";
|
2025-06-04 12:02:07 -04:00
|
|
|
import path from "path";
|
2025-01-01 17:50:12 -05:00
|
|
|
|
|
|
|
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
|
|
|
// EXCEPT FOR THE DATABASE AND THE SCHEMA
|
2024-12-25 16:40:39 -05:00
|
|
|
|
|
|
|
// Define the migration list with versions and their corresponding functions
|
|
|
|
const migrations = [
|
|
|
|
// Add new migrations here as they are created
|
2025-06-04 12:02:07 -04:00
|
|
|
] as {
|
|
|
|
version: string;
|
|
|
|
run: () => Promise<void>;
|
|
|
|
}[];
|
2024-12-25 15:49:35 -05:00
|
|
|
|
2025-02-03 21:18:16 -05:00
|
|
|
await run();
|
|
|
|
|
|
|
|
async function run() {
|
|
|
|
// run the migrations
|
|
|
|
await runMigrations();
|
|
|
|
}
|
|
|
|
|
2024-12-25 15:49:35 -05:00
|
|
|
export async function runMigrations() {
|
2025-01-30 00:03:11 -05:00
|
|
|
try {
|
2025-02-02 15:30:41 -05:00
|
|
|
const appVersion = APP_VERSION;
|
2024-12-25 15:49:35 -05:00
|
|
|
|
2025-06-04 12:02:07 -04:00
|
|
|
// determine if the migrations table exists
|
|
|
|
const exists = await db
|
|
|
|
.select()
|
|
|
|
.from(versionMigrations)
|
|
|
|
.limit(1)
|
|
|
|
.execute()
|
|
|
|
.then((res) => res.length > 0)
|
|
|
|
.catch(() => false);
|
|
|
|
|
2025-01-30 00:03:11 -05:00
|
|
|
if (exists) {
|
2025-06-04 12:02:07 -04:00
|
|
|
console.log("Migrations table exists, running scripts...");
|
2025-01-30 00:03:11 -05:00
|
|
|
await executeScripts();
|
|
|
|
} else {
|
2025-06-04 12:02:07 -04:00
|
|
|
console.log("Migrations table does not exist, creating it...");
|
2025-01-30 00:03:11 -05:00
|
|
|
console.log("Running migrations...");
|
|
|
|
try {
|
2025-06-04 12:02:07 -04:00
|
|
|
await migrate(db, {
|
2025-01-30 00:03:11 -05:00
|
|
|
migrationsFolder: path.join(__DIRNAME, "init") // put here during the docker build
|
|
|
|
});
|
|
|
|
console.log("Migrations completed successfully.");
|
|
|
|
} catch (error) {
|
|
|
|
console.error("Error running migrations:", error);
|
|
|
|
}
|
|
|
|
|
|
|
|
await db
|
2025-01-30 23:30:33 -05:00
|
|
|
.insert(versionMigrations)
|
|
|
|
.values({
|
|
|
|
version: appVersion,
|
|
|
|
executedAt: Date.now()
|
|
|
|
})
|
|
|
|
.execute();
|
2025-01-30 00:03:11 -05:00
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
console.error("Error running migrations:", e);
|
2025-01-30 23:30:33 -05:00
|
|
|
await new Promise((resolve) =>
|
|
|
|
setTimeout(resolve, 1000 * 60 * 60 * 24 * 1)
|
|
|
|
);
|
2024-12-25 15:49:35 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-25 16:40:39 -05:00
|
|
|
async function executeScripts() {
|
2024-12-25 15:49:35 -05:00
|
|
|
try {
|
2024-12-25 16:40:39 -05:00
|
|
|
// Get the last executed version from the database
|
2025-01-30 23:30:33 -05:00
|
|
|
const lastExecuted = await db.select().from(versionMigrations);
|
2024-12-25 16:40:39 -05:00
|
|
|
|
2025-01-30 23:30:33 -05:00
|
|
|
// Filter and sort migrations
|
|
|
|
const pendingMigrations = lastExecuted
|
|
|
|
.map((m) => m)
|
|
|
|
.sort((a, b) => semver.compare(b.version, a.version));
|
|
|
|
const startVersion = pendingMigrations[0]?.version ?? "0.0.0";
|
2025-01-01 17:50:12 -05:00
|
|
|
console.log(`Starting migrations from version ${startVersion}`);
|
2024-12-25 16:40:39 -05:00
|
|
|
|
2025-01-30 23:30:33 -05:00
|
|
|
const migrationsToRun = migrations.filter((migration) =>
|
|
|
|
semver.gt(migration.version, startVersion)
|
|
|
|
);
|
|
|
|
|
|
|
|
console.log(
|
|
|
|
"Migrations to run:",
|
|
|
|
migrationsToRun.map((m) => m.version).join(", ")
|
|
|
|
);
|
2024-12-25 16:40:39 -05:00
|
|
|
|
|
|
|
// Run migrations in order
|
2025-01-30 23:30:33 -05:00
|
|
|
for (const migration of migrationsToRun) {
|
2025-01-01 17:50:12 -05:00
|
|
|
console.log(`Running migration ${migration.version}`);
|
2024-12-25 16:40:39 -05:00
|
|
|
|
|
|
|
try {
|
|
|
|
await migration.run();
|
|
|
|
|
|
|
|
// Update version in database
|
|
|
|
await db
|
|
|
|
.insert(versionMigrations)
|
|
|
|
.values({
|
|
|
|
version: migration.version,
|
|
|
|
executedAt: Date.now()
|
|
|
|
})
|
|
|
|
.execute();
|
|
|
|
|
2025-01-01 17:50:12 -05:00
|
|
|
console.log(
|
2024-12-25 16:40:39 -05:00
|
|
|
`Successfully completed migration ${migration.version}`
|
|
|
|
);
|
2025-01-30 23:30:33 -05:00
|
|
|
} catch (e) {
|
2025-02-03 21:18:16 -05:00
|
|
|
if (
|
2025-06-04 12:02:07 -04:00
|
|
|
e instanceof Error &&
|
|
|
|
typeof (e as any).code === "string" &&
|
|
|
|
(e as any).code === "23505"
|
2025-02-03 21:18:16 -05:00
|
|
|
) {
|
2025-01-30 23:30:33 -05:00
|
|
|
console.error("Migration has already run! Skipping...");
|
2025-06-04 12:02:07 -04:00
|
|
|
continue; // or return, depending on context
|
2025-01-30 23:30:33 -05:00
|
|
|
}
|
2025-06-04 12:02:07 -04:00
|
|
|
|
2025-01-01 16:40:01 -05:00
|
|
|
console.error(
|
2024-12-25 16:40:39 -05:00
|
|
|
`Failed to run migration ${migration.version}:`,
|
2025-01-30 23:30:33 -05:00
|
|
|
e
|
2024-12-25 16:40:39 -05:00
|
|
|
);
|
2025-06-04 12:02:07 -04:00
|
|
|
throw e;
|
2024-12-25 16:40:39 -05:00
|
|
|
}
|
|
|
|
}
|
2024-12-25 15:49:35 -05:00
|
|
|
|
2025-01-01 17:50:12 -05:00
|
|
|
console.log("All migrations completed successfully");
|
2024-12-25 16:40:39 -05:00
|
|
|
} catch (error) {
|
2025-01-01 16:40:01 -05:00
|
|
|
console.error("Migration process failed:", error);
|
2024-12-25 16:40:39 -05:00
|
|
|
throw error;
|
|
|
|
}
|
2024-12-25 15:49:35 -05:00
|
|
|
}
|