From 7de52d2bbbb0da2383b357b79e086e89191ecf1f Mon Sep 17 00:00:00 2001 From: Whiznificent Date: Sat, 29 Aug 2026 12:56:28 +0000 Subject: [PATCH 1/2] feat: add database indexes to automation-action entity (#1232) Add @Index decorators to AutomationAction entity for commonly queried columns: - workflowId (single): speeds up foreign key lookups / CASCADE deletes - type (single): speeds up filtering actions by type - order (single): speeds up ORDER BY order queries - deletedAt (single): speeds up soft-delete aware queries - workflowId + order (composite): optimised ordered action fetch per workflow - workflowId + type (composite): optimised type-filter per workflow Add migration 1800000000001-add-automation-action-indexes.ts with idempotent CREATE INDEX IF NOT EXISTS / DROP INDEX IF EXISTS statements. Closes #1232 --- .../entities/automation-action.entity.ts | 7 +++ ...000000001-add-automation-action-indexes.ts | 45 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/migrations/1800000000001-add-automation-action-indexes.ts diff --git a/src/email-marketing/entities/automation-action.entity.ts b/src/email-marketing/entities/automation-action.entity.ts index e50a2841..11ef3a97 100644 --- a/src/email-marketing/entities/automation-action.entity.ts +++ b/src/email-marketing/entities/automation-action.entity.ts @@ -6,6 +6,7 @@ import { JoinColumn, DeleteDateColumn, VersionColumn, + Index, } from 'typeorm'; import { ApiProperty } from '@nestjs/swagger'; import { AutomationWorkflow } from './automation-workflow.entity'; @@ -15,6 +16,8 @@ import { ActionType } from '../enums/action-type.enum'; * Represents the automation Action entity. */ @Entity('automation_actions') +@Index('IDX_automation_actions_workflowId_order', ['workflowId', 'order']) +@Index('IDX_automation_actions_workflowId_type', ['workflowId', 'type']) export class AutomationAction { @ApiProperty() @PrimaryGeneratedColumn('uuid') @@ -24,6 +27,7 @@ export class AutomationAction { version: number; @ApiProperty() + @Index('IDX_automation_actions_workflowId') @Column() workflowId: string; @@ -32,6 +36,7 @@ export class AutomationAction { workflow: AutomationWorkflow; @ApiProperty({ enum: ActionType }) + @Index('IDX_automation_actions_type') @Column({ type: 'enum', enum: ActionType }) type: ActionType; @@ -40,6 +45,7 @@ export class AutomationAction { config: Record; @ApiProperty() + @Index('IDX_automation_actions_order') @Column({ default: 0 }) order: number; @@ -47,6 +53,7 @@ export class AutomationAction { @Column({ type: 'text', nullable: true }) description?: string; + @Index('IDX_automation_actions_deletedAt') @DeleteDateColumn() deletedAt?: Date; } diff --git a/src/migrations/1800000000001-add-automation-action-indexes.ts b/src/migrations/1800000000001-add-automation-action-indexes.ts new file mode 100644 index 00000000..0612b1b9 --- /dev/null +++ b/src/migrations/1800000000001-add-automation-action-indexes.ts @@ -0,0 +1,45 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddAutomationActionIndexes1800000000001 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE INDEX IF NOT EXISTS "IDX_automation_actions_workflowId" ON "automation_actions" ("workflowId")', + ); + await queryRunner.query( + 'CREATE INDEX IF NOT EXISTS "IDX_automation_actions_type" ON "automation_actions" ("type")', + ); + await queryRunner.query( + 'CREATE INDEX IF NOT EXISTS "IDX_automation_actions_order" ON "automation_actions" ("order")', + ); + await queryRunner.query( + 'CREATE INDEX IF NOT EXISTS "IDX_automation_actions_deletedAt" ON "automation_actions" ("deletedAt")', + ); + await queryRunner.query( + 'CREATE INDEX IF NOT EXISTS "IDX_automation_actions_workflowId_order" ON "automation_actions" ("workflowId", "order")', + ); + await queryRunner.query( + 'CREATE INDEX IF NOT EXISTS "IDX_automation_actions_workflowId_type" ON "automation_actions" ("workflowId", "type")', + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'DROP INDEX IF EXISTS "IDX_automation_actions_workflowId_type"', + ); + await queryRunner.query( + 'DROP INDEX IF EXISTS "IDX_automation_actions_workflowId_order"', + ); + await queryRunner.query( + 'DROP INDEX IF EXISTS "IDX_automation_actions_deletedAt"', + ); + await queryRunner.query( + 'DROP INDEX IF EXISTS "IDX_automation_actions_order"', + ); + await queryRunner.query( + 'DROP INDEX IF EXISTS "IDX_automation_actions_type"', + ); + await queryRunner.query( + 'DROP INDEX IF EXISTS "IDX_automation_actions_workflowId"', + ); + } +} From 0a847af3ebf56072a76f467847295ed9afc003de Mon Sep 17 00:00:00 2001 From: Whiznificent Date: Tue, 1 Sep 2026 09:49:34 +0000 Subject: [PATCH 2/2] chore(migrations): fix prettier formatting in automation action indexes migration --- ...000000001-add-automation-action-indexes.ts | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/migrations/1800000000001-add-automation-action-indexes.ts b/src/migrations/1800000000001-add-automation-action-indexes.ts index 0612b1b9..123fcf1d 100644 --- a/src/migrations/1800000000001-add-automation-action-indexes.ts +++ b/src/migrations/1800000000001-add-automation-action-indexes.ts @@ -23,23 +23,11 @@ export class AddAutomationActionIndexes1800000000001 implements MigrationInterfa } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'DROP INDEX IF EXISTS "IDX_automation_actions_workflowId_type"', - ); - await queryRunner.query( - 'DROP INDEX IF EXISTS "IDX_automation_actions_workflowId_order"', - ); - await queryRunner.query( - 'DROP INDEX IF EXISTS "IDX_automation_actions_deletedAt"', - ); - await queryRunner.query( - 'DROP INDEX IF EXISTS "IDX_automation_actions_order"', - ); - await queryRunner.query( - 'DROP INDEX IF EXISTS "IDX_automation_actions_type"', - ); - await queryRunner.query( - 'DROP INDEX IF EXISTS "IDX_automation_actions_workflowId"', - ); + await queryRunner.query('DROP INDEX IF EXISTS "IDX_automation_actions_workflowId_type"'); + await queryRunner.query('DROP INDEX IF EXISTS "IDX_automation_actions_workflowId_order"'); + await queryRunner.query('DROP INDEX IF EXISTS "IDX_automation_actions_deletedAt"'); + await queryRunner.query('DROP INDEX IF EXISTS "IDX_automation_actions_order"'); + await queryRunner.query('DROP INDEX IF EXISTS "IDX_automation_actions_type"'); + await queryRunner.query('DROP INDEX IF EXISTS "IDX_automation_actions_workflowId"'); } }