diff --git a/packages/core/admin/ee/server/bootstrap.js b/packages/core/admin/ee/server/bootstrap.js index 7032a2b3ef..678ce883e9 100644 --- a/packages/core/admin/ee/server/bootstrap.js +++ b/packages/core/admin/ee/server/bootstrap.js @@ -5,7 +5,7 @@ const { features } = require('@strapi/strapi/lib/utils/ee'); const executeCEBootstrap = require('../../server/bootstrap'); const { getService } = require('../../server/utils'); const actions = require('./config/admin-actions'); -const { persistTablesWithPrefix, persistTablesWithSuffix } = require('./utils/persisted-tables'); +const { persistTablesWithPrefix } = require('./utils/persisted-tables'); module.exports = async () => { const { actionProvider } = getService('permission'); @@ -22,7 +22,6 @@ module.exports = async () => { if (features.isEnabled('review-workflows')) { await persistTablesWithPrefix('strapi_workflows'); - await persistTablesWithSuffix('_strapi_review_workflows_stage_links'); const { bootstrap: rwBootstrap } = getService('review-workflows'); diff --git a/packages/core/admin/ee/server/services/review-workflows/review-workflows.js b/packages/core/admin/ee/server/services/review-workflows/review-workflows.js index 7001a98ec0..6cb5aa6ee2 100644 --- a/packages/core/admin/ee/server/services/review-workflows/review-workflows.js +++ b/packages/core/admin/ee/server/services/review-workflows/review-workflows.js @@ -10,6 +10,7 @@ const defaultWorkflow = require('../../constants/default-workflow.json'); const { ENTITY_STAGE_ATTRIBUTE } = require('../../constants/workflows'); const { getDefaultWorkflow } = require('../../utils/review-workflows'); +const { persistTable, removePersistedTablesWithSuffix } = require('../../utils/persisted-tables'); async function initDefaultWorkflow({ workflowsService, stagesService, strapi }) { const wfCount = await workflowsService.count(); @@ -73,12 +74,20 @@ function enableReviewWorkflow({ strapi }) { const stagesService = getService('stages', { strapi }); const up = async (contentTypeUID) => { + // Persist the stage join table + const { attributes, tableName } = strapi.db.metadata.get(contentTypeUID); + const joinTableName = attributes[ENTITY_STAGE_ATTRIBUTE].joinTable.name; + await persistTable(joinTableName, [tableName]); + + // Update CT entities stage return stagesService.updateEntitiesStage(contentTypeUID, { fromStageId: null, toStageId: firstStage.id, }); }; + await removePersistedTablesWithSuffix('_strapi_review_workflows_stage_links'); + return pipe([ getContentTypeUIDsWithActivatedReviewWorkflows, // Iterate over UIDs to extend the content-type diff --git a/packages/core/admin/ee/server/utils/persisted-tables.js b/packages/core/admin/ee/server/utils/persisted-tables.js index bff71a881b..698350ab9c 100644 --- a/packages/core/admin/ee/server/utils/persisted-tables.js +++ b/packages/core/admin/ee/server/utils/persisted-tables.js @@ -1,5 +1,19 @@ 'use strict'; +const { differenceWith, isEqual } = require('lodash/fp'); + +/** + * Transform table name to the object format + * @param {Array }>} table + * @returns Array<{ table: string; dependsOn?: Array<{ table: string;}> }> + */ +const transformTableName = (table) => { + if (typeof table === 'string') { + return { name: table }; + } + return table; +}; + /** * Finds all tables in the database matching the regular expression * @param {Object} ctx @@ -16,22 +30,59 @@ async function findTables({ strapi }, regex) { * Add tables name to the reserved tables in core store * @param {Object} ctx * @param {Strapi} ctx.strapi - * @param {string[]} tableNames + * @param {Array }>} tableNames * @return {Promise} */ async function addPersistTables({ strapi }, tableNames) { const persistedTables = await getPersistedTables({ strapi }); - const notReservedTableNames = tableNames.filter((name) => !persistedTables.includes(name)); + const tables = tableNames.map(transformTableName); - if (!notReservedTableNames.length) { + // Get new tables to be persisted, remove tables if they already were persisted + const notPersistedTableNames = differenceWith(isEqual, tables, persistedTables); + // Remove tables that are going to be changed + const tablesToPersist = differenceWith( + (t1, t2) => t1.name === t2.name, + persistedTables, + notPersistedTableNames + ); + + if (!notPersistedTableNames.length) { return; } - persistedTables.push(...notReservedTableNames); + tablesToPersist.push(...notPersistedTableNames); await strapi.store.set({ type: 'core', key: 'persisted_tables', - value: persistedTables, + value: tablesToPersist, + }); +} + +/** + * Remove tables name from the reserved tables in core store + * @param {Object} ctx + * @param {Strapi} ctx.strapi + * @param {Array} tableNames + * @return {Promise} + */ +async function removePersistedTables({ strapi }, tableNames) { + const persistedTables = await getPersistedTables({ strapi }); + + // Get new tables to be persisted, remove tables if they already were persisted + const newPersistedTables = differenceWith( + (t1, t2) => t1.name === t2, + persistedTables, + tableNames + ); + + if (newPersistedTables.length === persistedTables.length) { + return; + } + + await strapi.store.set({ + type: 'core', + key: 'persisted_tables', + value: newPersistedTables, }); } @@ -41,11 +92,15 @@ async function addPersistTables({ strapi }, tableNames) { * @param {Strapi} ctx.strapi * @returns {Promise} */ -const getPersistedTables = async ({ strapi }) => - (await strapi.store.get({ + +async function getPersistedTables({ strapi }) { + const persistedTables = await strapi.store.get({ type: 'core', key: 'persisted_tables', - })) ?? []; + }); + + return (persistedTables || []).map(transformTableName); +} /** * Add all table names that start with a prefix to the reserved tables in @@ -62,19 +117,25 @@ const persistTablesWithPrefix = async (tableNamePrefix) => { }; /** - * Add all table names that end with a suffix to the reserved tables in core store + * Remove all table names that end with a suffix from the reserved tables in core store * @param {string} tableNameSuffix * @return {Promise} */ -const persistTablesWithSuffix = async (tableNameSuffix) => { +const removePersistedTablesWithSuffix = async (tableNameSuffix) => { const tableNameRegex = new RegExp(`.*${tableNameSuffix}$`); const tableNames = await findTables({ strapi }, tableNameRegex); + await removePersistedTables({ strapi }, tableNames); +}; - await addPersistTables({ strapi }, tableNames); +const persistTable = async (tableName, dependsOn) => { + await addPersistTables({ strapi }, [ + { name: tableName, dependsOn: dependsOn?.map((depTableName) => ({ name: depTableName })) }, + ]); }; module.exports = { persistTablesWithPrefix, - persistTablesWithSuffix, + removePersistedTablesWithSuffix, + persistTable, findTables, }; diff --git a/packages/core/database/lib/schema/diff.js b/packages/core/database/lib/schema/diff.js index 96f7018621..ef3aaaa679 100644 --- a/packages/core/database/lib/schema/diff.js +++ b/packages/core/database/lib/schema/diff.js @@ -344,6 +344,13 @@ module.exports = (db) => { } } + const parsePersistedTable = (persistedTable) => { + if (typeof persistedTable === 'string') { + return persistedTable; + } + return persistedTable.name; + }; + const persistedTables = helpers.hasTable(srcSchema, 'strapi_core_store_settings') ? (await strapi.store.get({ type: 'core', @@ -351,12 +358,19 @@ module.exports = (db) => { })) ?? [] : []; + const reservedTables = [...RESERVED_TABLE_NAMES, ...persistedTables.map(parsePersistedTable)]; + for (const srcTable of srcSchema.tables) { - if ( - !helpers.hasTable(destSchema, srcTable.name) && - ![...RESERVED_TABLE_NAMES, ...persistedTables].includes(srcTable.name) - ) { - removedTables.push(srcTable); + if (!helpers.hasTable(destSchema, srcTable.name) && !reservedTables.includes(srcTable.name)) { + const dependencies = persistedTables + .filter((table) => { + return table?.dependsOn?.some((table) => table.name === srcTable.name); + }) + .map((dependsOnTable) => { + return srcSchema.tables.find((srcTable) => srcTable.name === dependsOnTable.name); + }); + + removedTables.push(srcTable, ...dependencies); } }