From 078d8020863470c82f107dd29b20ff39db53d468 Mon Sep 17 00:00:00 2001 From: Francisco Gaona Date: Sat, 31 Jan 2026 03:01:41 +0100 Subject: [PATCH] WIP - Fix migration for config list views --- ...1000001_add_layout_type_to_page_layouts.js | 92 ++++++++++++++++--- 1 file changed, 81 insertions(+), 11 deletions(-) diff --git a/backend/migrations/tenant/20250131000001_add_layout_type_to_page_layouts.js b/backend/migrations/tenant/20250131000001_add_layout_type_to_page_layouts.js index 921da3b..4ae3db3 100644 --- a/backend/migrations/tenant/20250131000001_add_layout_type_to_page_layouts.js +++ b/backend/migrations/tenant/20250131000001_add_layout_type_to_page_layouts.js @@ -2,24 +2,94 @@ * @param { import("knex").Knex } knex * @returns { Promise } */ -exports.up = function(knex) { - return knex.schema.alterTable('page_layouts', (table) => { - // Add layout_type column to distinguish between detail/edit layouts and list view layouts - // Default to 'detail' for existing layouts - table.enum('layout_type', ['detail', 'list']).notNullable().defaultTo('detail').after('name'); - - // Update the unique index to include layout_type so we can have both a default detail and default list layout - table.dropIndex(['object_id', 'is_default']); - }); +exports.up = async function(knex) { + // Check if layout_type column already exists (in case of partial migration) + const hasLayoutType = await knex.schema.hasColumn('page_layouts', 'layout_type'); + + // Check if the old index exists + const [indexes] = await knex.raw(`SHOW INDEX FROM page_layouts WHERE Key_name = 'page_layouts_object_id_is_default_index'`); + const hasOldIndex = indexes.length > 0; + + // Check if foreign key exists + const [fks] = await knex.raw(` + SELECT CONSTRAINT_NAME FROM information_schema.TABLE_CONSTRAINTS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'page_layouts' + AND CONSTRAINT_TYPE = 'FOREIGN KEY' + AND CONSTRAINT_NAME = 'page_layouts_object_id_foreign' + `); + const hasForeignKey = fks.length > 0; + + if (hasOldIndex) { + // First, drop the foreign key constraint that depends on the index (if it exists) + if (hasForeignKey) { + await knex.schema.alterTable('page_layouts', (table) => { + table.dropForeign(['object_id']); + }); + } + + // Now we can safely drop the old index + await knex.schema.alterTable('page_layouts', (table) => { + table.dropIndex(['object_id', 'is_default']); + }); + } + + // Add layout_type column if it doesn't exist + if (!hasLayoutType) { + await knex.schema.alterTable('page_layouts', (table) => { + // Add layout_type column to distinguish between detail/edit layouts and list view layouts + // Default to 'detail' for existing layouts + table.enum('layout_type', ['detail', 'list']).notNullable().defaultTo('detail').after('name'); + }); + } + + // Check if new index exists + const [newIndexes] = await knex.raw(`SHOW INDEX FROM page_layouts WHERE Key_name = 'page_layouts_object_id_layout_type_is_default_index'`); + const hasNewIndex = newIndexes.length > 0; + + if (!hasNewIndex) { + // Create new index including layout_type + await knex.schema.alterTable('page_layouts', (table) => { + table.index(['object_id', 'layout_type', 'is_default']); + }); + } + + // Re-check if foreign key exists (may have been dropped above or in previous attempt) + const [fksAfter] = await knex.raw(` + SELECT CONSTRAINT_NAME FROM information_schema.TABLE_CONSTRAINTS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'page_layouts' + AND CONSTRAINT_TYPE = 'FOREIGN KEY' + AND CONSTRAINT_NAME = 'page_layouts_object_id_foreign' + `); + + if (fksAfter.length === 0) { + // Re-add the foreign key constraint + await knex.schema.alterTable('page_layouts', (table) => { + table.foreign('object_id').references('id').inTable('object_definitions').onDelete('CASCADE'); + }); + } }; /** * @param { import("knex").Knex } knex * @returns { Promise } */ -exports.down = function(knex) { - return knex.schema.alterTable('page_layouts', (table) => { +exports.down = async function(knex) { + // Drop the foreign key first + await knex.schema.alterTable('page_layouts', (table) => { + table.dropForeign(['object_id']); + }); + + // Drop the new index and column, restore old index + await knex.schema.alterTable('page_layouts', (table) => { + table.dropIndex(['object_id', 'layout_type', 'is_default']); table.dropColumn('layout_type'); table.index(['object_id', 'is_default']); }); + + // Re-add the foreign key constraint + await knex.schema.alterTable('page_layouts', (table) => { + table.foreign('object_id').references('id').inTable('object_definitions').onDelete('CASCADE'); + }); };