UNPKG

payload

Version:

Node, React, Headless CMS and Application Framework built on Next.js

213 lines (212 loc) • 8.57 kB
import { hasLocalizeStatusEnabled } from '../../../../utilities/getVersionsConfig.js'; import { toSnakeCase } from '../shared.js'; export async function down(args) { const { collectionSlug, db, globalSlug, payload, sql } = args; if (!collectionSlug && !globalSlug) { throw new Error('Either collectionSlug or globalSlug must be provided'); } if (collectionSlug && globalSlug) { throw new Error('Cannot provide both collectionSlug and globalSlug'); } const entitySlug = collectionSlug || globalSlug; // Convert camelCase slugs to snake_case and add version prefix/suffix const versionsTable = collectionSlug ? `_${toSnakeCase(collectionSlug)}_v` : `_${toSnakeCase(globalSlug)}_v`; const localesTable = `${versionsTable}_locales`; if (!payload.config.localization) { throw new Error('Localization is not enabled in payload config'); } const entityConfig = collectionSlug ? payload.config.collections.find((c)=>c.slug === collectionSlug) : payload.config.globals.find((g)=>g.slug === globalSlug); if (!entityConfig) { throw new Error(`${collectionSlug ? 'Collection' : 'Global'} not found: ${collectionSlug || globalSlug}`); } if (hasLocalizeStatusEnabled(entityConfig)) { throw new Error(`${entitySlug} has localizeStatus enabled, cannot run down migration. ` + `Please disable localizeStatus in your config before rolling back this migration.`); } const defaultLocale = payload.config.localization.defaultLocale; payload.logger.info({ msg: `Rolling back _status localization migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug}` }); // 1. Restore version__status column to main table payload.logger.info({ msg: `Restoring version__status column to ${versionsTable}` }); await db.execute({ drizzle: db.drizzle, sql: sql` ALTER TABLE ${sql.identifier(versionsTable)} ADD COLUMN version__status VARCHAR ` }); // 2. Copy status from default locale back to main table payload.logger.info({ msg: `Copying status from default locale (${defaultLocale}) back to main table` }); await db.execute({ drizzle: db.drizzle, sql: sql` UPDATE ${sql.identifier(versionsTable)} pv SET version__status = pl.version__status FROM ${sql.identifier(localesTable)} pl WHERE pv.id = pl._parent_id AND pl._locale = ${defaultLocale} ` }); // 3. Check if there are other localized fields besides version__status const columnCheckResult = await db.execute({ drizzle: db.drizzle, sql: sql` SELECT COUNT(*) as count FROM information_schema.columns WHERE table_schema = 'public' AND table_name = ${localesTable} AND column_name NOT IN ('id', '_locale', '_parent_id', 'version__status') ` }); const hasOtherLocalizedFields = Number(columnCheckResult.rows[0]?.count) > 0; if (!hasOtherLocalizedFields) { // SCENARIO 1 ROLLBACK: No other localized fields, drop entire table payload.logger.info({ msg: `Dropping entire locales table: ${localesTable}` }); await db.execute({ drizzle: db.drizzle, sql: sql`DROP TABLE ${sql.identifier(localesTable)} CASCADE` }); } else { // SCENARIO 2 ROLLBACK: Other localized fields exist, just drop version__status column payload.logger.info({ msg: `Dropping version__status column from ${localesTable}` }); await db.execute({ drizzle: db.drizzle, sql: sql` ALTER TABLE ${sql.identifier(localesTable)} DROP COLUMN version__status ` }); } // 4. Restore _status to main collection/global table if it was dropped const mainTable = collectionSlug ? toSnakeCase(collectionSlug) : toSnakeCase(globalSlug); const mainLocalesTable = `${mainTable}_locales`; // Check if _status exists in the main table const statusInMainTableCheck = await db.execute({ drizzle: db.drizzle, sql: sql` SELECT EXISTS ( SELECT FROM information_schema.columns WHERE table_schema = 'public' AND table_name = ${mainTable} AND column_name = '_status' ) as exists ` }); if (!statusInMainTableCheck.rows[0]?.exists) { // _status column doesn't exist in main table, need to restore it // Check if main collection/global has a locales table const mainLocalesTableCheck = await db.execute({ drizzle: db.drizzle, sql: sql` SELECT EXISTS ( SELECT FROM information_schema.tables WHERE table_schema = 'public' AND table_name = ${mainLocalesTable} ) as exists ` }); if (mainLocalesTableCheck.rows[0]?.exists) { // Locales table exists - check if _status is there const statusInLocalesCheck = await db.execute({ drizzle: db.drizzle, sql: sql` SELECT EXISTS ( SELECT FROM information_schema.columns WHERE table_schema = 'public' AND table_name = ${mainLocalesTable} AND column_name = '_status' ) as exists ` }); if (statusInLocalesCheck.rows[0]?.exists) { // Add _status back to main table payload.logger.info({ msg: `Restoring _status column to ${mainTable}` }); await db.execute({ drizzle: db.drizzle, sql: sql` ALTER TABLE ${sql.identifier(mainTable)} ADD COLUMN _status VARCHAR ` }); // Copy status from default locale back to main table await db.execute({ drizzle: db.drizzle, sql: sql` UPDATE ${sql.identifier(mainTable)} m SET _status = l._status FROM ${sql.identifier(mainLocalesTable)} l WHERE m.id = l._parent_id AND l._locale = ${defaultLocale} ` }); // Drop _status from locales table payload.logger.info({ msg: `Dropping _status column from ${mainLocalesTable}` }); await db.execute({ drizzle: db.drizzle, sql: sql` ALTER TABLE ${sql.identifier(mainLocalesTable)} DROP COLUMN _status ` }); } } else { // No locales table exists - this means collection/global has no localized fields // Just add _status back to main table with default values payload.logger.info({ msg: `Restoring _status column to ${mainTable} (no locales table exists)` }); await db.execute({ drizzle: db.drizzle, sql: sql` ALTER TABLE ${sql.identifier(mainTable)} ADD COLUMN _status VARCHAR ` }); // Set default status based on latest version status for each document // Get all documents in the collection const documents = await db.execute({ drizzle: db.drizzle, sql: sql` SELECT DISTINCT id FROM ${sql.identifier(mainTable)} ` }); for (const doc of documents.rows){ // Get latest version status for this document const latestVersionStatus = await db.execute({ drizzle: db.drizzle, sql: sql` SELECT version__status FROM ${sql.identifier(versionsTable)} WHERE parent_id = ${doc.id} ORDER BY created_at DESC LIMIT 1 ` }); const status = latestVersionStatus.rows[0]?.version__status || 'draft'; await db.execute({ drizzle: db.drizzle, sql: sql` UPDATE ${sql.identifier(mainTable)} SET _status = ${status} WHERE id = ${doc.id} ` }); } payload.logger.info({ msg: `Restored _status for ${documents.rows.length} documents` }); } } payload.logger.info({ msg: 'Rollback completed successfully' }); } //# sourceMappingURL=down.js.map