Object metadata API create one using workspace migration v2 (#13420)

# Introduction
In this PR we create basic transpilation methods and utils to handle
input to flat, entity to flat, object maps to flat. In order to
transpile everything into a common validation that will be implemented
in another PR

## FieldMetadataEntity typing
Added `never | null` to fields that should never be in order to ease
general abstracted method to pass null, as anw it's what is in the
database

## Todo
- ~~Create a feature flag~~
- Integration test for object creation through metadata api + pg col
introspection and snapshoting
This commit is contained in:
Paul Rastoin
2025-07-29 17:47:28 +02:00
committed by GitHub
parent 600df4fd90
commit c1bf0a1fbf
66 changed files with 1224 additions and 164 deletions
@@ -76,7 +76,7 @@ export type FieldMetadataDefaultValue<
? FieldMetadataDefaultValueForAnyType | null // Could be improved to be | unknown
: T extends keyof FieldMetadataDefaultValueMapping
? FieldMetadataDefaultValueForType<T>
: never;
: never | null;
type FieldMetadataDefaultValueExtractedTypes = {
[K in keyof FieldMetadataDefaultValueMapping]: ExtractValueType<
@@ -18,4 +18,4 @@ export type FieldMetadataOptions<
? null | (FieldMetadataDefaultOption[] | FieldMetadataComplexOption[]) // Could be improved to be | unknown
: T extends keyof FieldMetadataOptionsMapping
? FieldMetadataOptionsMapping[T]
: never;
: never | null;
@@ -60,4 +60,4 @@ export type FieldMetadataSettings<
? null | AllFieldMetadataSettings // Could be improved to be | unknown
: T extends keyof FieldMetadataSettingsMapping
? FieldMetadataSettingsMapping[T] | null
: never;
: never | null;
@@ -10,4 +10,4 @@ export type AssignTypeIfIsRelationFieldMetadataType<
? Ttype
: T extends FieldMetadataType.MORPH_RELATION
? Ttype
: never;
: never | null;
@@ -2,6 +2,10 @@ import { Expect, HasAllProperties } from 'twenty-shared/testing';
import { FieldMetadataType, NullablePartial } from 'twenty-shared/types';
import { Relation as TypeOrmRelation } from 'typeorm';
import {
FieldMetadataDefaultValueForAnyType,
FieldMetadataDefaultValueForType,
} from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
import {
AllFieldMetadataSettings,
FieldMetadataDateSettings,
@@ -10,10 +14,6 @@ import {
FieldMetadataRelationSettings,
FieldMetadataTextSettings,
} from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import {
FieldMetadataDefaultValueForAnyType,
FieldMetadataDefaultValueForType,
} from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
import {
FieldMetadataComplexOption,
@@ -30,10 +30,10 @@ type DefinedRelationRecord = {
};
type NotDefinedRelationRecord = {
relationTargetFieldMetadataId: never;
relationTargetFieldMetadata: never;
relationTargetObjectMetadataId: never;
relationTargetObjectMetadata: never;
relationTargetFieldMetadataId: never | null;
relationTargetFieldMetadata: never | null;
relationTargetObjectMetadataId: never | null;
relationTargetObjectMetadata: never | null;
};
type AbstractFieldMetadata = FieldMetadataEntity<FieldMetadataType>;
@@ -115,23 +115,27 @@ type RelationAssertions = [
>,
];
type NotDefinedSettings = {
settings: never | null;
};
// eslint-disable-next-line unused-imports/no-unused-vars, @typescript-eslint/no-unused-vars
type SettingsAssertions = [
Expect<HasAllProperties<CurrencyFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<FullNameFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<RatingFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<SelectFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<MultiSelectFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<PositionFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<RawJsonFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<RichTextFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<ActorFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<ArrayFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<PhonesFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<EmailsFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<LinksFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<UUIDFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<BooleanFieldMetadata, { settings: never }>>,
Expect<HasAllProperties<CurrencyFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<FullNameFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<RatingFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<SelectFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<MultiSelectFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<PositionFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<RawJsonFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<RichTextFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<ActorFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<ArrayFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<PhonesFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<EmailsFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<LinksFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<UUIDFieldMetadata, NotDefinedSettings>>,
Expect<HasAllProperties<BooleanFieldMetadata, NotDefinedSettings>>,
Expect<
HasAllProperties<
@@ -328,8 +332,12 @@ type DefaultValueAssertions = [
>
>,
Expect<HasAllProperties<RelationFieldMetadata, { defaultValue: never }>>,
Expect<HasAllProperties<MorphRelationFieldMetadata, { defaultValue: never }>>,
Expect<
HasAllProperties<RelationFieldMetadata, { defaultValue: never | null }>
>,
Expect<
HasAllProperties<MorphRelationFieldMetadata, { defaultValue: never | null }>
>,
Expect<
HasAllProperties<
@@ -339,6 +347,10 @@ type DefaultValueAssertions = [
>,
];
type NotDefinedOptions = {
options: never | null;
};
// eslint-disable-next-line unused-imports/no-unused-vars, @typescript-eslint/no-unused-vars
type OptionsAssertions = [
Expect<
@@ -360,25 +372,24 @@ type OptionsAssertions = [
>
>,
Expect<HasAllProperties<UUIDFieldMetadata, { options: never }>>,
Expect<HasAllProperties<TextFieldMetadata, { options: never }>>,
Expect<HasAllProperties<NumberFieldMetadata, { options: never }>>,
Expect<HasAllProperties<BooleanFieldMetadata, { options: never }>>,
Expect<HasAllProperties<DateFieldMetadata, { options: never }>>,
Expect<HasAllProperties<DateTimeFieldMetadata, { options: never }>>,
Expect<HasAllProperties<CurrencyFieldMetadata, { options: never }>>,
Expect<HasAllProperties<FullNameFieldMetadata, { options: never }>>,
Expect<HasAllProperties<PositionFieldMetadata, { options: never }>>,
Expect<HasAllProperties<RawJsonFieldMetadata, { options: never }>>,
Expect<HasAllProperties<RichTextFieldMetadata, { options: never }>>,
Expect<HasAllProperties<ActorFieldMetadata, { options: never }>>,
Expect<HasAllProperties<ArrayFieldMetadata, { options: never }>>,
Expect<HasAllProperties<PhonesFieldMetadata, { options: never }>>,
Expect<HasAllProperties<EmailsFieldMetadata, { options: never }>>,
Expect<HasAllProperties<LinksFieldMetadata, { options: never }>>,
Expect<HasAllProperties<RelationFieldMetadata, { options: never }>>,
Expect<HasAllProperties<MorphRelationFieldMetadata, { options: never }>>,
Expect<HasAllProperties<UUIDFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<TextFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<NumberFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<BooleanFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<DateFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<DateTimeFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<CurrencyFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<FullNameFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<PositionFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<RawJsonFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<RichTextFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<ActorFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<ArrayFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<PhonesFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<EmailsFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<LinksFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<RelationFieldMetadata, NotDefinedOptions>>,
Expect<HasAllProperties<MorphRelationFieldMetadata, NotDefinedOptions>>,
Expect<
HasAllProperties<
@@ -1,11 +1,11 @@
import { v4 } from 'uuid';
import { trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties } from 'twenty-shared/utils';
import {
FieldMetadataComplexOption,
FieldMetadataDefaultOption,
} from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties } from 'src/utils/trim-and-remove-duplicated-whitespaces-from-object-string-properties';
export const prepareCustomFieldMetadataOptions = (
options: FieldMetadataDefaultOption[] | FieldMetadataComplexOption[],