[GQL_VIEW_FILTER_API_BREAKING_CHANGE][WHEN_RELEASED_REQUIRES_CACHE_FLUSH] ViewFilter migration to workspace migration v2 (#15010)
# Introduction Migrating `viewFilter` to v2 in order to migrate later the field update side effect on view to v2 too ## What's done - Created flat-view-filter - flat view filter runner - flat view filter builder - create view filter service v2 and input transpilers - refactor the existing view filter resolver to fix standard ( BREAKING_CHANGE on graphql api update especially ) REST stays the same - refactored the front to consume the mutations autogenerated ## New generic tools ### Compare two flat entity Introducing a new util to compare two flat entity, it's strictly typed and will be added to the generic builder in a following PR This will ease flat entity addition as won't required to create a specific abstraction for comparison Generic builder will expect specific constant: properties to compare and properties to stringify ### Transform flat entity for comparison Forked and refactor the initial existing method for flat entity business scope and type safety ## Coverage Migrated existing integration tests to fit new contract API This PR does not add strong coverage on validation exceptions Deadlines are too short close https://github.com/twentyhq/core-team-issues/issues/1666
This commit is contained in:
+1
@@ -10,4 +10,5 @@ export const ALL_FLAT_ENTITY_MAPS_PROPERTIES = [
|
||||
'flatCronTriggerMaps',
|
||||
'flatRouteTriggerMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatViewFilterMaps',
|
||||
] as const satisfies (keyof AllFlatEntityMaps)[];
|
||||
|
||||
+1
@@ -11,4 +11,5 @@ export const EMPTY_ALL_FLAT_ENTITY_MAPS = {
|
||||
flatCronTriggerMaps: EMPTY_FLAT_ENTITY_MAPS,
|
||||
flatDatabaseEventTriggerMaps: EMPTY_FLAT_ENTITY_MAPS,
|
||||
flatRouteTriggerMaps: EMPTY_FLAT_ENTITY_MAPS,
|
||||
flatViewFilterMaps: EMPTY_FLAT_ENTITY_MAPS,
|
||||
} as const satisfies AllFlatEntityMaps;
|
||||
|
||||
+2
@@ -4,6 +4,7 @@ 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 { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
|
||||
import { type FlatViewFilter } from 'src/engine/metadata-modules/flat-view-filter/types/flat-view-filter.type';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { type FlatRouteTrigger } from 'src/engine/metadata-modules/route-trigger/types/flat-route-trigger.type';
|
||||
import { type FlatServerlessFunction } from 'src/engine/metadata-modules/serverless-function/types/flat-serverless-function.type';
|
||||
@@ -18,4 +19,5 @@ export type AllFlatEntitiesByMetadataEngineName = {
|
||||
cronTrigger: FlatCronTrigger;
|
||||
databaseEventTrigger: FlatDatabaseEventTrigger;
|
||||
routeTrigger: FlatRouteTrigger;
|
||||
viewFilter: FlatViewFilter;
|
||||
};
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
import diff from 'microdiff';
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
import { parseJson } from 'twenty-shared/utils';
|
||||
|
||||
import { type AllFlatEntities } from 'src/engine/core-modules/common/types/all-flat-entities.type';
|
||||
import { transformFlatEntityForComparison } from 'src/engine/core-modules/common/utils/transform-flat-entity-for-comparison.util';
|
||||
import { type PropertyUpdate } from 'src/engine/workspace-manager/workspace-migration-v2/types/property-update.type';
|
||||
|
||||
export const compareTwoFlatEntity = <
|
||||
TFlatEntity extends AllFlatEntities,
|
||||
PToCompare extends keyof TFlatEntity,
|
||||
PJsonB extends keyof TFlatEntity,
|
||||
>({
|
||||
fromFlatEntity,
|
||||
toFlatEntity,
|
||||
propertiesToCompare,
|
||||
propertiesToStringify,
|
||||
}: {
|
||||
propertiesToCompare: PToCompare[];
|
||||
propertiesToStringify: PJsonB[];
|
||||
} & FromTo<TFlatEntity, 'flatEntity'>) => {
|
||||
const [transformedFromFlatEntity, transformedToFlatEntity] = [
|
||||
fromFlatEntity,
|
||||
toFlatEntity,
|
||||
].map((flatEntity) =>
|
||||
transformFlatEntityForComparison({
|
||||
flatEntity,
|
||||
options: {
|
||||
propertiesToCompare,
|
||||
propertiesToStringify,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const flatEntityDifferences = diff(
|
||||
transformedFromFlatEntity,
|
||||
transformedToFlatEntity,
|
||||
);
|
||||
|
||||
return flatEntityDifferences.flatMap<
|
||||
Array<
|
||||
{
|
||||
[P in PToCompare]: PropertyUpdate<TFlatEntity, P>;
|
||||
}[PToCompare]
|
||||
>[number]
|
||||
>((difference) => {
|
||||
switch (difference.type) {
|
||||
case 'CHANGE': {
|
||||
const { oldValue, path, value } = difference;
|
||||
const property = path[0] as PToCompare;
|
||||
const isJsonb = propertiesToStringify.includes(
|
||||
property as unknown as PJsonB,
|
||||
);
|
||||
|
||||
if (isJsonb) {
|
||||
return {
|
||||
from: parseJson(oldValue),
|
||||
to: parseJson(value),
|
||||
property,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
from: oldValue,
|
||||
to: value,
|
||||
property,
|
||||
};
|
||||
}
|
||||
case 'CREATE':
|
||||
case 'REMOVE':
|
||||
default: {
|
||||
// Should never occurs, we should only provide null never undefined and so on
|
||||
return [];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
import { type AllFlatEntities } from 'src/engine/core-modules/common/types/all-flat-entities.type';
|
||||
import { orderObjectProperties } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/order-object-properties.util';
|
||||
|
||||
export function transformFlatEntityForComparison<
|
||||
TFlatEntity extends AllFlatEntities,
|
||||
PToCompare extends keyof TFlatEntity,
|
||||
PJsonB extends keyof TFlatEntity,
|
||||
>({
|
||||
flatEntity,
|
||||
options: { propertiesToCompare, propertiesToStringify },
|
||||
}: {
|
||||
flatEntity: TFlatEntity;
|
||||
options: {
|
||||
propertiesToCompare: PToCompare[];
|
||||
propertiesToStringify: PJsonB[];
|
||||
};
|
||||
}) {
|
||||
return propertiesToCompare.reduce(
|
||||
(flatEntityAccumulator, propertyToCompare) => {
|
||||
const currentValue = flatEntity[propertyToCompare];
|
||||
|
||||
if (
|
||||
propertiesToStringify.includes(propertyToCompare as unknown as PJsonB)
|
||||
) {
|
||||
const orderedValue = orderObjectProperties(currentValue);
|
||||
|
||||
return {
|
||||
...flatEntityAccumulator,
|
||||
[propertyToCompare]: JSON.stringify(orderedValue),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...flatEntityAccumulator,
|
||||
[propertyToCompare]: currentValue,
|
||||
};
|
||||
},
|
||||
{} as Pick<TFlatEntity, PToCompare>,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user