diff --git a/packages/@n8n/db/src/migrations/common/1765886667897-AddAgentIdForeignKeys.ts b/packages/@n8n/db/src/migrations/common/1765886667897-AddAgentIdForeignKeys.ts new file mode 100644 index 0000000000000..77a4483de71c0 --- /dev/null +++ b/packages/@n8n/db/src/migrations/common/1765886667897-AddAgentIdForeignKeys.ts @@ -0,0 +1,52 @@ +import type { MigrationContext, ReversibleMigration } from '../migration-types'; + +const table = { + agents: 'chat_hub_agents', + sessions: 'chat_hub_sessions', + messages: 'chat_hub_messages', +} as const; + +export class AddAgentIdForeignKeys1765886667897 implements ReversibleMigration { + async up({ schemaBuilder: { addForeignKey }, runQuery, escape }: MigrationContext) { + const escapedAgentIdColumn = escape.columnName('agentId'); + + // Clean up orphaned agentId references before adding foreign key constraint + await runQuery( + `UPDATE ${escape.tableName(table.sessions)} SET ${escapedAgentIdColumn} = NULL WHERE ${escapedAgentIdColumn} IS NOT NULL AND ${escapedAgentIdColumn} NOT IN (SELECT id FROM ${escape.tableName(table.agents)})`, + ); + await runQuery( + `UPDATE ${escape.tableName(table.messages)} SET ${escapedAgentIdColumn} = NULL WHERE ${escapedAgentIdColumn} IS NOT NULL AND ${escapedAgentIdColumn} NOT IN (SELECT id FROM ${escape.tableName(table.agents)})`, + ); + + // Add foreign key constraint for agentId in sessions table + await addForeignKey( + table.sessions, + 'agentId', + [table.agents, 'id'], + 'FK_chat_hub_sessions_agentId', + 'SET NULL', + ); + await addForeignKey( + table.messages, + 'agentId', + [table.agents, 'id'], + 'FK_chat_hub_messages_agentId', + 'SET NULL', + ); + } + + async down({ schemaBuilder: { dropForeignKey } }: MigrationContext) { + await dropForeignKey( + table.messages, + 'agentId', + [table.agents, 'id'], + 'FK_chat_hub_messages_agentId', + ); + await dropForeignKey( + table.sessions, + 'agentId', + [table.agents, 'id'], + 'FK_chat_hub_sessions_agentId', + ); + } +} diff --git a/packages/@n8n/db/src/migrations/mysqldb/index.ts b/packages/@n8n/db/src/migrations/mysqldb/index.ts index 92ce829841a47..a4892c7a4c613 100644 --- a/packages/@n8n/db/src/migrations/mysqldb/index.ts +++ b/packages/@n8n/db/src/migrations/mysqldb/index.ts @@ -126,6 +126,7 @@ import { AddDynamicCredentialEntryTable1764689388394 } from '../common/176468938 import { BackfillMissingWorkflowHistoryRecords1765448186933 } from '../common/1765448186933-BackfillMissingWorkflowHistoryRecords'; import { AddResolvableFieldsToCredentials1765459448000 } from '../common/1765459448000-AddResolvableFieldsToCredentials'; import { AddIconToAgentTable1765788427674 } from '../common/1765788427674-AddIconToAgentTable'; +import { AddAgentIdForeignKeys1765886667897 } from '../common/1765886667897-AddAgentIdForeignKeys'; import type { Migration } from '../migration-types'; export const mysqlMigrations: Migration[] = [ @@ -257,4 +258,5 @@ export const mysqlMigrations: Migration[] = [ BackfillMissingWorkflowHistoryRecords1765448186933, AddResolvableFieldsToCredentials1765459448000, AddIconToAgentTable1765788427674, + AddAgentIdForeignKeys1765886667897, ]; diff --git a/packages/@n8n/db/src/migrations/postgresdb/index.ts b/packages/@n8n/db/src/migrations/postgresdb/index.ts index ebca1b497f788..8d811e1cca7cf 100644 --- a/packages/@n8n/db/src/migrations/postgresdb/index.ts +++ b/packages/@n8n/db/src/migrations/postgresdb/index.ts @@ -127,6 +127,7 @@ import { AddDynamicCredentialEntryTable1764689388394 } from '../common/176468938 import { BackfillMissingWorkflowHistoryRecords1765448186933 } from '../common/1765448186933-BackfillMissingWorkflowHistoryRecords'; import { AddResolvableFieldsToCredentials1765459448000 } from '../common/1765459448000-AddResolvableFieldsToCredentials'; import { AddIconToAgentTable1765788427674 } from '../common/1765788427674-AddIconToAgentTable'; +import { AddAgentIdForeignKeys1765886667897 } from '../common/1765886667897-AddAgentIdForeignKeys'; import type { Migration } from '../migration-types'; export const postgresMigrations: Migration[] = [ @@ -259,4 +260,5 @@ export const postgresMigrations: Migration[] = [ AddResolvableFieldsToCredentials1765459448000, AddIconToAgentTable1765788427674, ConvertAgentIdToUuid1765804780000, + AddAgentIdForeignKeys1765886667897, ]; diff --git a/packages/@n8n/db/src/migrations/sqlite/1765886667897-AddAgentIdForeignKeys.ts b/packages/@n8n/db/src/migrations/sqlite/1765886667897-AddAgentIdForeignKeys.ts new file mode 100644 index 0000000000000..d0dd16ca94ca0 --- /dev/null +++ b/packages/@n8n/db/src/migrations/sqlite/1765886667897-AddAgentIdForeignKeys.ts @@ -0,0 +1,5 @@ +import { AddAgentIdForeignKeys1765886667897 as BaseMigration } from '../common/1765886667897-AddAgentIdForeignKeys'; + +export class AddAgentIdForeignKeys1765886667897 extends BaseMigration { + transaction = false as const; +} diff --git a/packages/@n8n/db/src/migrations/sqlite/index.ts b/packages/@n8n/db/src/migrations/sqlite/index.ts index 226599dda03f0..2e4a6383c2b25 100644 --- a/packages/@n8n/db/src/migrations/sqlite/index.ts +++ b/packages/@n8n/db/src/migrations/sqlite/index.ts @@ -48,6 +48,7 @@ import { AddWorkflowVersionColumn1761047826451 } from './1761047826451-AddWorkfl import { ChangeDependencyInfoToJson1761655473000 } from './1761655473000-ChangeDependencyInfoToJson'; import { AddCreatorIdToProjectTable1764276827837 } from './1764276827837-AddCreatorIdToProjectTable'; import { AddResolvableFieldsToCredentials1764689448000 } from './1764689448000-AddResolvableFieldsToCredentials'; +import { AddAgentIdForeignKeys1765886667897 } from './1765886667897-AddAgentIdForeignKeys'; import { UniqueWorkflowNames1620821879465 } from '../common/1620821879465-UniqueWorkflowNames'; import { UpdateWorkflowCredentials1630330987096 } from '../common/1630330987096-UpdateWorkflowCredentials'; import { AddNodeIds1658930531669 } from '../common/1658930531669-AddNodeIds'; @@ -249,6 +250,7 @@ const sqliteMigrations: Migration[] = [ BackfillMissingWorkflowHistoryRecords1765448186933, AddResolvableFieldsToCredentials1764689448000, AddIconToAgentTable1765788427674, + AddAgentIdForeignKeys1765886667897, ]; export { sqliteMigrations };