Improve performance on metadata computation (#12785)
In this PR: ## Improve recompute metadata cache performance. We are aiming for ~100ms Deleting relationMetadata table and FKs pointing on it Fetching indexMetadata and indexFieldMetadata in a separate query as typeorm is suboptimizing ## Remove caching lock As recomputing the metadata cache is lighter, we try to stop preventing multiple concurrent computations. This also simplifies interfaces ## Introduce self recovery mecanisms to recompute cache automatically if corrupted Aka getFreshObjectMetadataMaps ## custom object resolver performance improvement: 1sec to 200ms Double check queries and indexes used while creating a custom object Remove the queries to db to use the cached objectMetadataMap ## reduce objectMetadataMaps to 500kb <img width="222" alt="image" src="https://github.com/user-attachments/assets/2370dc80-49b6-4b63-8d5e-30c5ebdaa062" /> We used to stored 3 fieldMetadataMaps (byId, byName, byJoinColumnName). While this is great for devXP, this is not great for performances. Using the same mecanisme as for objectMetadataMap: we only keep byIdMap and introduce two otherMaps to idByName, idByJoinColumnName to make the bridge ## Add dataloader on IndexMetadata (aka indexMetadataList in the API) ## Improve field resolver performances too ## Deprecate ClientConfig
This commit is contained in:
@ -153,6 +153,7 @@ export class StandardFieldFactory {
|
||||
isActive: workspaceFieldMetadataArgs.isActive ?? true,
|
||||
asExpression: workspaceFieldMetadataArgs.asExpression,
|
||||
generatedType: workspaceFieldMetadataArgs.generatedType,
|
||||
isLabelSyncedWithName: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
@ -191,6 +192,7 @@ export class StandardFieldFactory {
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
isActive: workspaceRelationMetadataArgs.isActive ?? true,
|
||||
isLabelSyncedWithName: true,
|
||||
});
|
||||
|
||||
return fieldMetadataCollection;
|
||||
|
||||
@ -3,7 +3,10 @@ import { Injectable, Logger } from '@nestjs/common';
|
||||
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 { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import {
|
||||
IndexMetadataEntity,
|
||||
IndexType,
|
||||
} from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import { generateDeterministicIndexName } from 'src/engine/metadata-modules/index-metadata/utils/generate-deterministic-index-name';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
|
||||
@ -88,7 +91,7 @@ export class StandardIndexFactory {
|
||||
isUnique: workspaceIndexMetadataArgs.isUnique,
|
||||
isCustom: false,
|
||||
indexWhereClause: workspaceIndexMetadataArgs.whereClause,
|
||||
indexType: workspaceIndexMetadataArgs.type,
|
||||
indexType: workspaceIndexMetadataArgs.type ?? IndexType.BTREE,
|
||||
};
|
||||
|
||||
return indexMetadata;
|
||||
@ -129,7 +132,7 @@ export class StandardIndexFactory {
|
||||
columns: workspaceIndexMetadataArgs.columns,
|
||||
isCustom: false,
|
||||
isUnique: workspaceIndexMetadataArgs.isUnique,
|
||||
indexType: workspaceIndexMetadataArgs.type,
|
||||
indexType: workspaceIndexMetadataArgs.type ?? IndexType.BTREE,
|
||||
indexWhereClause: workspaceIndexMetadataArgs.whereClause,
|
||||
};
|
||||
|
||||
|
||||
@ -21,7 +21,9 @@ export class StandardObjectFactory {
|
||||
private createObjectMetadata(
|
||||
target: typeof BaseWorkspaceEntity,
|
||||
context: WorkspaceSyncContext,
|
||||
): Omit<PartialWorkspaceEntity, 'fields' | 'indexMetadatas'> | undefined {
|
||||
):
|
||||
| Omit<PartialWorkspaceEntity, 'fields' | 'indexMetadatas' | 'icon'>
|
||||
| undefined {
|
||||
const workspaceEntityMetadataArgs =
|
||||
metadataArgsStorage.filterEntities(target);
|
||||
|
||||
|
||||
@ -9,7 +9,12 @@ export type PartialFieldMetadata<
|
||||
T extends FieldMetadataType = FieldMetadataType,
|
||||
> = Omit<
|
||||
FieldMetadataInterface<T>,
|
||||
'id' | 'label' | 'description' | 'objectMetadataId'
|
||||
| 'id'
|
||||
| 'label'
|
||||
| 'description'
|
||||
| 'objectMetadataId'
|
||||
| 'createdAt'
|
||||
| 'updatedAt'
|
||||
> & {
|
||||
standardId: string;
|
||||
label: string | ((objectMetadata: ObjectMetadataEntity) => string);
|
||||
|
||||
@ -16,8 +16,11 @@ export const computeStandardFields = (
|
||||
)[],
|
||||
originalObjectMetadata: ObjectMetadataEntity,
|
||||
customObjectMetadataCollection: ObjectMetadataEntity[] = [],
|
||||
): ComputedPartialFieldMetadata[] => {
|
||||
const fields: ComputedPartialFieldMetadata[] = [];
|
||||
): Omit<ComputedPartialFieldMetadata, 'createdAt' | 'updatedAt'>[] => {
|
||||
const fields: Omit<
|
||||
ComputedPartialFieldMetadata,
|
||||
'createdAt' | 'updatedAt'
|
||||
>[] = [];
|
||||
|
||||
for (const partialFieldMetadata of standardFieldMetadataCollection) {
|
||||
// Relation from standard object to custom object
|
||||
@ -43,6 +46,8 @@ export const computeStandardFields = (
|
||||
...rest,
|
||||
standardId: relationStandardId,
|
||||
defaultValue: null,
|
||||
isNullable: true,
|
||||
isLabelSyncedWithName: true,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user