Index v2 side effects (#14567)

# Introduction
Honestly this implem is a mess, discussing a potential side effect
handler with @weiko before the build and run that would handle each side
effect per entity and operation

Handling:
- [ ] unique index is generated when a field is updated with the
`isUnique`
- [x] an index is generated when a relation is created
- [x] search vector index creation on custom object creation
- [x] renaming a field metadata or an object should re-create all
related indexes which are composed by their namings
- [x] delete object should remove any related indexes
- [x] delete field should update related indexes ( if index ends up
empty it should be removed )
- [ ] on object renaming that contains morph fields -> triggers update
field -> trigger index recompute
- [x] on update name renaming should recompute all related indexes

## TODO
- [x] Integration testing
- [ ] Refactor the index maps cache to be storing a
`idsByObjectMetadataId`
- [x] Refactor deterministic name to use order sorting
- [x] Remove flat index from flat object

## What's next

Will handle morph indexes in a new dedicated PR for the moment will
stick to this
Same for the cache improvement and uniqueness
This commit is contained in:
Paul Rastoin
2025-09-23 10:57:11 +02:00
committed by GitHub
parent d0b9c7f076
commit fbd3286792
63 changed files with 2591 additions and 1323 deletions
@@ -2,6 +2,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { v4 } from 'uuid';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
CUSTOM_OBJECT_STANDARD_FIELD_IDS,
@@ -10,12 +11,16 @@ import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-mana
type BuildDefaultFlatFieldMetadataForCustomObjectArgs = {
workspaceId: string;
objectMetadataId: string;
flatObjectMetadata: Pick<FlatObjectMetadata, 'id'>;
};
export type DefaultFlatFieldForCustomObjectMaps = ReturnType<
typeof buildDefaultFlatFieldMetadatasForCustomObject
>;
// This could be replaced totally by an import schema + its transpilation when it's ready
export const buildDefaultFlatFieldMetadatasForCustomObject = ({
workspaceId,
objectMetadataId,
flatObjectMetadata: { id: objectMetadataId },
}: BuildDefaultFlatFieldMetadataForCustomObjectArgs) => {
const createdAt = new Date();
const idField: FlatFieldMetadata<FieldMetadataType.UUID> = {
@@ -278,13 +283,17 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
};
return {
idField,
nameField,
createdAtField,
updatedAtField,
deletedAtField,
createdByField,
positionField,
searchVectorField,
} as const;
fields: {
idField,
nameField,
createdAtField,
updatedAtField,
deletedAtField,
createdByField,
positionField,
searchVectorField,
},
} as const satisfies {
fields: Record<string, FlatFieldMetadata>;
};
};
@@ -0,0 +1,52 @@
import { v4 } from 'uuid';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { IndexType } from 'src/engine/metadata-modules/index-metadata/types/indexType.types';
import { generateFlatIndexMetadataWithNameOrThrow } from 'src/engine/metadata-modules/index-metadata/utils/generate-flat-index.util';
import { type DefaultFlatFieldForCustomObjectMaps } from 'src/engine/metadata-modules/object-metadata/utils/build-default-flat-field-metadatas-for-custom-object.util';
export const buildDefaultIndexesForCustomObject = ({
workspaceId,
flatObjectMetadata,
defaultFlatFieldForCustomObjectMaps,
}: {
workspaceId: string;
flatObjectMetadata: FlatObjectMetadata;
defaultFlatFieldForCustomObjectMaps: DefaultFlatFieldForCustomObjectMaps;
}) => {
const tsFlatVectorIndexId = v4();
const createdAt = new Date();
const tsVectorFlatIndex = generateFlatIndexMetadataWithNameOrThrow({
flatIndex: {
createdAt,
flatIndexFieldMetadatas: [
{
createdAt,
fieldMetadataId:
defaultFlatFieldForCustomObjectMaps.fields.searchVectorField.id,
id: v4(),
indexMetadataId: tsFlatVectorIndexId,
order: 0,
updatedAt: createdAt,
},
],
id: tsFlatVectorIndexId,
indexType: IndexType.GIN,
indexWhereClause: null,
isCustom: false,
isUnique: false,
objectMetadataId: flatObjectMetadata.id,
universalIdentifier: tsFlatVectorIndexId,
updatedAt: createdAt,
workspaceId,
},
flatObjectMetadata,
});
return {
indexes: {
tsVectorFlatIndex,
},
} as const satisfies { indexes: Record<string, FlatIndexMetadata> };
};