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:
+33
@@ -0,0 +1,33 @@
|
||||
import { createHash } from 'crypto';
|
||||
|
||||
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 { computeTableName } from 'src/engine/utils/compute-table-name.util';
|
||||
|
||||
type GenerateDeterministicIndexNameArgs = {
|
||||
flatObjectMetadata: Pick<FlatObjectMetadata, 'nameSingular' | 'isCustom'>;
|
||||
isUnique?: boolean;
|
||||
relatedFieldNames: Pick<FlatFieldMetadata, 'name'>[];
|
||||
};
|
||||
export const generateDeterministicIndexNameV2 = ({
|
||||
relatedFieldNames,
|
||||
flatObjectMetadata,
|
||||
isUnique = false,
|
||||
}: GenerateDeterministicIndexNameArgs): string => {
|
||||
const hash = createHash('sha256');
|
||||
|
||||
const tableName = computeTableName(
|
||||
flatObjectMetadata.nameSingular,
|
||||
flatObjectMetadata.isCustom,
|
||||
);
|
||||
|
||||
const columnsNames = relatedFieldNames.map(
|
||||
(flatFieldMetadata) => flatFieldMetadata.name,
|
||||
);
|
||||
|
||||
[tableName, ...columnsNames].forEach((column) => {
|
||||
hash.update(column);
|
||||
});
|
||||
|
||||
return `IDX_${isUnique ? 'UNIQUE_' : ''}${hash.digest('hex').slice(0, 27)}`;
|
||||
};
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import {
|
||||
FlatEntityMapsException,
|
||||
FlatEntityMapsExceptionCode,
|
||||
} from 'src/engine/core-modules/common/exceptions/flat-entity-maps.exception';
|
||||
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
|
||||
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 { generateDeterministicIndexNameV2 } from 'src/engine/metadata-modules/index-metadata/utils/generate-deterministic-index-name-v2';
|
||||
|
||||
type GenerateFlatIndexArgs = {
|
||||
flatObjectMetadata: FlatObjectMetadata;
|
||||
flatIndex: Omit<FlatIndexMetadata, 'name'>;
|
||||
};
|
||||
export const generateFlatIndexMetadataWithNameOrThrow = ({
|
||||
flatObjectMetadata,
|
||||
flatIndex,
|
||||
}: GenerateFlatIndexArgs): FlatIndexMetadata => {
|
||||
const orderedFlatFieldNames = flatIndex.flatIndexFieldMetadatas
|
||||
.sort((a, b) => a.order - b.order)
|
||||
.map((flatIndexField) => {
|
||||
const relatedFlatFieldMetadata =
|
||||
flatObjectMetadata.flatFieldMetadatas.find(
|
||||
(flatFieldMetadata) =>
|
||||
flatFieldMetadata.id === flatIndexField.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(relatedFlatFieldMetadata)) {
|
||||
throw new FlatEntityMapsException(
|
||||
'Could not find flat index field related field in cache',
|
||||
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const name = isMorphOrRelationFlatFieldMetadata(relatedFlatFieldMetadata)
|
||||
? (relatedFlatFieldMetadata.settings.joinColumnName ??
|
||||
relatedFlatFieldMetadata.name)
|
||||
: relatedFlatFieldMetadata.name;
|
||||
|
||||
return {
|
||||
name,
|
||||
};
|
||||
});
|
||||
|
||||
const name = generateDeterministicIndexNameV2({
|
||||
flatObjectMetadata,
|
||||
isUnique: flatIndex.isUnique,
|
||||
relatedFieldNames: orderedFlatFieldNames,
|
||||
});
|
||||
|
||||
return {
|
||||
...flatIndex,
|
||||
name,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user