[Flexible Schema] Create indexes for join columns (#6165)
## Context
We want to add an index on our foreign keys since PG does not do it for
us. An index can sometimes be expensive and not always meaningful
depending on different usages but in our case we decided to apply an
index for every foreign keys.
```typescript
@WorkspaceIndex()
@WorkspaceJoinColumn('author')
authorId: string;
```
This syntax is valid but since we want to apply it to every join column
I've decided to update the code of WorkspaceJoinColumn so it properly
registers a new index at the same time which is less error-prone.
Note: We had a bug on index name generation since postgres index names
are unique per schema and not table, the object metadata id (hashed) has
been added to the formula that generates the name of the index
## Test
Sync metadata. We have 45 join columns as of today per workspace, we
should see 45 rows inside IndexMetadata table
This commit is contained in:
@ -0,0 +1,37 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddDateColumnsToIndexMetadata1720524654925
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'AddDateColumnsToIndexMetadata1720524654925';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."indexMetadata" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."indexMetadata" ADD "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."indexFieldMetadata" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."indexFieldMetadata" ADD "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."indexFieldMetadata" DROP COLUMN "updatedAt"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."indexFieldMetadata" DROP COLUMN "createdAt"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."indexMetadata" DROP COLUMN "updatedAt"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."indexMetadata" DROP COLUMN "createdAt"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,16 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
Relation,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
|
||||
@Entity('indexFieldMetadata')
|
||||
export class IndexFieldMetadataEntity {
|
||||
@ -43,4 +45,10 @@ export class IndexFieldMetadataEntity {
|
||||
|
||||
@Column({ nullable: false })
|
||||
order: number;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
Relation,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
Relation,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-field-metadata/index-field-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
|
||||
@Entity('indexMetadata')
|
||||
export class IndexMetadataEntity {
|
||||
@ -40,4 +42,10 @@ export class IndexMetadataEntity {
|
||||
},
|
||||
)
|
||||
indexFieldMetadatas: Relation<IndexFieldMetadataEntity[]>;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { generateDeterministicIndexName } from 'src/engine/metadata-modules/index-metadata/utils/generate-deterministic-index-name';
|
||||
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
|
||||
import { convertClassNameToObjectMetadataName } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util';
|
||||
|
||||
export interface WorkspaceIndexOptions {
|
||||
columns?: string[];
|
||||
@ -16,11 +17,13 @@ export function WorkspaceIndex(
|
||||
}
|
||||
|
||||
// TODO: handle composite field metadata types
|
||||
// TODO: handle relation field metadata types
|
||||
|
||||
if (Array.isArray(columns) && columns.length > 0) {
|
||||
metadataArgsStorage.addIndexes({
|
||||
name: `IDX_${generateDeterministicIndexName(columns)}`,
|
||||
name: `IDX_${generateDeterministicIndexName([
|
||||
convertClassNameToObjectMetadataName(target.name),
|
||||
...columns,
|
||||
])}`,
|
||||
columns,
|
||||
target: target,
|
||||
});
|
||||
@ -29,7 +32,10 @@ export function WorkspaceIndex(
|
||||
}
|
||||
|
||||
metadataArgsStorage.addIndexes({
|
||||
name: `IDX_${generateDeterministicIndexName([propertyKey.toString()])}`,
|
||||
name: `IDX_${generateDeterministicIndexName([
|
||||
convertClassNameToObjectMetadataName(target.constructor.name),
|
||||
propertyKey.toString(),
|
||||
])}`,
|
||||
columns: [propertyKey.toString()],
|
||||
target: target.constructor,
|
||||
});
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { WorkspaceIndex } from 'src/engine/twenty-orm/decorators/workspace-index.decorator';
|
||||
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
|
||||
|
||||
export function WorkspaceJoinColumn(
|
||||
@ -9,5 +10,8 @@ export function WorkspaceJoinColumn(
|
||||
relationName: relationPropertyKey,
|
||||
joinColumn: propertyKey.toString(),
|
||||
});
|
||||
|
||||
// Register index for join column
|
||||
WorkspaceIndex()(object, propertyKey);
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
|
||||
import { WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||
import { PartialIndexMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-index-metadata.interface';
|
||||
import { WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||
|
||||
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
|
||||
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
|
||||
|
||||
@Injectable()
|
||||
@ -31,7 +31,7 @@ export class StandardIndexFactory {
|
||||
target: typeof BaseWorkspaceEntity,
|
||||
context: WorkspaceSyncContext,
|
||||
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
|
||||
workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||
_workspaceFeatureFlagsMap: FeatureFlagMap,
|
||||
): Partial<IndexMetadataEntity>[] {
|
||||
const workspaceEntity = metadataArgsStorage.filterEntities(target);
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/
|
||||
|
||||
export type PartialIndexMetadata = Omit<
|
||||
IndexMetadataEntity,
|
||||
'id' | 'objectMetadata' | 'indexFieldMetadatas'
|
||||
'id' | 'objectMetadata' | 'indexFieldMetadatas' | 'createdAt' | 'updatedAt'
|
||||
> & {
|
||||
columns: string[];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user