Workspace schema migration runner v2 (#13899)

This commit is contained in:
Weiko
2025-08-14 15:58:25 +02:00
committed by GitHub
parent c1885233bc
commit 1707e00ad4
47 changed files with 4098 additions and 3354 deletions
@@ -0,0 +1,18 @@
import { FieldMetadataType } from 'twenty-shared/types';
const compositeFieldTypes = [
FieldMetadataType.ADDRESS,
FieldMetadataType.CURRENCY,
FieldMetadataType.FULL_NAME,
FieldMetadataType.LINKS,
FieldMetadataType.EMAILS,
FieldMetadataType.PHONES,
FieldMetadataType.RICH_TEXT_V2,
FieldMetadataType.ACTOR,
] as const;
export type CompositeFieldMetadataType = (typeof compositeFieldTypes)[number];
export const COMPOSITE_FIELD_TYPES: CompositeFieldMetadataType[] = [
...compositeFieldTypes,
];
@@ -0,0 +1,11 @@
import { FieldMetadataType } from 'twenty-shared/types';
const enumFieldTypes = [
FieldMetadataType.SELECT,
FieldMetadataType.MULTI_SELECT,
FieldMetadataType.RATING,
] as const;
export type EnumFieldMetadataType = (typeof enumFieldTypes)[number];
export const ENUM_FIELD_TYPES: EnumFieldMetadataType[] = [...enumFieldTypes];
@@ -0,0 +1,12 @@
import { FieldMetadataType } from 'twenty-shared/types';
const relationFieldTypes = [
FieldMetadataType.RELATION,
FieldMetadataType.MORPH_RELATION,
] as const;
export type RelationFieldMetadataType = (typeof relationFieldTypes)[number];
export const RELATION_FIELD_TYPES: RelationFieldMetadataType[] = [
...relationFieldTypes,
];
@@ -0,0 +1,24 @@
import { type FieldMetadataType } from 'twenty-shared/types';
import { type CompositeType } from 'src/engine/metadata-modules/field-metadata/interfaces/composite-type.interface';
import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types';
import {
FieldMetadataException,
FieldMetadataExceptionCode,
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
export const getCompositeTypeOrThrow = (
fieldType: FieldMetadataType,
): CompositeType => {
const compositeType = compositeTypeDefinitions.get(fieldType);
if (!compositeType) {
throw new FieldMetadataException(
`Composite type not found for field metadata type: ${fieldType}`,
FieldMetadataExceptionCode.UNCOVERED_FIELD_METADATA_TYPE_VALIDATION,
);
}
return compositeType;
};
@@ -4,7 +4,7 @@ export const unserializeDefaultValue = (
serializedDefaultValue: FieldMetadataDefaultSerializableValue,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): any => {
if (serializedDefaultValue === null) {
if (serializedDefaultValue === undefined || serializedDefaultValue === null) {
return null;
}
@@ -0,0 +1,11 @@
import {
COMPOSITE_FIELD_TYPES,
type CompositeFieldMetadataType,
} from 'src/engine/metadata-modules/field-metadata/types/composite-field-metadata-type.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isFlatFieldMetadataEntityOfTypes } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-falt-field-metadata-of-types.util';
export const isCompositeFlatFieldMetadata = (
flatFieldMetadata: FlatFieldMetadata,
): flatFieldMetadata is FlatFieldMetadata<CompositeFieldMetadataType> =>
isFlatFieldMetadataEntityOfTypes(flatFieldMetadata, COMPOSITE_FIELD_TYPES);
@@ -0,0 +1,11 @@
import {
ENUM_FIELD_TYPES,
type EnumFieldMetadataType,
} from 'src/engine/metadata-modules/field-metadata/types/enum-field-metadata-type.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isFlatFieldMetadataEntityOfTypes } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-falt-field-metadata-of-types.util';
export const isEnumFlatFieldMetadata = (
flatFieldMetadata: FlatFieldMetadata,
): flatFieldMetadata is FlatFieldMetadata<EnumFieldMetadataType> =>
isFlatFieldMetadataEntityOfTypes(flatFieldMetadata, ENUM_FIELD_TYPES);
@@ -0,0 +1,13 @@
import { type FieldMetadataType } from 'twenty-shared/types';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
export function isFlatFieldMetadataEntityOfTypes<
Field extends FlatFieldMetadata<FieldMetadataType>,
Types extends FieldMetadataType[],
>(
fieldMetadata: Pick<Field, 'type'>,
types: Types,
): fieldMetadata is Field & FlatFieldMetadata<Types[number]> {
return types.includes(fieldMetadata.type);
}
@@ -0,0 +1,11 @@
import {
RELATION_FIELD_TYPES,
type RelationFieldMetadataType,
} from 'src/engine/metadata-modules/field-metadata/types/relation-field-metadata-type.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isFlatFieldMetadataEntityOfTypes } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-falt-field-metadata-of-types.util';
export const isRelationFlatFieldMetadata = (
flatFieldMetadata: FlatFieldMetadata,
): flatFieldMetadata is FlatFieldMetadata<RelationFieldMetadataType> =>
isFlatFieldMetadataEntityOfTypes(flatFieldMetadata, RELATION_FIELD_TYPES);
@@ -0,0 +1,32 @@
import { isDefined } from 'twenty-shared/utils';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import {
FlatObjectMetadataMapsException,
FlatObjectMetadataMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/flat-object-metadata-maps.exception';
import {
findFlatFieldMetadataInFlatObjectMetadataMaps,
type FindFlatFieldMetadataInFlatObjectMetadataMapsArgs,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps.util';
export const findFlatFieldMetadataInFlatObjectMetadataMapsOrThrow = ({
flatObjectMetadataMaps,
fieldMetadataId,
objectMetadataId,
}: FindFlatFieldMetadataInFlatObjectMetadataMapsArgs): FlatFieldMetadata => {
const flatFieldMetadata = findFlatFieldMetadataInFlatObjectMetadataMaps({
flatObjectMetadataMaps,
fieldMetadataId,
objectMetadataId,
});
if (!isDefined(flatFieldMetadata)) {
throw new FlatObjectMetadataMapsException(
'flat field metadata not found in flat object metadata maps',
FlatObjectMetadataMapsExceptionCode.FIELD_METADATA_NOT_FOUND,
);
}
return flatFieldMetadata;
};
@@ -0,0 +1,32 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatObjectMetadataMapsException,
FlatObjectMetadataMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/flat-object-metadata-maps.exception';
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { findFlatObjectMetadataInFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-in-flat-object-metadata-maps.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
export type FindFlatObjectMetadataInFlatObjectMetadataMapsArgs = {
objectMetadataId: string;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
};
export const findFlatObjectMetadataInFlatObjectMetadataMapsOrThrow = ({
flatObjectMetadataMaps,
objectMetadataId,
}: FindFlatObjectMetadataInFlatObjectMetadataMapsArgs): FlatObjectMetadata => {
const flatObjectMetadata = findFlatObjectMetadataInFlatObjectMetadataMaps({
flatObjectMetadataMaps,
objectMetadataId,
});
if (!isDefined(flatObjectMetadata)) {
throw new FlatObjectMetadataMapsException(
'flat object metadata not found in flat object metadata maps',
FlatObjectMetadataMapsExceptionCode.OBJECT_METADATA_NOT_FOUND,
);
}
return flatObjectMetadata;
};
@@ -1,6 +1,7 @@
import { isDefined } from 'twenty-shared/utils';
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-with-flat-field-maps-in-flat-object-metadata-maps.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { fromFlatObjectMetadataWithFlatFieldMapsToFlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-with-flat-field-maps-to-flat-object-metadatas.util';
@@ -15,7 +16,10 @@ export const findFlatObjectMetadataInFlatObjectMetadataMaps = ({
| FlatObjectMetadata
| undefined => {
const flatObjectMetadataWithFlatFieldMaps =
flatObjectMetadataMaps.byId[objectMetadataId];
findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMaps({
flatObjectMetadataMaps,
objectMetadataId,
});
if (!isDefined(flatObjectMetadataWithFlatFieldMaps)) {
return undefined;
@@ -0,0 +1,32 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatObjectMetadataMapsException,
FlatObjectMetadataMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/flat-object-metadata-maps.exception';
import { type FlatObjectMetadataWithFlatFieldMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-with-flat-field-metadata-maps.type';
import {
type FindFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsArgs,
findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMaps,
} from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-with-flat-field-maps-in-flat-object-metadata-maps.util';
export const findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsOrThrow =
({
flatObjectMetadataMaps,
objectMetadataId,
}: FindFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsArgs): FlatObjectMetadataWithFlatFieldMaps => {
const flatObjectMetadataWithFlatFieldMaps =
findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMaps({
flatObjectMetadataMaps,
objectMetadataId,
});
if (!isDefined(flatObjectMetadataWithFlatFieldMaps)) {
throw new FlatObjectMetadataMapsException(
'flat object metadata with flat field maps not found in flat object metadata maps',
FlatObjectMetadataMapsExceptionCode.OBJECT_METADATA_NOT_FOUND,
);
}
return flatObjectMetadataWithFlatFieldMaps;
};
@@ -0,0 +1,27 @@
import { isDefined } from 'twenty-shared/utils';
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
import { type FlatObjectMetadataWithFlatFieldMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-with-flat-field-metadata-maps.type';
export type FindFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsArgs =
{
objectMetadataId: string;
flatObjectMetadataMaps: FlatObjectMetadataMaps;
};
export const findFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMaps =
({
flatObjectMetadataMaps,
objectMetadataId,
}: FindFlatObjectMetadataWithFlatFieldMapsInFlatObjectMetadataMapsArgs):
| FlatObjectMetadataWithFlatFieldMaps
| undefined => {
const flatObjectMetadataWithFlatFieldMaps =
flatObjectMetadataMaps.byId[objectMetadataId];
if (!isDefined(flatObjectMetadataWithFlatFieldMaps)) {
return undefined;
}
return flatObjectMetadataWithFlatFieldMaps;
};
@@ -19,6 +19,7 @@ import {
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.exception';
// TODO: could we export this to GraphQL ?
// TOOD: once this module is removed, replace existing usages with CompositeFieldMetadataType from composite-field-metadata-type.type.ts
export type CompositeFieldMetadataType =
| FieldMetadataType.ADDRESS
| FieldMetadataType.CURRENCY