Fix - Update searchVector when labelIdentifier is updated (#16940)
Fixes https://github.com/twentyhq/twenty/issues/16891 In next PR, validation rules will be added in migration logic
This commit is contained in:
+2
@@ -171,12 +171,14 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
|
||||
flatViewsToDelete,
|
||||
flatViewFieldsToDelete,
|
||||
flatViewsToUpdate,
|
||||
flatFieldMetadatasToUpdate: flatFieldMetadatasToUpdateFromSideEffect,
|
||||
} = sideEffectResult.result;
|
||||
|
||||
return {
|
||||
flatFieldMetadatasToUpdate: [
|
||||
...accumulator.flatFieldMetadatasToUpdate,
|
||||
toFlatFieldMetadata,
|
||||
...flatFieldMetadatasToUpdateFromSideEffect,
|
||||
],
|
||||
flatIndexMetadatasToUpdate: [
|
||||
...accumulator.flatIndexMetadatasToUpdate,
|
||||
|
||||
+32
-1
@@ -1,6 +1,8 @@
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { type FieldInputTranspilationResult } from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { handleEnumFlatFieldMetadataUpdateSideEffects } from 'src/engine/metadata-modules/flat-field-metadata/utils/handle-enum-flat-field-metadata-update-side-effects.util';
|
||||
@@ -12,6 +14,7 @@ import {
|
||||
type FieldMetadataUpdateIndexSideEffect,
|
||||
handleIndexChangesDuringFieldUpdate,
|
||||
} from 'src/engine/metadata-modules/flat-field-metadata/utils/handle-index-changes-during-field-update.util';
|
||||
import { handleLabelIdentifierChangesDuringFieldUpdate } from 'src/engine/metadata-modules/flat-field-metadata/utils/handle-label-identifier-changes-during-field-update.util';
|
||||
import { isEnumFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-enum-flat-field-metadata.util';
|
||||
import { type FlatViewFiltersToDeleteAndUpdate } from 'src/engine/metadata-modules/flat-field-metadata/utils/recompute-view-filters-on-flat-field-metadata-options-update.util';
|
||||
import { type FlatViewGroupsToDeleteUpdateAndCreate } from 'src/engine/metadata-modules/flat-field-metadata/utils/recompute-view-groups-on-flat-field-metadata-options-update.util';
|
||||
@@ -20,7 +23,9 @@ export type FlatFieldMetadataUpdateSideEffects =
|
||||
FlatViewFiltersToDeleteAndUpdate &
|
||||
FlatViewGroupsToDeleteUpdateAndCreate &
|
||||
FieldMetadataUpdateIndexSideEffect &
|
||||
FieldMetadataDeactivationSideEffect;
|
||||
FieldMetadataDeactivationSideEffect & {
|
||||
flatFieldMetadatasToUpdate: FlatFieldMetadata[];
|
||||
};
|
||||
|
||||
type HandleFlatFieldMetadataUpdateSideEffectArgs = FromTo<
|
||||
FlatFieldMetadata,
|
||||
@@ -52,6 +57,7 @@ export const FLAT_FIELD_METADATA_UPDATE_EMPTY_SIDE_EFFECTS: FlatFieldMetadataUpd
|
||||
flatViewsToDelete: [],
|
||||
flatViewFieldsToDelete: [],
|
||||
flatViewsToUpdate: [],
|
||||
flatFieldMetadatasToUpdate: [],
|
||||
};
|
||||
|
||||
export const handleFlatFieldMetadataUpdateSideEffect = ({
|
||||
@@ -131,6 +137,31 @@ export const handleFlatFieldMetadataUpdateSideEffect = ({
|
||||
return indexChangesSideEffectResult;
|
||||
}
|
||||
|
||||
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
flatEntityId: fromFlatFieldMetadata.objectMetadataId,
|
||||
});
|
||||
|
||||
const isLabelIdentifierFieldMetadata =
|
||||
flatObjectMetadata.labelIdentifierFieldMetadataId ===
|
||||
toFlatFieldMetadata.id;
|
||||
|
||||
if (isLabelIdentifierFieldMetadata) {
|
||||
const flatSearchVectorFieldToUpdate =
|
||||
handleLabelIdentifierChangesDuringFieldUpdate({
|
||||
fromFlatFieldMetadata,
|
||||
toFlatFieldMetadata,
|
||||
flatObjectMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (isDefined(flatSearchVectorFieldToUpdate)) {
|
||||
sideEffectResult.flatFieldMetadatasToUpdate.push(
|
||||
flatSearchVectorFieldToUpdate,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
flatIndexMetadatasToUpdate,
|
||||
flatIndexMetadatasToCreate,
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
import { type FieldMetadataType, type FromTo } from 'twenty-shared/types';
|
||||
import { findOrThrow } from 'twenty-shared/utils';
|
||||
|
||||
import {
|
||||
FieldMetadataException,
|
||||
FieldMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
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 { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/search-field-metadata/constants/search-vector-field.constants';
|
||||
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
|
||||
import { type SearchableFieldType } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-searchable-field.util';
|
||||
|
||||
type HandleLabelIdentifierChangesDuringFieldUpdateArgs = {
|
||||
flatObjectMetadata: FlatObjectMetadata;
|
||||
} & FromTo<FlatFieldMetadata, 'flatFieldMetadata'> &
|
||||
Pick<AllFlatEntityMaps, 'flatFieldMetadataMaps'>;
|
||||
|
||||
export const handleLabelIdentifierChangesDuringFieldUpdate = ({
|
||||
fromFlatFieldMetadata,
|
||||
toFlatFieldMetadata,
|
||||
flatObjectMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
}: HandleLabelIdentifierChangesDuringFieldUpdateArgs):
|
||||
| FlatFieldMetadata<FieldMetadataType.TS_VECTOR>
|
||||
| undefined => {
|
||||
const hasNameChanged =
|
||||
fromFlatFieldMetadata.name !== toFlatFieldMetadata.name;
|
||||
|
||||
if (!hasNameChanged) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const objectFlatFieldMetadatas =
|
||||
findManyFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
flatEntityIds: flatObjectMetadata.fieldMetadataIds,
|
||||
});
|
||||
|
||||
const searchVectorField = findOrThrow(
|
||||
objectFlatFieldMetadatas,
|
||||
(field) => field.name === SEARCH_VECTOR_FIELD.name,
|
||||
new FieldMetadataException(
|
||||
`Search vector field not found for object metadata ${flatObjectMetadata.id}`,
|
||||
FieldMetadataExceptionCode.FIELD_METADATA_NOT_FOUND,
|
||||
),
|
||||
) as FlatFieldMetadata<FieldMetadataType.TS_VECTOR>;
|
||||
|
||||
try {
|
||||
const newAsExpression = getTsVectorColumnExpressionFromFields([
|
||||
{
|
||||
name: toFlatFieldMetadata.name,
|
||||
type: toFlatFieldMetadata.type as SearchableFieldType,
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
...searchVectorField,
|
||||
settings: {
|
||||
...searchVectorField.settings,
|
||||
asExpression: newAsExpression,
|
||||
},
|
||||
};
|
||||
} catch {
|
||||
throw new FieldMetadataException(
|
||||
`Failed to compute search vector column expression for field ${toFlatFieldMetadata.name}`,
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
);
|
||||
}
|
||||
};
|
||||
+2
@@ -84,6 +84,7 @@ export const fromUpdateObjectInputToFlatObjectMetadataAndRelatedFlatEntities =
|
||||
flatViewFieldsToCreate,
|
||||
flatViewFieldsToUpdate,
|
||||
otherObjectFlatFieldMetadatasToUpdate,
|
||||
sameObjectFlatFieldMetadatasToUpdate,
|
||||
} = handleFlatObjectMetadataUpdateSideEffect({
|
||||
fromFlatObjectMetadata: existingFlatObjectMetadata,
|
||||
toFlatObjectMetadata,
|
||||
@@ -100,5 +101,6 @@ export const fromUpdateObjectInputToFlatObjectMetadataAndRelatedFlatEntities =
|
||||
flatViewFieldsToCreate,
|
||||
flatViewFieldsToUpdate,
|
||||
otherObjectFlatFieldMetadatasToUpdate,
|
||||
sameObjectFlatFieldMetadatasToUpdate,
|
||||
};
|
||||
};
|
||||
|
||||
+24
@@ -6,12 +6,14 @@ import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-m
|
||||
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 { recomputeIndexAfterFlatObjectMetadataSingularNameUpdate } from 'src/engine/metadata-modules/flat-object-metadata/utils/recompute-index-after-flat-object-metadata-singular-name-update.util';
|
||||
import { recomputeSearchVectorFieldAfterLabelIdentifierUpdate } from 'src/engine/metadata-modules/flat-object-metadata/utils/recompute-search-vector-field-after-label-identifier-update.util';
|
||||
import { recomputeViewFieldIdentifierAfterFlatObjectIdentifierUpdate } from 'src/engine/metadata-modules/flat-object-metadata/utils/recompute-view-field-identifier-after-flat-object-identifier-update.util';
|
||||
import { renameRelatedMorphFieldOnObjectNamesUpdate } from 'src/engine/metadata-modules/flat-object-metadata/utils/rename-related-morph-field-on-object-names-update.util';
|
||||
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
|
||||
|
||||
export type FlatObjectMetadataUpdateSideEffects = {
|
||||
otherObjectFlatFieldMetadatasToUpdate: FlatFieldMetadata[];
|
||||
sameObjectFlatFieldMetadatasToUpdate: FlatFieldMetadata[];
|
||||
flatViewFieldsToUpdate: FlatViewField[];
|
||||
flatViewFieldsToCreate: FlatViewField[];
|
||||
flatIndexMetadatasToUpdate: FlatIndexMetadata[];
|
||||
@@ -81,6 +83,27 @@ export const handleFlatObjectMetadataUpdateSideEffect = ({
|
||||
flatViewFieldsToUpdate: [],
|
||||
};
|
||||
|
||||
const sameObjectFlatFieldMetadatasToUpdate: FlatFieldMetadata[] = [];
|
||||
|
||||
if (
|
||||
toFlatObjectMetadata.isSearchable &&
|
||||
isDefined(toFlatObjectMetadata.labelIdentifierFieldMetadataId) &&
|
||||
fromFlatObjectMetadata.labelIdentifierFieldMetadataId !==
|
||||
toFlatObjectMetadata.labelIdentifierFieldMetadataId
|
||||
) {
|
||||
const updatedSearchVectorField =
|
||||
recomputeSearchVectorFieldAfterLabelIdentifierUpdate({
|
||||
existingFlatObjectMetadata: fromFlatObjectMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
updatedLabelIdentifierFieldMetadataId:
|
||||
toFlatObjectMetadata.labelIdentifierFieldMetadataId,
|
||||
});
|
||||
|
||||
if (isDefined(updatedSearchVectorField)) {
|
||||
sameObjectFlatFieldMetadatasToUpdate.push(updatedSearchVectorField);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
flatIndexMetadatasToUpdate: [
|
||||
...morphRelatedFlatIndexesToUpdate,
|
||||
@@ -89,5 +112,6 @@ export const handleFlatObjectMetadataUpdateSideEffect = ({
|
||||
flatViewFieldsToCreate,
|
||||
flatViewFieldsToUpdate,
|
||||
otherObjectFlatFieldMetadatasToUpdate: morphFlatFieldMetadatasToUpdate,
|
||||
sameObjectFlatFieldMetadatasToUpdate,
|
||||
};
|
||||
};
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
import { type FieldMetadataType } from 'twenty-shared/types';
|
||||
import { findOrThrow, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
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 {
|
||||
ObjectMetadataException,
|
||||
ObjectMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
|
||||
import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/search-field-metadata/constants/search-vector-field.constants';
|
||||
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
|
||||
import { type SearchableFieldType } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-searchable-field.util';
|
||||
|
||||
type RecomputeSearchVectorFieldAfterLabelIdentifierUpdateArgs = {
|
||||
existingFlatObjectMetadata: FlatObjectMetadata;
|
||||
updatedLabelIdentifierFieldMetadataId: string;
|
||||
} & Pick<AllFlatEntityMaps, 'flatFieldMetadataMaps'>;
|
||||
|
||||
export const recomputeSearchVectorFieldAfterLabelIdentifierUpdate = ({
|
||||
existingFlatObjectMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
updatedLabelIdentifierFieldMetadataId,
|
||||
}: RecomputeSearchVectorFieldAfterLabelIdentifierUpdateArgs):
|
||||
| FlatFieldMetadata<FieldMetadataType.TS_VECTOR>
|
||||
| undefined => {
|
||||
const objectFlatFieldMetadatas =
|
||||
findManyFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
flatEntityIds: existingFlatObjectMetadata.fieldMetadataIds,
|
||||
});
|
||||
|
||||
const searchVectorField = findOrThrow(
|
||||
objectFlatFieldMetadatas,
|
||||
(field) => field.name === SEARCH_VECTOR_FIELD.name,
|
||||
) as FlatFieldMetadata<FieldMetadataType.TS_VECTOR>;
|
||||
|
||||
const newLabelIdentifierField = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
flatEntityId: updatedLabelIdentifierFieldMetadataId,
|
||||
});
|
||||
|
||||
if (!isDefined(newLabelIdentifierField)) {
|
||||
throw new ObjectMetadataException(
|
||||
`New label identifier field not found for object metadata`,
|
||||
ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const newAsExpression = getTsVectorColumnExpressionFromFields([
|
||||
{
|
||||
name: newLabelIdentifierField.name,
|
||||
type: newLabelIdentifierField.type as SearchableFieldType,
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
...searchVectorField,
|
||||
settings: {
|
||||
...searchVectorField.settings,
|
||||
asExpression: newAsExpression,
|
||||
generatedType: 'STORED',
|
||||
},
|
||||
};
|
||||
} catch {
|
||||
throw new ObjectMetadataException(
|
||||
`Failed to compute search vector column expression for field ${newLabelIdentifierField.name}`,
|
||||
ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
|
||||
);
|
||||
}
|
||||
};
|
||||
+5
-1
@@ -81,6 +81,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
|
||||
const {
|
||||
otherObjectFlatFieldMetadatasToUpdate,
|
||||
sameObjectFlatFieldMetadatasToUpdate,
|
||||
flatObjectMetadataToUpdate,
|
||||
flatIndexMetadatasToUpdate,
|
||||
flatViewFieldsToCreate,
|
||||
@@ -111,7 +112,10 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
fieldMetadata: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: otherObjectFlatFieldMetadatasToUpdate,
|
||||
flatEntityToUpdate: [
|
||||
...otherObjectFlatFieldMetadatasToUpdate,
|
||||
...sameObjectFlatFieldMetadatasToUpdate,
|
||||
],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: flatViewFieldsToCreate,
|
||||
|
||||
+2
@@ -945,6 +945,8 @@ export class WorkspaceMigrationBuildOrchestratorService {
|
||||
const { aggregatedOrchestratorActionsReport } =
|
||||
aggregateOrchestratorActionsReport({
|
||||
orchestratorActionsReport,
|
||||
flatFieldMetadataMaps:
|
||||
optimisticAllFlatEntityMaps.flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
|
||||
|
||||
export type AggregateOrchestratorActionsReportArgs = {
|
||||
orchestratorActionsReport: OrchestratorActionsReport;
|
||||
flatFieldMetadataMaps?: FlatEntityMaps<FlatFieldMetadata>;
|
||||
};
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
|
||||
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/search-field-metadata/constants/search-vector-field.constants';
|
||||
import { createEmptyOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/constant/empty-orchestrator-actions-report.constant';
|
||||
import { aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldActions } from 'src/engine/workspace-manager/workspace-migration-v2/utils/aggregate-orchestrator-actions-report-deprioritize-search-vector-update-field-actions.util';
|
||||
import { type UpdateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/types/workspace-migration-field-action-v2';
|
||||
|
||||
describe('aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldActions', () => {
|
||||
it('should move searchVector update actions to the end of the update list', () => {
|
||||
const orchestratorActionsReport = {
|
||||
...createEmptyOrchestratorActionsReport(),
|
||||
fieldMetadata: {
|
||||
create: [],
|
||||
update: [
|
||||
{
|
||||
type: 'update',
|
||||
metadataName: 'fieldMetadata',
|
||||
entityId: 'search-vector-field-1',
|
||||
objectMetadataId: 'object-1',
|
||||
updates: [
|
||||
{
|
||||
property: 'label',
|
||||
from: 'Search Vector',
|
||||
to: 'Updated Search Vector',
|
||||
},
|
||||
],
|
||||
} satisfies UpdateFieldAction,
|
||||
{
|
||||
type: 'update',
|
||||
metadataName: 'fieldMetadata',
|
||||
entityId: 'regular-field-1',
|
||||
objectMetadataId: 'object-1',
|
||||
updates: [
|
||||
{
|
||||
property: 'label',
|
||||
from: 'First Name',
|
||||
to: 'Updated First Name',
|
||||
},
|
||||
],
|
||||
} satisfies UpdateFieldAction,
|
||||
{
|
||||
type: 'update',
|
||||
metadataName: 'fieldMetadata',
|
||||
entityId: 'regular-field-2',
|
||||
objectMetadataId: 'object-1',
|
||||
updates: [
|
||||
{
|
||||
property: 'label',
|
||||
from: 'Last Name',
|
||||
to: 'Updated Last Name',
|
||||
},
|
||||
],
|
||||
} satisfies UpdateFieldAction,
|
||||
],
|
||||
delete: [],
|
||||
},
|
||||
};
|
||||
|
||||
const flatFieldMetadataMaps = [
|
||||
getFlatFieldMetadataMock({
|
||||
universalIdentifier: 'search-vector-field-1',
|
||||
objectMetadataId: 'object-1',
|
||||
type: FieldMetadataType.TS_VECTOR,
|
||||
id: 'search-vector-field-1',
|
||||
name: SEARCH_VECTOR_FIELD.name,
|
||||
}),
|
||||
getFlatFieldMetadataMock({
|
||||
universalIdentifier: 'regular-field-1',
|
||||
objectMetadataId: 'object-1',
|
||||
type: FieldMetadataType.TEXT,
|
||||
id: 'regular-field-1',
|
||||
name: 'firstName',
|
||||
}),
|
||||
getFlatFieldMetadataMock({
|
||||
universalIdentifier: 'regular-field-2',
|
||||
objectMetadataId: 'object-1',
|
||||
type: FieldMetadataType.TEXT,
|
||||
id: 'regular-field-2',
|
||||
name: 'lastName',
|
||||
}),
|
||||
].reduce<FlatEntityMaps<FlatFieldMetadata>>(
|
||||
(flatEntityMaps, field) =>
|
||||
addFlatEntityToFlatEntityMapsOrThrow({
|
||||
flatEntity: field,
|
||||
flatEntityMaps,
|
||||
}),
|
||||
createEmptyFlatEntityMaps() as FlatEntityMaps<FlatFieldMetadata>,
|
||||
);
|
||||
|
||||
const result =
|
||||
aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldActions(
|
||||
{
|
||||
orchestratorActionsReport,
|
||||
flatFieldMetadataMaps,
|
||||
},
|
||||
);
|
||||
|
||||
const updateFieldActions = result.fieldMetadata
|
||||
.update as UpdateFieldAction[];
|
||||
|
||||
const actualEntityIds = updateFieldActions.map((action) => action.entityId);
|
||||
|
||||
expect(actualEntityIds).toEqual([
|
||||
'regular-field-1',
|
||||
'regular-field-2',
|
||||
'search-vector-field-1',
|
||||
]);
|
||||
|
||||
expect(result.fieldMetadata.create).toEqual(
|
||||
orchestratorActionsReport.fieldMetadata.create,
|
||||
);
|
||||
expect(result.fieldMetadata.delete).toEqual(
|
||||
orchestratorActionsReport.fieldMetadata.delete,
|
||||
);
|
||||
expect(result.objectMetadata).toEqual(
|
||||
orchestratorActionsReport.objectMetadata,
|
||||
);
|
||||
});
|
||||
});
|
||||
+2
-5
@@ -2,14 +2,11 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
|
||||
import { type AggregateOrchestratorActionsReportArgs } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-aggregate-orchestrator-actions-report-args.type';
|
||||
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
|
||||
import { type CreateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/types/workspace-migration-field-action-v2';
|
||||
import { type CreateObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/types/workspace-migration-object-action-v2';
|
||||
|
||||
type AggregateOrchestratorActionsReportCreateObjectAndCreateFieldActionsArgs = {
|
||||
orchestratorActionsReport: OrchestratorActionsReport;
|
||||
};
|
||||
|
||||
type AggregatedActions = {
|
||||
createdFieldActionByObjectMetadataId: Record<string, CreateFieldAction>;
|
||||
createdObjectActionByObjectMetadataId: Record<string, CreateObjectAction>;
|
||||
@@ -18,7 +15,7 @@ type AggregatedActions = {
|
||||
export const aggregateOrchestratorActionsReportCreateObjectAndCreateFieldActions =
|
||||
({
|
||||
orchestratorActionsReport,
|
||||
}: AggregateOrchestratorActionsReportCreateObjectAndCreateFieldActionsArgs): OrchestratorActionsReport => {
|
||||
}: AggregateOrchestratorActionsReportArgs): OrchestratorActionsReport => {
|
||||
const initialCreatedObjectActionByObjectMetadataId = (
|
||||
orchestratorActionsReport.objectMetadata.create as CreateObjectAction[]
|
||||
).reduce(
|
||||
|
||||
+2
-5
@@ -1,20 +1,17 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type AggregateOrchestratorActionsReportArgs } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-aggregate-orchestrator-actions-report-args.type';
|
||||
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
|
||||
import { type DeleteFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/types/workspace-migration-field-action-v2';
|
||||
import { type DeleteObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/types/workspace-migration-object-action-v2';
|
||||
|
||||
type AggregateOrchestratorActionsReportDeleteObjectAndDeleteFieldActionsArgs = {
|
||||
orchestratorActionsReport: OrchestratorActionsReport;
|
||||
};
|
||||
|
||||
type AggregatedActions = {
|
||||
deleteFieldActionByFieldMetadataId: Record<string, DeleteFieldAction>;
|
||||
};
|
||||
export const aggregateOrchestratorActionsReportDeleteObjectAndDeleteFieldActions =
|
||||
({
|
||||
orchestratorActionsReport,
|
||||
}: AggregateOrchestratorActionsReportDeleteObjectAndDeleteFieldActionsArgs): OrchestratorActionsReport => {
|
||||
}: AggregateOrchestratorActionsReportArgs): OrchestratorActionsReport => {
|
||||
const deleteObjectActionByObjectMetadataId = (
|
||||
orchestratorActionsReport.objectMetadata.delete as DeleteObjectAction[]
|
||||
).reduce<Record<string, DeleteObjectAction>>(
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
|
||||
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/search-field-metadata/constants/search-vector-field.constants';
|
||||
import { type AggregateOrchestratorActionsReportArgs } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-aggregate-orchestrator-actions-report-args.type';
|
||||
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
|
||||
import { type UpdateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/types/workspace-migration-field-action-v2';
|
||||
|
||||
export const aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldActions =
|
||||
({
|
||||
orchestratorActionsReport,
|
||||
flatFieldMetadataMaps,
|
||||
}: AggregateOrchestratorActionsReportArgs): OrchestratorActionsReport => {
|
||||
assertIsDefinedOrThrow(flatFieldMetadataMaps);
|
||||
|
||||
const updateFieldActions = orchestratorActionsReport.fieldMetadata
|
||||
.update as UpdateFieldAction[];
|
||||
|
||||
const { searchVectorUpdateFieldActions, otherUpdateFieldActions } =
|
||||
updateFieldActions.reduce<{
|
||||
searchVectorUpdateFieldActions: UpdateFieldAction[];
|
||||
otherUpdateFieldActions: UpdateFieldAction[];
|
||||
}>(
|
||||
(acc, updateFieldAction) => {
|
||||
const flatFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
flatEntityId: updateFieldAction.entityId,
|
||||
});
|
||||
|
||||
const isSearchVectorUpdateFieldAction =
|
||||
flatFieldMetadata?.name === SEARCH_VECTOR_FIELD.name;
|
||||
|
||||
if (isSearchVectorUpdateFieldAction) {
|
||||
return {
|
||||
...acc,
|
||||
searchVectorUpdateFieldActions: [
|
||||
...acc.searchVectorUpdateFieldActions,
|
||||
updateFieldAction,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...acc,
|
||||
otherUpdateFieldActions: [
|
||||
...acc.otherUpdateFieldActions,
|
||||
updateFieldAction,
|
||||
],
|
||||
};
|
||||
},
|
||||
{
|
||||
searchVectorUpdateFieldActions: [],
|
||||
otherUpdateFieldActions: [],
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
...orchestratorActionsReport,
|
||||
fieldMetadata: {
|
||||
...orchestratorActionsReport.fieldMetadata,
|
||||
update: [...otherUpdateFieldActions, ...searchVectorUpdateFieldActions],
|
||||
},
|
||||
};
|
||||
};
|
||||
+5
-4
@@ -1,20 +1,21 @@
|
||||
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
|
||||
import { type AggregateOrchestratorActionsReportArgs } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-aggregate-orchestrator-actions-report-args.type';
|
||||
import { aggregateOrchestratorActionsReportCreateObjectAndCreateFieldActions } from 'src/engine/workspace-manager/workspace-migration-v2/utils/aggregate-orchestrator-actions-report-create-object-and-create-field-actions.util';
|
||||
import { aggregateOrchestratorActionsReportDeleteObjectAndDeleteFieldActions } from 'src/engine/workspace-manager/workspace-migration-v2/utils/aggregate-orchestrator-actions-report-delete-object-and-delete-field.util';
|
||||
import { aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldActions } from 'src/engine/workspace-manager/workspace-migration-v2/utils/aggregate-orchestrator-actions-report-deprioritize-search-vector-update-field-actions.util';
|
||||
|
||||
type AggregateOrchestratorActionsReportArgs = {
|
||||
orchestratorActionsReport: OrchestratorActionsReport;
|
||||
};
|
||||
export const aggregateOrchestratorActionsReport = ({
|
||||
orchestratorActionsReport,
|
||||
flatFieldMetadataMaps,
|
||||
}: AggregateOrchestratorActionsReportArgs) => {
|
||||
const aggregatedOrchestratorActionsReport = [
|
||||
aggregateOrchestratorActionsReportCreateObjectAndCreateFieldActions,
|
||||
aggregateOrchestratorActionsReportDeleteObjectAndDeleteFieldActions,
|
||||
aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldActions,
|
||||
].reduce(
|
||||
(currentOrchestratorActionsReport, aggregator) =>
|
||||
aggregator({
|
||||
orchestratorActionsReport: currentOrchestratorActionsReport,
|
||||
flatFieldMetadataMaps,
|
||||
}),
|
||||
orchestratorActionsReport,
|
||||
);
|
||||
|
||||
+31
@@ -190,6 +190,37 @@ export class UpdateFieldActionHandlerService extends WorkspaceMigrationRunnerAct
|
||||
},
|
||||
};
|
||||
}
|
||||
if (
|
||||
isPropertyUpdate(update, 'settings') &&
|
||||
isDefined(update.to?.asExpression) &&
|
||||
isDefined(update.from?.asExpression) &&
|
||||
(update.to.asExpression !== update.from.asExpression ||
|
||||
update.to.generatedType !== update.from.generatedType)
|
||||
) {
|
||||
await this.workspaceSchemaManagerService.columnManager.dropColumns({
|
||||
queryRunner,
|
||||
schemaName,
|
||||
tableName,
|
||||
columnNames: [optimisticFlatFieldMetadata.name],
|
||||
});
|
||||
await this.workspaceSchemaManagerService.columnManager.addColumns({
|
||||
queryRunner,
|
||||
schemaName,
|
||||
tableName,
|
||||
columnDefinitions: [
|
||||
{
|
||||
name: optimisticFlatFieldMetadata.name,
|
||||
type: 'tsvector',
|
||||
...update.to,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
optimisticFlatFieldMetadata = {
|
||||
...optimisticFlatFieldMetadata,
|
||||
settings: update.to,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user