From 1ef7b7a474b8c8d1aaddfb1e8e11d4f825e7adca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Mon, 2 Jun 2025 09:55:45 +0200 Subject: [PATCH] Add indices on frequent queries (#12401) Fixes #12165 Also changed the index naming convention because some were not properly name and would have caused conflicts in the long run --- ...add-user-workspace-role-composite-index.ts | 19 ++ ...tadata-workspace-object-composite-index.ts | 19 ++ .../1748844710107-addSoftDeleteIndexes.ts | 35 ++++ .../1748846032709-fixMetadataIndexes.ts | 169 ++++++++++++++++++ .../common/1748846118238-fixCoreIndexes.ts | 71 ++++++++ .../common/1748849487789-fixCoreIndexes2.ts | 23 +++ .../approved-access-domain.entity.ts | 7 +- .../entities/billing-entitlement.entity.ts | 5 +- .../billing-subscription-item.entity.ts | 8 +- .../entities/billing-subscription.entity.ts | 2 +- .../feature-flag/feature-flag.entity.ts | 2 +- .../key-value-pair/key-value-pair.entity.ts | 30 +++- .../user-workspace/user-workspace.entity.ts | 9 +- .../engine/core-modules/user/user.entity.ts | 1 + .../workspace/workspace.entity.ts | 2 + .../field-metadata/field-metadata.entity.ts | 14 +- .../index-field-metadata.entity.ts | 2 +- .../index-metadata/index-metadata.entity.ts | 7 +- .../object-metadata/object-metadata.entity.ts | 7 +- .../object-permission.entity.ts | 5 +- .../metadata-modules/role/role.entity.ts | 2 +- .../role/user-workspace-role.entity.ts | 10 +- .../setting-permission.entity.ts | 2 +- 23 files changed, 419 insertions(+), 32 deletions(-) create mode 100644 packages/twenty-server/src/database/typeorm/core/migrations/common/1748843737248-add-user-workspace-role-composite-index.ts create mode 100644 packages/twenty-server/src/database/typeorm/core/migrations/common/1748843862307-add-index-metadata-workspace-object-composite-index.ts create mode 100644 packages/twenty-server/src/database/typeorm/core/migrations/common/1748844710107-addSoftDeleteIndexes.ts create mode 100644 packages/twenty-server/src/database/typeorm/core/migrations/common/1748846032709-fixMetadataIndexes.ts create mode 100644 packages/twenty-server/src/database/typeorm/core/migrations/common/1748846118238-fixCoreIndexes.ts create mode 100644 packages/twenty-server/src/database/typeorm/core/migrations/common/1748849487789-fixCoreIndexes2.ts diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/common/1748843737248-add-user-workspace-role-composite-index.ts b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748843737248-add-user-workspace-role-composite-index.ts new file mode 100644 index 000000000..c0f1039f3 --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748843737248-add-user-workspace-role-composite-index.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddUserWorkspaceRoleCompositeIndex1748843737248 + implements MigrationInterface +{ + name = 'AddUserWorkspaceRoleCompositeIndex1748843737248'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE INDEX "IDX_USER_WORKSPACE_ROLE_USER_WORKSPACE_ID_WORKSPACE_ID" ON "core"."userWorkspaceRole" ("userWorkspaceId", "workspaceId") `, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DROP INDEX "core"."IDX_USER_WORKSPACE_ROLE_USER_WORKSPACE_ID_WORKSPACE_ID"`, + ); + } +} diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/common/1748843862307-add-index-metadata-workspace-object-composite-index.ts b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748843862307-add-index-metadata-workspace-object-composite-index.ts new file mode 100644 index 000000000..adca5ebb6 --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748843862307-add-index-metadata-workspace-object-composite-index.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddIndexMetadataWorkspaceObjectCompositeIndex1748843862307 + implements MigrationInterface +{ + name = 'AddIndexMetadataWorkspaceObjectCompositeIndex1748843862307'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE INDEX "IDX_INDEX_METADATA_WORKSPACE_ID_OBJECT_METADATA_ID" ON "core"."indexMetadata" ("workspaceId", "objectMetadataId") `, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DROP INDEX "core"."IDX_INDEX_METADATA_WORKSPACE_ID_OBJECT_METADATA_ID"`, + ); + } +} diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/common/1748844710107-addSoftDeleteIndexes.ts b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748844710107-addSoftDeleteIndexes.ts new file mode 100644 index 000000000..a05ac2259 --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748844710107-addSoftDeleteIndexes.ts @@ -0,0 +1,35 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddSoftDeleteIndexes1748844710107 implements MigrationInterface { + name = 'AddSoftDeleteIndexes1748844710107'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE INDEX "IDX_USER_WORKSPACE_WORKSPACE_ID" ON "core"."userWorkspace" ("workspaceId") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_USER_WORKSPACE_USER_ID" ON "core"."userWorkspace" ("userId") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_USER_WORKSPACE_ID_DELETED_AT" ON "core"."userWorkspace" ("id", "deletedAt") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_USER_ID_DELETED_AT" ON "core"."user" ("id", "deletedAt") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_WORKSPACE_ID_DELETED_AT" ON "core"."workspace" ("id", "deletedAt") `, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "core"."IDX_WORKSPACE_ID_DELETED_AT"`); + await queryRunner.query(`DROP INDEX "core"."IDX_USER_ID_DELETED_AT"`); + await queryRunner.query( + `DROP INDEX "core"."IDX_USER_WORKSPACE_ID_DELETED_AT"`, + ); + await queryRunner.query(`DROP INDEX "core"."IDX_USER_WORKSPACE_USER_ID"`); + await queryRunner.query( + `DROP INDEX "core"."IDX_USER_WORKSPACE_WORKSPACE_ID"`, + ); + } +} diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/common/1748846032709-fixMetadataIndexes.ts b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748846032709-fixMetadataIndexes.ts new file mode 100644 index 000000000..a86dbb2f8 --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748846032709-fixMetadataIndexes.ts @@ -0,0 +1,169 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class FixMetadataIndexes1748846032709 implements MigrationInterface { + name = 'FixMetadataIndexes1748846032709'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "core"."IndexOnFieldMetadataId"`); + await queryRunner.query( + `DROP INDEX "core"."IndexOnRelationTargetObjectMetadataId"`, + ); + await queryRunner.query( + `DROP INDEX "core"."IndexOnRelationTargetFieldMetadataId"`, + ); + await queryRunner.query(`DROP INDEX "core"."IndexOnObjectMetadataId"`); + await queryRunner.query(`DROP INDEX "core"."IndexOnWorkspaceId"`); + await queryRunner.query( + `ALTER TABLE "core"."indexMetadata" DROP CONSTRAINT "IndexOnNameAndWorkspaceIdAndObjectMetadataUnique"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."fieldMetadata" DROP CONSTRAINT "IndexOnNameObjectMetadataIdAndWorkspaceIdUnique"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectMetadata" DROP CONSTRAINT "IndexOnNamePluralAndWorkspaceIdUnique"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectMetadata" DROP CONSTRAINT "IndexOnNameSingularAndWorkspaceIdUnique"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectPermission" DROP CONSTRAINT "IndexOnObjectPermissionUnique"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."userWorkspaceRole" DROP CONSTRAINT "IndexOnUserWorkspaceRoleUnique"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."role" DROP CONSTRAINT "IndexOnRoleUnique"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."settingPermission" DROP CONSTRAINT "IndexOnSettingPermissionUnique"`, + ); + + await queryRunner.query( + `CREATE INDEX "IDX_INDEX_FIELD_METADATA_FIELD_METADATA_ID" ON "core"."indexFieldMetadata" ("fieldMetadataId") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_FIELD_METADATA_OBJECT_METADATA_ID" ON "core"."fieldMetadata" ("objectMetadataId") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_FIELD_METADATA_WORKSPACE_ID" ON "core"."fieldMetadata" ("workspaceId") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_FIELD_METADATA_OBJECT_METADATA_ID_WORKSPACE_ID" ON "core"."fieldMetadata" ("objectMetadataId", "workspaceId") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_FIELD_METADATA_RELATION_TARGET_OBJECT_METADATA_ID" ON "core"."fieldMetadata" ("relationTargetObjectMetadataId") `, + ); + await queryRunner.query( + `CREATE INDEX "IDX_FIELD_METADATA_RELATION_TARGET_FIELD_METADATA_ID" ON "core"."fieldMetadata" ("relationTargetFieldMetadataId") `, + ); + await queryRunner.query( + `ALTER TABLE "core"."indexMetadata" ADD CONSTRAINT "IDX_INDEX_METADATA_NAME_WORKSPACE_ID_OBJECT_METADATA_ID_UNIQUE" UNIQUE ("name", "workspaceId", "objectMetadataId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."fieldMetadata" ADD CONSTRAINT "IDX_FIELD_METADATA_NAME_OBJECT_METADATA_ID_WORKSPACE_ID_UNIQUE" UNIQUE ("name", "objectMetadataId", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectMetadata" ADD CONSTRAINT "IDX_OBJECT_METADATA_NAME_PLURAL_WORKSPACE_ID_UNIQUE" UNIQUE ("namePlural", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectMetadata" ADD CONSTRAINT "IDX_OBJECT_METADATA_NAME_SINGULAR_WORKSPACE_ID_UNIQUE" UNIQUE ("nameSingular", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectPermission" ADD CONSTRAINT "IDX_OBJECT_PERMISSION_OBJECT_METADATA_ID_ROLE_ID_UNIQUE" UNIQUE ("objectMetadataId", "roleId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."userWorkspaceRole" ADD CONSTRAINT "IDX_USER_WORKSPACE_ROLE_USER_WORKSPACE_ID_ROLE_ID_UNIQUE" UNIQUE ("userWorkspaceId", "roleId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."role" ADD CONSTRAINT "IDX_ROLE_LABEL_WORKSPACE_ID_UNIQUE" UNIQUE ("label", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."settingPermission" ADD CONSTRAINT "IDX_SETTING_PERMISSION_SETTING_ROLE_ID_UNIQUE" UNIQUE ("setting", "roleId")`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."settingPermission" DROP CONSTRAINT "IDX_SETTING_PERMISSION_SETTING_ROLE_ID_UNIQUE"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."role" DROP CONSTRAINT "IDX_ROLE_LABEL_WORKSPACE_ID_UNIQUE"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."userWorkspaceRole" DROP CONSTRAINT "IDX_USER_WORKSPACE_ROLE_USER_WORKSPACE_ID_ROLE_ID_UNIQUE"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectPermission" DROP CONSTRAINT "IDX_OBJECT_PERMISSION_OBJECT_METADATA_ID_ROLE_ID_UNIQUE"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectMetadata" DROP CONSTRAINT "IDX_OBJECT_METADATA_NAME_SINGULAR_WORKSPACE_ID_UNIQUE"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectMetadata" DROP CONSTRAINT "IDX_OBJECT_METADATA_NAME_PLURAL_WORKSPACE_ID_UNIQUE"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."fieldMetadata" DROP CONSTRAINT "IDX_FIELD_METADATA_NAME_OBJECT_METADATA_ID_WORKSPACE_ID_UNIQUE"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."indexMetadata" DROP CONSTRAINT "IDX_INDEX_METADATA_NAME_WORKSPACE_ID_OBJECT_METADATA_ID_UNIQUE"`, + ); + await queryRunner.query( + `DROP INDEX "core"."IDX_FIELD_METADATA_RELATION_TARGET_FIELD_METADATA_ID"`, + ); + await queryRunner.query( + `DROP INDEX "core"."IDX_FIELD_METADATA_RELATION_TARGET_OBJECT_METADATA_ID"`, + ); + await queryRunner.query( + `DROP INDEX "core"."IDX_FIELD_METADATA_OBJECT_METADATA_ID_WORKSPACE_ID"`, + ); + await queryRunner.query( + `DROP INDEX "core"."IDX_FIELD_METADATA_WORKSPACE_ID"`, + ); + await queryRunner.query( + `DROP INDEX "core"."IDX_FIELD_METADATA_OBJECT_METADATA_ID"`, + ); + await queryRunner.query( + `DROP INDEX "core"."IDX_INDEX_FIELD_METADATA_FIELD_METADATA_ID"`, + ); + + await queryRunner.query( + `ALTER TABLE "core"."settingPermission" ADD CONSTRAINT "IndexOnSettingPermissionUnique" UNIQUE ("roleId", "setting")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."role" ADD CONSTRAINT "IndexOnRoleUnique" UNIQUE ("label", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."userWorkspaceRole" ADD CONSTRAINT "IndexOnUserWorkspaceRoleUnique" UNIQUE ("roleId", "userWorkspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectPermission" ADD CONSTRAINT "IndexOnObjectPermissionUnique" UNIQUE ("roleId", "objectMetadataId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectMetadata" ADD CONSTRAINT "IndexOnNameSingularAndWorkspaceIdUnique" UNIQUE ("nameSingular", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."objectMetadata" ADD CONSTRAINT "IndexOnNamePluralAndWorkspaceIdUnique" UNIQUE ("namePlural", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."fieldMetadata" ADD CONSTRAINT "IndexOnNameObjectMetadataIdAndWorkspaceIdUnique" UNIQUE ("objectMetadataId", "name", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."indexMetadata" ADD CONSTRAINT "IndexOnNameAndWorkspaceIdAndObjectMetadataUnique" UNIQUE ("name", "workspaceId", "objectMetadataId")`, + ); + await queryRunner.query( + `CREATE INDEX "IndexOnWorkspaceId" ON "core"."fieldMetadata" ("workspaceId") `, + ); + await queryRunner.query( + `CREATE INDEX "IndexOnObjectMetadataId" ON "core"."fieldMetadata" ("objectMetadataId") `, + ); + await queryRunner.query( + `CREATE INDEX "IndexOnRelationTargetFieldMetadataId" ON "core"."fieldMetadata" ("relationTargetFieldMetadataId") `, + ); + await queryRunner.query( + `CREATE INDEX "IndexOnRelationTargetObjectMetadataId" ON "core"."fieldMetadata" ("relationTargetObjectMetadataId") `, + ); + await queryRunner.query( + `CREATE INDEX "IndexOnFieldMetadataId" ON "core"."indexFieldMetadata" ("fieldMetadataId") `, + ); + } +} diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/common/1748846118238-fixCoreIndexes.ts b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748846118238-fixCoreIndexes.ts new file mode 100644 index 000000000..05c5476ff --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748846118238-fixCoreIndexes.ts @@ -0,0 +1,71 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class FixCoreIndexes1748846118238 implements MigrationInterface { + name = 'FixCoreIndexes1748846118238'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DROP INDEX "core"."IndexOnKeyUserIdAndNullWorkspaceIdUnique"`, + ); + await queryRunner.query( + `DROP INDEX "core"."IndexOnKeyWorkspaceIdAndNullUserIdUnique"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."keyValuePair" DROP CONSTRAINT "IndexOnKeyUserIdWorkspaceIdUnique"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."approvedAccessDomain" DROP CONSTRAINT "IndexOnDomainAndWorkspaceId"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."featureFlag" DROP CONSTRAINT "IndexOnKeyAndWorkspaceIdUnique"`, + ); + await queryRunner.query( + `CREATE UNIQUE INDEX "IDX_KEY_VALUE_PAIR_KEY_USER_ID_NULL_WORKSPACE_ID_UNIQUE" ON "core"."keyValuePair" ("key", "userId") WHERE "workspaceId" is NULL`, + ); + await queryRunner.query( + `CREATE UNIQUE INDEX "IDX_KEY_VALUE_PAIR_KEY_WORKSPACE_ID_NULL_USER_ID_UNIQUE" ON "core"."keyValuePair" ("key", "workspaceId") WHERE "userId" is NULL`, + ); + await queryRunner.query( + `ALTER TABLE "core"."keyValuePair" ADD CONSTRAINT "IDX_KEY_VALUE_PAIR_KEY_USER_ID_WORKSPACE_ID_UNIQUE" UNIQUE ("key", "userId", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."approvedAccessDomain" ADD CONSTRAINT "IDX_APPROVED_ACCESS_DOMAIN_DOMAIN_WORKSPACE_ID_UNIQUE" UNIQUE ("domain", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."featureFlag" ADD CONSTRAINT "IDX_FEATURE_FLAG_KEY_WORKSPACE_ID_UNIQUE" UNIQUE ("key", "workspaceId")`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."featureFlag" DROP CONSTRAINT "IDX_FEATURE_FLAG_KEY_WORKSPACE_ID_UNIQUE"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."approvedAccessDomain" DROP CONSTRAINT "IDX_APPROVED_ACCESS_DOMAIN_DOMAIN_WORKSPACE_ID_UNIQUE"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."keyValuePair" DROP CONSTRAINT "IDX_KEY_VALUE_PAIR_KEY_USER_ID_WORKSPACE_ID_UNIQUE"`, + ); + await queryRunner.query( + `DROP INDEX "core"."IDX_KEY_VALUE_PAIR_KEY_WORKSPACE_ID_NULL_USER_ID_UNIQUE"`, + ); + await queryRunner.query( + `DROP INDEX "core"."IDX_KEY_VALUE_PAIR_KEY_USER_ID_NULL_WORKSPACE_ID_UNIQUE"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."featureFlag" ADD CONSTRAINT "IndexOnKeyAndWorkspaceIdUnique" UNIQUE ("key", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."approvedAccessDomain" ADD CONSTRAINT "IndexOnDomainAndWorkspaceId" UNIQUE ("domain", "workspaceId")`, + ); + await queryRunner.query( + `ALTER TABLE "core"."keyValuePair" ADD CONSTRAINT "IndexOnKeyUserIdWorkspaceIdUnique" UNIQUE ("userId", "workspaceId", "key")`, + ); + await queryRunner.query( + `CREATE UNIQUE INDEX "IndexOnKeyWorkspaceIdAndNullUserIdUnique" ON "core"."keyValuePair" ("workspaceId", "key") WHERE ("userId" IS NULL)`, + ); + await queryRunner.query( + `CREATE UNIQUE INDEX "IndexOnKeyUserIdAndNullWorkspaceIdUnique" ON "core"."keyValuePair" ("userId", "key") WHERE ("workspaceId" IS NULL)`, + ); + } +} diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/common/1748849487789-fixCoreIndexes2.ts b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748849487789-fixCoreIndexes2.ts new file mode 100644 index 000000000..30b3f1ef8 --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/common/1748849487789-fixCoreIndexes2.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class FixCoreIndexes21748849487789 implements MigrationInterface { + name = 'FixCoreIndexes21748849487789'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."userWorkspace" DROP CONSTRAINT "IndexOnUserIdAndWorkspaceIdUnique"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."userWorkspace" ADD CONSTRAINT "IDX_USER_WORKSPACE_USER_ID_WORKSPACE_ID_UNIQUE" UNIQUE ("userId", "workspaceId")`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."userWorkspace" DROP CONSTRAINT "IDX_USER_WORKSPACE_USER_ID_WORKSPACE_ID_UNIQUE"`, + ); + await queryRunner.query( + `ALTER TABLE "core"."userWorkspace" ADD CONSTRAINT "IndexOnUserIdAndWorkspaceIdUnique" UNIQUE ("userId", "workspaceId")`, + ); + } +} diff --git a/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain.entity.ts b/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain.entity.ts index bfbab3a4b..c8d73fef2 100644 --- a/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain.entity.ts @@ -7,8 +7,8 @@ import { JoinColumn, ManyToOne, PrimaryGeneratedColumn, - UpdateDateColumn, Unique, + UpdateDateColumn, } from 'typeorm'; import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface'; @@ -17,7 +17,10 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; @Entity({ name: 'approvedAccessDomain', schema: 'core' }) @ObjectType() -@Unique('IndexOnDomainAndWorkspaceId', ['domain', 'workspaceId']) +@Unique('IDX_APPROVED_ACCESS_DOMAIN_DOMAIN_WORKSPACE_ID_UNIQUE', [ + 'domain', + 'workspaceId', +]) export class ApprovedAccessDomain { @PrimaryGeneratedColumn('uuid') id: string; diff --git a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-entitlement.entity.ts b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-entitlement.entity.ts index b093064b8..a6088873d 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-entitlement.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-entitlement.entity.ts @@ -20,7 +20,10 @@ import { BillingCustomer } from 'src/engine/core-modules/billing/entities/billin import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum'; @Entity({ name: 'billingEntitlement', schema: 'core' }) @ObjectType() -@Unique('IndexOnFeatureKeyAndWorkspaceIdUnique', ['key', 'workspaceId']) +@Unique('IDX_BILLING_ENTITLEMENT_KEY_WORKSPACE_ID_UNIQUE', [ + 'key', + 'workspaceId', +]) export class BillingEntitlement { @IDField(() => UUIDScalarType) @PrimaryGeneratedColumn('uuid') diff --git a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription-item.entity.ts b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription-item.entity.ts index 48e2c9512..fe88dc213 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription-item.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription-item.entity.ts @@ -17,10 +17,10 @@ import { BillingProduct } from 'src/engine/core-modules/billing/entities/billing import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; import { BillingSubscriptionItemMetadata } from 'src/engine/core-modules/billing/types/billing-subscription-item-metadata.type'; @Entity({ name: 'billingSubscriptionItem', schema: 'core' }) -@Unique('IndexOnBillingSubscriptionIdAndStripeProductIdUnique', [ - 'billingSubscriptionId', - 'stripeProductId', -]) +@Unique( + 'IDX_BILLING_SUBSCRIPTION_ITEM_BILLING_SUBSCRIPTION_ID_STRIPE_PRODUCT_ID_UNIQUE', + ['billingSubscriptionId', 'stripeProductId'], +) export class BillingSubscriptionItem { @PrimaryGeneratedColumn('uuid') id: string; diff --git a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts index 6dafd27f5..d5e0ce418 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/entities/billing-subscription.entity.ts @@ -29,7 +29,7 @@ registerEnumType(SubscriptionStatus, { name: 'SubscriptionStatus' }); registerEnumType(SubscriptionInterval, { name: 'SubscriptionInterval' }); @Entity({ name: 'billingSubscription', schema: 'core' }) -@Index('IndexOnActiveSubscriptionPerWorkspace', ['workspaceId'], { +@Index('IDX_BILLING_SUBSCRIPTION_WORKSPACE_ID_UNIQUE', ['workspaceId'], { unique: true, where: `status IN ('trialing', 'active', 'past_due')`, }) diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.entity.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.entity.ts index 580f81194..031d8e420 100644 --- a/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/feature-flag.entity.ts @@ -18,7 +18,7 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; @Entity({ name: 'featureFlag', schema: 'core' }) @ObjectType() -@Unique('IndexOnKeyAndWorkspaceIdUnique', ['key', 'workspaceId']) +@Unique('IDX_FEATURE_FLAG_KEY_WORKSPACE_ID_UNIQUE', ['key', 'workspaceId']) export class FeatureFlag { @IDField(() => UUIDScalarType) @PrimaryGeneratedColumn('uuid') diff --git a/packages/twenty-server/src/engine/core-modules/key-value-pair/key-value-pair.entity.ts b/packages/twenty-server/src/engine/core-modules/key-value-pair/key-value-pair.entity.ts index 805a398e6..44ca26034 100644 --- a/packages/twenty-server/src/engine/core-modules/key-value-pair/key-value-pair.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/key-value-pair/key-value-pair.entity.ts @@ -26,15 +26,27 @@ export enum KeyValuePairType { @Entity({ name: 'keyValuePair', schema: 'core' }) @ObjectType() -@Unique('IndexOnKeyUserIdWorkspaceIdUnique', ['key', 'userId', 'workspaceId']) -@Index('IndexOnKeyWorkspaceIdAndNullUserIdUnique', ['key', 'workspaceId'], { - unique: true, - where: '"userId" is NULL', -}) -@Index('IndexOnKeyUserIdAndNullWorkspaceIdUnique', ['key', 'userId'], { - unique: true, - where: '"workspaceId" is NULL', -}) +@Unique('IDX_KEY_VALUE_PAIR_KEY_USER_ID_WORKSPACE_ID_UNIQUE', [ + 'key', + 'userId', + 'workspaceId', +]) +@Index( + 'IDX_KEY_VALUE_PAIR_KEY_WORKSPACE_ID_NULL_USER_ID_UNIQUE', + ['key', 'workspaceId'], + { + unique: true, + where: '"userId" is NULL', + }, +) +@Index( + 'IDX_KEY_VALUE_PAIR_KEY_USER_ID_NULL_WORKSPACE_ID_UNIQUE', + ['key', 'userId'], + { + unique: true, + where: '"workspaceId" is NULL', + }, +) export class KeyValuePair { @IDField(() => UUIDScalarType) @PrimaryGeneratedColumn('uuid') diff --git a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts index 9be7b9882..c20d859e3 100644 --- a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts @@ -7,6 +7,7 @@ import { CreateDateColumn, DeleteDateColumn, Entity, + Index, JoinColumn, ManyToOne, OneToMany, @@ -33,7 +34,13 @@ registerEnumType(PermissionsOnAllObjectRecords, { @Entity({ name: 'userWorkspace', schema: 'core' }) @ObjectType() -@Unique('IndexOnUserIdAndWorkspaceIdUnique', ['userId', 'workspaceId']) +@Unique('IDX_USER_WORKSPACE_USER_ID_WORKSPACE_ID_UNIQUE', [ + 'userId', + 'workspaceId', +]) +@Index('IDX_USER_WORKSPACE_ID_DELETED_AT', ['id', 'deletedAt']) +@Index('IDX_USER_WORKSPACE_USER_ID', ['userId']) +@Index('IDX_USER_WORKSPACE_WORKSPACE_ID', ['workspaceId']) export class UserWorkspace { @IDField(() => UUIDScalarType) @PrimaryGeneratedColumn('uuid') diff --git a/packages/twenty-server/src/engine/core-modules/user/user.entity.ts b/packages/twenty-server/src/engine/core-modules/user/user.entity.ts index ea513286f..8eb34ad5b 100644 --- a/packages/twenty-server/src/engine/core-modules/user/user.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/user/user.entity.ts @@ -34,6 +34,7 @@ registerEnumType(OnboardingStatus, { unique: true, where: '"deletedAt" IS NULL', }) +@Index('IDX_USER_ID_DELETED_AT', ['id', 'deletedAt']) export class User { @IDField(() => UUIDScalarType) @PrimaryGeneratedColumn('uuid') diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts index 69d13f70d..bd5adfd0b 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts @@ -8,6 +8,7 @@ import { CreateDateColumn, DeleteDateColumn, Entity, + Index, OneToMany, PrimaryGeneratedColumn, Relation, @@ -34,6 +35,7 @@ registerEnumType(WorkspaceActivationStatus, { ) @Entity({ name: 'workspace', schema: 'core' }) @ObjectType() +@Index('IDX_WORKSPACE_ID_DELETED_AT', ['id', 'deletedAt']) export class Workspace { // Fields @IDField(() => UUIDScalarType) diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts index f0c4fad15..a15c4a707 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.entity.ts @@ -25,17 +25,21 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; @Entity('fieldMetadata') -@Unique('IndexOnNameObjectMetadataIdAndWorkspaceIdUnique', [ +@Unique('IDX_FIELD_METADATA_NAME_OBJECT_METADATA_ID_WORKSPACE_ID_UNIQUE', [ 'name', 'objectMetadataId', 'workspaceId', ]) -@Index('IndexOnRelationTargetFieldMetadataId', [ +@Index('IDX_FIELD_METADATA_RELATION_TARGET_FIELD_METADATA_ID', [ 'relationTargetFieldMetadataId', ]) -@Index('IndexOnRelationTargetObjectMetadataId', [ +@Index('IDX_FIELD_METADATA_RELATION_TARGET_OBJECT_METADATA_ID', [ 'relationTargetObjectMetadataId', ]) +@Index('IDX_FIELD_METADATA_OBJECT_METADATA_ID_WORKSPACE_ID', [ + 'objectMetadataId', + 'workspaceId', +]) export class FieldMetadataEntity< T extends FieldMetadataType = FieldMetadataType, > implements FieldMetadataInterface @@ -53,7 +57,7 @@ export class FieldMetadataEntity< onDelete: 'CASCADE', }) @JoinColumn({ name: 'objectMetadataId' }) - @Index('IndexOnObjectMetadataId') + @Index('IDX_FIELD_METADATA_OBJECT_METADATA_ID', ['objectMetadataId']) object: Relation; @Column({ @@ -102,7 +106,7 @@ export class FieldMetadataEntity< isUnique: boolean; @Column({ nullable: false, type: 'uuid' }) - @Index('IndexOnWorkspaceId') + @Index('IDX_FIELD_METADATA_WORKSPACE_ID', ['workspaceId']) workspaceId: string; @Column({ default: false }) diff --git a/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-field-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-field-metadata.entity.ts index 32680b645..40aa8b491 100644 --- a/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-field-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-field-metadata.entity.ts @@ -32,7 +32,7 @@ export class IndexFieldMetadataEntity { indexMetadata: Relation; @Column({ nullable: false }) - @Index('IndexOnFieldMetadataId') + @Index('IDX_INDEX_FIELD_METADATA_FIELD_METADATA_ID', ['fieldMetadataId']) fieldMetadataId: string; @ManyToOne( diff --git a/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.entity.ts index b748e2ea5..6d1f021d0 100644 --- a/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/index-metadata/index-metadata.entity.ts @@ -2,6 +2,7 @@ import { Column, CreateDateColumn, Entity, + Index, JoinColumn, ManyToOne, OneToMany, @@ -19,11 +20,15 @@ export enum IndexType { GIN = 'GIN', } -@Unique('IndexOnNameAndWorkspaceIdAndObjectMetadataUnique', [ +@Unique('IDX_INDEX_METADATA_NAME_WORKSPACE_ID_OBJECT_METADATA_ID_UNIQUE', [ 'name', 'workspaceId', 'objectMetadataId', ]) +@Index('IDX_INDEX_METADATA_WORKSPACE_ID_OBJECT_METADATA_ID', [ + 'workspaceId', + 'objectMetadataId', +]) @Entity('indexMetadata') export class IndexMetadataEntity { @PrimaryGeneratedColumn('uuid') diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts index a8e0821a9..659a194d5 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts @@ -21,11 +21,14 @@ import { ObjectPermissionEntity } from 'src/engine/metadata-modules/object-permi import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; @Entity('objectMetadata') -@Unique('IndexOnNameSingularAndWorkspaceIdUnique', [ +@Unique('IDX_OBJECT_METADATA_NAME_SINGULAR_WORKSPACE_ID_UNIQUE', [ 'nameSingular', 'workspaceId', ]) -@Unique('IndexOnNamePluralAndWorkspaceIdUnique', ['namePlural', 'workspaceId']) +@Unique('IDX_OBJECT_METADATA_NAME_PLURAL_WORKSPACE_ID_UNIQUE', [ + 'namePlural', + 'workspaceId', +]) export class ObjectMetadataEntity implements ObjectMetadataInterface { @PrimaryGeneratedColumn('uuid') id: string; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-permission/object-permission.entity.ts b/packages/twenty-server/src/engine/metadata-modules/object-permission/object-permission.entity.ts index 0c607246c..dedc42e12 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-permission/object-permission.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-permission/object-permission.entity.ts @@ -14,7 +14,10 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; @Entity('objectPermission') -@Unique('IndexOnObjectPermissionUnique', ['objectMetadataId', 'roleId']) +@Unique('IDX_OBJECT_PERMISSION_OBJECT_METADATA_ID_ROLE_ID_UNIQUE', [ + 'objectMetadataId', + 'roleId', +]) export class ObjectPermissionEntity { @PrimaryGeneratedColumn('uuid') id: string; diff --git a/packages/twenty-server/src/engine/metadata-modules/role/role.entity.ts b/packages/twenty-server/src/engine/metadata-modules/role/role.entity.ts index 4487d657c..b86338d9a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/role.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/role.entity.ts @@ -14,7 +14,7 @@ import { UserWorkspaceRoleEntity } from 'src/engine/metadata-modules/role/user-w import { SettingPermissionEntity } from 'src/engine/metadata-modules/setting-permission/setting-permission.entity'; @Entity('role') -@Unique('IndexOnRoleUnique', ['label', 'workspaceId']) +@Unique('IDX_ROLE_LABEL_WORKSPACE_ID_UNIQUE', ['label', 'workspaceId']) export class RoleEntity { @PrimaryGeneratedColumn('uuid') id: string; diff --git a/packages/twenty-server/src/engine/metadata-modules/role/user-workspace-role.entity.ts b/packages/twenty-server/src/engine/metadata-modules/role/user-workspace-role.entity.ts index 7d55984aa..3fa469f31 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/user-workspace-role.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/user-workspace-role.entity.ts @@ -2,6 +2,7 @@ import { Column, CreateDateColumn, Entity, + Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn, @@ -13,7 +14,14 @@ import { import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; @Entity('userWorkspaceRole') -@Unique('IndexOnUserWorkspaceRoleUnique', ['userWorkspaceId', 'roleId']) +@Unique('IDX_USER_WORKSPACE_ROLE_USER_WORKSPACE_ID_ROLE_ID_UNIQUE', [ + 'userWorkspaceId', + 'roleId', +]) +@Index('IDX_USER_WORKSPACE_ROLE_USER_WORKSPACE_ID_WORKSPACE_ID', [ + 'userWorkspaceId', + 'workspaceId', +]) export class UserWorkspaceRoleEntity { @PrimaryGeneratedColumn('uuid') id: string; diff --git a/packages/twenty-server/src/engine/metadata-modules/setting-permission/setting-permission.entity.ts b/packages/twenty-server/src/engine/metadata-modules/setting-permission/setting-permission.entity.ts index 264d2f4ec..dd135b77f 100644 --- a/packages/twenty-server/src/engine/metadata-modules/setting-permission/setting-permission.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/setting-permission/setting-permission.entity.ts @@ -14,7 +14,7 @@ import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/c import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; @Entity('settingPermission') -@Unique('IndexOnSettingPermissionUnique', ['setting', 'roleId']) +@Unique('IDX_SETTING_PERMISSION_SETTING_ROLE_ID_UNIQUE', ['setting', 'roleId']) export class SettingPermissionEntity { @PrimaryGeneratedColumn('uuid') id: string;