From 99ccdc1326770e1ebd7cf9b1705c819812485564 Mon Sep 17 00:00:00 2001 From: NGPixel Date: Wed, 12 Aug 2026 03:19:41 -0400 Subject: [PATCH] feat: prevent migrations on v2 db and exit with error --- backend/core/db.ts | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/backend/core/db.ts b/backend/core/db.ts index b2acebfea..ce4600982 100644 --- a/backend/core/db.ts +++ b/backend/core/db.ts @@ -2,6 +2,7 @@ import { isPlainObject } from 'es-toolkit/predicate' import path from 'node:path' import fs from 'node:fs/promises' import { setTimeout } from 'node:timers/promises' +import { sql } from 'drizzle-orm' import { drizzle } from 'drizzle-orm/node-postgres' import { migrate } from 'drizzle-orm/node-postgres/migrator' import { Pool, type PoolClient, type PoolConfig } from 'pg' @@ -13,7 +14,6 @@ import { flags } from '../models/flags.ts' import { createDeferred } from '../helpers/common.ts' import { createNotifier } from '../helpers/pubsub.ts' // import migrationSource from '../db/migrator-source.js' -// const migrateFromLegacy = require('../db/legacy') /** * Sends the event bus's cross-instance notifications, one at a time. @@ -34,6 +34,17 @@ const notifier = createNotifier(() => WIKI.dbManager.pubsubClient, 'event bus') */ const REQUIRED_EXTENSIONS = ['ltree', 'pg_trgm'] +/** + * Tables whose presence means the database belongs to a Wiki.js 2.x installation. + * + * `knex_migrations` is the 2.x migration ledger — 3.x tracks its own in `migrations`, via Drizzle — + * and `searchEngines` is a 2.x-only table, kept as a second signal for a database whose migration + * ledger somebody has dropped or renamed. Either one is enough: 3.x creates neither, so seeing one + * cannot be a 3.x database. The names are the exact identifiers 2.x created, `searchEngines` + * included, so they are compared case-sensitively against `information_schema`. + */ +const LEGACY_TABLES = ['knex_migrations', 'searchEngines'] + /** * Query logger, consulted by Drizzle on every query. * @@ -73,7 +84,6 @@ export default { config: null as PoolConfig | null, dbName: null as string | null | undefined, VERSION: null as string | null, - LEGACY: false, onReady: createDeferred(), connectAttempts: 0, /** @@ -276,10 +286,34 @@ export default { } } }, + /** + * Refuse to run against a Wiki.js 2.x database. + * + * Checked before anything is created or migrated, because there is no upgrade path: the 3.x + * migrations would run over the 2.x tables they know nothing about and leave a database that is + * neither version. Exits rather than throws — a 2.x database is not something a retry or a later + * boot phase can recover from, and the operator has to point the config at a fresh one. + */ + async checkForLegacyInstall(db: WikiDb): Promise { + const res = await db.execute(sql` + SELECT table_name FROM information_schema.tables + WHERE table_schema = ${WIKI.config.db.schema} AND table_name IN ${LEGACY_TABLES} + LIMIT 1 + `) + if (res.rows.length > 0) { + WIKI.logger.error('ERROR: UPGRADING FROM A 2.x INSTALLATION IS NOT YET SUPPORTED. Exiting...') + WIKI.logger.error( + `Found the Wiki.js 2.x table "${res.rows[0].table_name}" in schema "${WIKI.config.db.schema}".` + ) + process.exit(1) + } + }, /** * Migrate DB Schemas */ async syncSchemas(db: WikiDb) { + await this.checkForLegacyInstall(db) + WIKI.logger.info('Ensuring DB schema exists...') await db.execute(`CREATE SCHEMA IF NOT EXISTS ${WIKI.config.db.schema}`)