UNPKG

@directus/api

Version:

Directus is a real-time API and App dashboard for managing SQL database content

88 lines (86 loc) 4.27 kB
import { useLogger } from "../../logger/index.js"; import { flushCaches } from "../../cache.js"; import getModuleDefault from "../../utils/get-module-default.js"; import path from "path"; import { useEnv } from "@directus/env"; import { orderBy } from "lodash-es"; import { fileURLToPath } from "node:url"; import { dirname } from "node:path"; import fse from "fs-extra"; import formatTitle from "@directus/format-title"; //#region src/database/migrations/run.ts const __dirname = dirname(fileURLToPath(import.meta.url)); async function run(database, direction, log = true) { const env = useEnv(); const logger = useLogger(); let migrationFiles = await fse.readdir(__dirname); const customMigrationsPath = path.resolve(env["MIGRATIONS_PATH"]); let customMigrationFiles = await fse.pathExists(customMigrationsPath) && await fse.readdir(customMigrationsPath) || []; migrationFiles = migrationFiles.filter((file) => /^[0-9]+[A-Z]-[^.]+\.(?:js|ts)$/.test(file)); customMigrationFiles = customMigrationFiles.filter((file) => file.includes("-") && /\.(c|m)?js$/.test(file)); const completedMigrations = await database.select("*").from("directus_migrations").orderBy("version"); const migrations = [...migrationFiles.map((path$2) => parseFilePath(path$2)), ...customMigrationFiles.map((path$2) => parseFilePath(path$2, true))].sort((a, b) => a.version > b.version ? 1 : -1); const migrationKeys = new Set(migrations.map((m) => m.version)); if (migrations.length > migrationKeys.size) throw new Error("Migration keys collide! Please ensure that every migration uses a unique key."); function parseFilePath(filePath, custom = false) { const version = filePath.split("-")[0]; const name = formatTitle(filePath.split("-").slice(1).join("_").split(".")[0]); const completed = !!completedMigrations.find((migration) => migration.version === version); return { file: custom ? path.join(customMigrationsPath, filePath) : path.join(__dirname, filePath), version, name, completed }; } if (direction === "up") await up(); if (direction === "down") await down(); if (direction === "latest") await latest(); async function up() { const currentVersion = completedMigrations[completedMigrations.length - 1]; let nextVersion; if (!currentVersion) nextVersion = migrations[0]; else nextVersion = migrations.find((migration) => { return migration.version > currentVersion.version && migration.completed === false; }); if (!nextVersion) throw Error("Nothing to upgrade"); const { up: up$1 } = await import(`file://${nextVersion.file}`); if (!up$1) logger.warn(`Couldn't find the "up" function from migration ${nextVersion.file}`); if (log) logger.info(`Applying ${nextVersion.name}...`); await up$1(database); await database.insert({ version: nextVersion.version, name: nextVersion.name }).into("directus_migrations"); await flushCaches(true); } async function down() { const lastAppliedMigration = orderBy(completedMigrations, ["timestamp", "version"], ["desc", "desc"])[0]; if (!lastAppliedMigration) throw Error("Nothing to downgrade"); const migration = migrations.find((migration$1) => migration$1.version === lastAppliedMigration.version); if (!migration) throw new Error("Couldn't find migration"); const { down: down$1 } = await import(`file://${migration.file}`); if (!down$1) logger.warn(`Couldn't find the "down" function from migration ${migration.file}`); if (log) logger.info(`Undoing ${migration.name}...`); await down$1(database); await database("directus_migrations").delete().where({ version: migration.version }); await flushCaches(true); } async function latest() { let needsCacheFlush = false; for (const migration of migrations) if (migration.completed === false) { needsCacheFlush = true; const { up: up$1 } = getModuleDefault(await import(`file://${migration.file}`)); if (!up$1) logger.warn(`Couldn't find the "up" function from migration ${migration.file}`); if (log) logger.info(`Applying ${migration.name}...`); await up$1(database); await database.insert({ version: migration.version, name: migration.name }).into("directus_migrations"); } if (needsCacheFlush) await flushCaches(true); } } //#endregion export { run as default };