[TYPES] UniversalEntity JsonbProperty and SerializedRelation (#17396)
# Introduction
In this PR we're introducing mainly two branded type signatures for both
`JsonbProperty` entities properties and `SerializedRelation` (jsonb
serialized property storing another entity id).
Allowing to dynamically map over them later in order to build universal
`jsonb` `serialized` relations.
## `JsonbProperty`
A branded wrapper type that marks entity properties stored as PostgreSQL
JSONB columns. It adds a phantom brand `__JsonbPropertyBrand__` to
object types while leaving primitives unchanged. The branded key is
optional and typed as never, also omitted when transpiled to
`UniversalFlat`
**Should be used at entities lvl only:**
```typescript
@Column({ type: 'jsonb', nullable: false })
gridPosition: JsonbProperty<GridPosition>;
@Column({ nullable: false, type: 'jsonb', default: [] })
publishedVersions: JsonbProperty<string[]>;
```
## `SerializedRelation`
A branded string type that marks foreign key IDs stored inside JSONB
objects. These are entity references serialized within a JSONB column
rather than being a regular database foreign key.
**Usage in jsonb property generic***
```ts
type FieldMetadataRelationSettings = {
relationType: RelationType;
onDelete?: RelationOnDeleteAction;
joinColumnName?: string | null;
junctionTargetFieldId?: SerializedRelation;
};
```
## `FormatJsonbSerializedRelation<T>`
A transformation type that processes JSONB properties for universal
entity mapping. It:
1. Detects properties with the `JsonbProperty` brand
2. Finds `SerializedRelation` properties
3. Renames them from `*Id` to `*UniversalIdentifier`
4. Removes the brand from the output type ( optional though )
```typescript
// Input: JsonbProperty<{ targetFieldMetadataId: SerializedRelation }>
// Output: { targetFieldMetadataUniversalIdentifier: SerializedRelation }
```
## Result
An example of the dynamic type mapping, through a type-test example
```ts
type SettingsTestCase = UniversalFlatFieldMetadata<
| FieldMetadataType.RELATION
| FieldMetadataType.NUMBER
| FieldMetadataType.TEXT
>['settings']
type SettingsExpectedResult =
| {
relationType: RelationType;
onDelete?: RelationOnDeleteAction | undefined;
joinColumnName?: string | null | undefined;
junctionTargetFieldUniversalIdentifier?: SerializedRelation | undefined;
}
| {
dataType?: NumberDataType | undefined;
decimals?: number | undefined;
type?: FieldNumberVariant | undefined;
}
| {
displayedMaxRows?: number | undefined;
}
| null;
type Assertions = [
Expect<Equal<SettingsTestCase, SettingsExpectedResult>>,
]
```
## Remarks
- Removed duplicated twenty-server and twenty-shared typed
- Removed class validator instances for default value that were not used
at runtime, we will refactor that to add validation across all entities
following a same pattern
This commit is contained in:
+71
@@ -0,0 +1,71 @@
|
||||
import { type Equal, type Expect } from 'twenty-shared/testing';
|
||||
|
||||
import { type ExtractJsonbProperties } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/extract-jsonb-properties.type';
|
||||
import { type JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
type EmptyObject = {};
|
||||
|
||||
type TestedRecord = {
|
||||
// Non-JsonbProperty fields
|
||||
plainString: string;
|
||||
plainNumber: number;
|
||||
plainObject: EmptyObject;
|
||||
plainObjectNullable: EmptyObject | null;
|
||||
plainArray: string[];
|
||||
plainUnknown: unknown;
|
||||
jsonbString: JsonbProperty<string>;
|
||||
jsonbPlainUnknown: JsonbProperty<unknown>;
|
||||
jsonbNumber: JsonbProperty<number>;
|
||||
jsonbull: JsonbProperty<null>;
|
||||
|
||||
// JsonbProperty fields - should be extracted
|
||||
jsonbPlainObject: JsonbProperty<EmptyObject>;
|
||||
jsonbPlainArray: JsonbProperty<string[]>;
|
||||
jsonbPlainObjectNullable: JsonbProperty<EmptyObject | null>;
|
||||
jsonbEmpty: JsonbProperty<EmptyObject>;
|
||||
jsonbArray: JsonbProperty<string[]>;
|
||||
jsonbNested: JsonbProperty<{ nested: { deep: number } }>;
|
||||
jsonbNullable: JsonbProperty<EmptyObject> | null;
|
||||
jsonbUndefinable: JsonbProperty<EmptyObject> | undefined;
|
||||
jsonbOptional?: JsonbProperty<EmptyObject>;
|
||||
jsonbInnerNullable: JsonbProperty<EmptyObject | null>;
|
||||
jsonbInnerUndefinable: JsonbProperty<EmptyObject | undefined>;
|
||||
jsonbUnionWithPrimitive: JsonbProperty<EmptyObject> | string | null;
|
||||
jsonbInnerNullableWithProperties: JsonbProperty<null | { value: string }>;
|
||||
wrongUsageButPassing:
|
||||
| JsonbProperty<null | { value: string }>
|
||||
| string
|
||||
| { foo: string };
|
||||
};
|
||||
|
||||
type TestResult = ExtractJsonbProperties<TestedRecord>;
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type Assertions = [
|
||||
Expect<
|
||||
Equal<
|
||||
TestResult,
|
||||
| 'jsonbPlainObject'
|
||||
| 'jsonbPlainArray'
|
||||
| 'jsonbPlainObjectNullable'
|
||||
| 'jsonbEmpty'
|
||||
| 'jsonbArray'
|
||||
| 'jsonbNested'
|
||||
| 'jsonbNullable'
|
||||
| 'jsonbUndefinable'
|
||||
| 'jsonbOptional'
|
||||
| 'jsonbInnerNullable'
|
||||
| 'jsonbInnerUndefinable'
|
||||
| 'jsonbInnerNullableWithProperties'
|
||||
| 'jsonbUnionWithPrimitive'
|
||||
| 'wrongUsageButPassing'
|
||||
>
|
||||
>,
|
||||
|
||||
// Empty object returns never
|
||||
Expect<Equal<ExtractJsonbProperties<EmptyObject>, never>>,
|
||||
|
||||
// Object with no JsonbProperty fields returns never
|
||||
Expect<Equal<ExtractJsonbProperties<{ a: string; b: number }>, never>>,
|
||||
];
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
import { type Equal, type Expect } from 'twenty-shared/testing';
|
||||
import { type SerializedRelation } from 'twenty-shared/types';
|
||||
|
||||
import { type FormatJsonbSerializedRelation } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/format-jsonb-serialized-relation.type';
|
||||
import {
|
||||
type JSONB_PROPERTY_BRAND,
|
||||
type JsonbProperty,
|
||||
} from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
|
||||
type BrandedObjectWithRelation = JsonbProperty<{
|
||||
name: string;
|
||||
targetFieldMetadataId: SerializedRelation;
|
||||
}>;
|
||||
|
||||
type BrandedObjectWithoutRelation = JsonbProperty<{
|
||||
name: string;
|
||||
count: number;
|
||||
}>;
|
||||
|
||||
type UnbrandedObject = {
|
||||
name: string;
|
||||
targetFieldMetadataId: SerializedRelation;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type BrandedObjectAssertions = [
|
||||
// Branded object with SerializedRelation: Id suffix renamed to UniversalIdentifier
|
||||
Expect<
|
||||
Equal<
|
||||
FormatJsonbSerializedRelation<BrandedObjectWithRelation>,
|
||||
{
|
||||
name: string;
|
||||
targetFieldMetadataUniversalIdentifier: SerializedRelation;
|
||||
}
|
||||
>
|
||||
>,
|
||||
|
||||
// Branded object without SerializedRelation: no renaming, just removes brand
|
||||
Expect<
|
||||
Equal<
|
||||
FormatJsonbSerializedRelation<BrandedObjectWithoutRelation>,
|
||||
{
|
||||
name: string;
|
||||
count: number;
|
||||
}
|
||||
>
|
||||
>,
|
||||
];
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type UnbrandedObjectAssertions = [
|
||||
// Unbranded objects pass through unchanged
|
||||
Expect<
|
||||
Equal<FormatJsonbSerializedRelation<UnbrandedObject>, UnbrandedObject>
|
||||
>,
|
||||
];
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type PrimitiveAssertions = [
|
||||
// Primitives pass through unchanged
|
||||
Expect<Equal<FormatJsonbSerializedRelation<string>, string>>,
|
||||
Expect<Equal<FormatJsonbSerializedRelation<number>, number>>,
|
||||
Expect<Equal<FormatJsonbSerializedRelation<null>, null>>,
|
||||
];
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type ArrayAssertions = [
|
||||
// Array of branded objects: transforms each element
|
||||
Expect<
|
||||
Equal<
|
||||
FormatJsonbSerializedRelation<BrandedObjectWithRelation[]>,
|
||||
{
|
||||
name: string;
|
||||
targetFieldMetadataUniversalIdentifier: SerializedRelation;
|
||||
}[]
|
||||
>
|
||||
>,
|
||||
|
||||
// Array of unbranded objects: passes through unchanged
|
||||
Expect<
|
||||
Equal<FormatJsonbSerializedRelation<UnbrandedObject[]>, UnbrandedObject[]>
|
||||
>,
|
||||
|
||||
// Array of primitives: passes through unchanged
|
||||
Expect<Equal<FormatJsonbSerializedRelation<string[]>, string[]>>,
|
||||
|
||||
// Nested array of branded objects: transforms innermost elements
|
||||
Expect<
|
||||
Equal<
|
||||
FormatJsonbSerializedRelation<BrandedObjectWithRelation[][]>,
|
||||
{
|
||||
name: string;
|
||||
targetFieldMetadataUniversalIdentifier: SerializedRelation;
|
||||
}[][]
|
||||
>
|
||||
>,
|
||||
|
||||
// Array of unbranded and branded objects union: transforms branded element
|
||||
Expect<
|
||||
Equal<
|
||||
FormatJsonbSerializedRelation<
|
||||
(BrandedObjectWithRelation | UnbrandedObject)[]
|
||||
>,
|
||||
(
|
||||
| {
|
||||
name: string;
|
||||
targetFieldMetadataUniversalIdentifier: SerializedRelation;
|
||||
}
|
||||
| UnbrandedObject
|
||||
)[]
|
||||
>
|
||||
>,
|
||||
];
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type UnionAssertions = [
|
||||
// Union with null: transforms branded object, keeps null
|
||||
Expect<
|
||||
Equal<
|
||||
FormatJsonbSerializedRelation<BrandedObjectWithRelation | null>,
|
||||
{
|
||||
name: string;
|
||||
targetFieldMetadataUniversalIdentifier: SerializedRelation;
|
||||
} | null
|
||||
>
|
||||
>,
|
||||
|
||||
// Array of union: transforms elements appropriately
|
||||
Expect<
|
||||
Equal<
|
||||
FormatJsonbSerializedRelation<(BrandedObjectWithRelation | null)[]>,
|
||||
({
|
||||
name: string;
|
||||
targetFieldMetadataUniversalIdentifier: SerializedRelation;
|
||||
} | null)[]
|
||||
>
|
||||
>,
|
||||
];
|
||||
|
||||
type MultipleRelationsObject = JsonbProperty<{
|
||||
name: string;
|
||||
sourceFieldId: SerializedRelation;
|
||||
targetFieldId: SerializedRelation;
|
||||
regularId: string;
|
||||
}>;
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type MultipleRelationsAssertions = [
|
||||
// Multiple SerializedRelation properties: all get renamed
|
||||
Expect<
|
||||
Equal<
|
||||
FormatJsonbSerializedRelation<MultipleRelationsObject>,
|
||||
{
|
||||
name: string;
|
||||
sourceFieldUniversalIdentifier: SerializedRelation;
|
||||
targetFieldUniversalIdentifier: SerializedRelation;
|
||||
regularId: string;
|
||||
}
|
||||
>
|
||||
>,
|
||||
];
|
||||
|
||||
// Verify brand is removed
|
||||
type BrandRemovedCheck =
|
||||
FormatJsonbSerializedRelation<BrandedObjectWithRelation>;
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type BrandRemovedAssertion = Expect<
|
||||
Equal<
|
||||
typeof JSONB_PROPERTY_BRAND extends keyof BrandRemovedCheck ? true : false,
|
||||
false
|
||||
>
|
||||
>;
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
import { type Equal, type Expect } from 'twenty-shared/testing';
|
||||
|
||||
import {
|
||||
type JSONB_PROPERTY_BRAND,
|
||||
type JsonbProperty,
|
||||
} from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
type EmptyObject = {};
|
||||
|
||||
type SimpleObject = { value: string };
|
||||
|
||||
type NestedObject = { nested: { deep: number } };
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type PrimitiveAssertions = [
|
||||
// Primitives pass through unchanged (not objects)
|
||||
Expect<Equal<JsonbProperty<string>, string>>,
|
||||
Expect<Equal<JsonbProperty<number>, number>>,
|
||||
Expect<Equal<JsonbProperty<boolean>, boolean>>,
|
||||
Expect<Equal<JsonbProperty<null>, null>>,
|
||||
Expect<Equal<JsonbProperty<undefined>, undefined>>,
|
||||
];
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type ObjectAssertions = [
|
||||
// Objects get branded
|
||||
Expect<
|
||||
Equal<
|
||||
JsonbProperty<SimpleObject>,
|
||||
SimpleObject & { [JSONB_PROPERTY_BRAND]?: never }
|
||||
>
|
||||
>,
|
||||
Expect<
|
||||
Equal<
|
||||
JsonbProperty<NestedObject>,
|
||||
NestedObject & { [JSONB_PROPERTY_BRAND]?: never }
|
||||
>
|
||||
>,
|
||||
Expect<
|
||||
Equal<
|
||||
JsonbProperty<EmptyObject>,
|
||||
EmptyObject & { [JSONB_PROPERTY_BRAND]?: never }
|
||||
>
|
||||
>,
|
||||
];
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type ArrayAssertions = [
|
||||
// Arrays are objects, so they get branded on the array itself
|
||||
Expect<
|
||||
Equal<
|
||||
JsonbProperty<string[]>,
|
||||
string[] & { [JSONB_PROPERTY_BRAND]?: never }
|
||||
>
|
||||
>,
|
||||
Expect<
|
||||
Equal<
|
||||
JsonbProperty<number[]>,
|
||||
number[] & { [JSONB_PROPERTY_BRAND]?: never }
|
||||
>
|
||||
>,
|
||||
Expect<
|
||||
Equal<
|
||||
JsonbProperty<SimpleObject[]>,
|
||||
SimpleObject[] & { [JSONB_PROPERTY_BRAND]?: never }
|
||||
>
|
||||
>,
|
||||
];
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type UnionAssertions = [
|
||||
// Union of object and null: object gets branded, null passes through
|
||||
Expect<
|
||||
Equal<
|
||||
JsonbProperty<SimpleObject | null>,
|
||||
(SimpleObject & { [JSONB_PROPERTY_BRAND]?: never }) | null
|
||||
>
|
||||
>,
|
||||
|
||||
// Union of objects: both get branded (distributive conditional)
|
||||
Expect<
|
||||
Equal<
|
||||
JsonbProperty<SimpleObject | NestedObject>,
|
||||
| (SimpleObject & { [JSONB_PROPERTY_BRAND]?: never })
|
||||
| (NestedObject & { [JSONB_PROPERTY_BRAND]?: never })
|
||||
>
|
||||
>,
|
||||
|
||||
// Array in union: array gets branded
|
||||
Expect<
|
||||
Equal<
|
||||
JsonbProperty<SimpleObject[] | null>,
|
||||
(SimpleObject[] & { [JSONB_PROPERTY_BRAND]?: never }) | null
|
||||
>
|
||||
>,
|
||||
];
|
||||
+78
-1
@@ -1,7 +1,18 @@
|
||||
import { type Expect, type HasAllProperties } from 'twenty-shared/testing';
|
||||
import {
|
||||
type Equal,
|
||||
type Expect,
|
||||
type HasAllProperties,
|
||||
} from 'twenty-shared/testing';
|
||||
import {
|
||||
type FieldMetadataDefaultOption,
|
||||
type FieldMetadataType,
|
||||
type FieldNumberVariant,
|
||||
type LinkMetadata,
|
||||
type NullablePartial,
|
||||
type NumberDataType,
|
||||
type RelationOnDeleteAction,
|
||||
type RelationType,
|
||||
type SerializedRelation,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
|
||||
@@ -79,3 +90,69 @@ type UniversalFlatTransformationAssertions = [
|
||||
>
|
||||
>,
|
||||
];
|
||||
|
||||
type NarrowedTestCase =
|
||||
UniversalFlatFieldMetadata<FieldMetadataType.RELATION>['settings'];
|
||||
|
||||
type NarrowedExpectedResult = {
|
||||
relationType: RelationType;
|
||||
onDelete?: RelationOnDeleteAction | undefined;
|
||||
joinColumnName?: string | null | undefined;
|
||||
junctionTargetFieldUniversalIdentifier?: SerializedRelation | undefined;
|
||||
};
|
||||
|
||||
type SettingsTestCase = UniversalFlatFieldMetadata<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.NUMBER | FieldMetadataType.TEXT
|
||||
>['settings'];
|
||||
|
||||
type SettingsExpectedResult =
|
||||
| {
|
||||
relationType: RelationType;
|
||||
onDelete?: RelationOnDeleteAction | undefined;
|
||||
joinColumnName?: string | null | undefined;
|
||||
junctionTargetFieldUniversalIdentifier?: SerializedRelation | undefined;
|
||||
}
|
||||
| {
|
||||
dataType?: NumberDataType | undefined;
|
||||
decimals?: number | undefined;
|
||||
type?: FieldNumberVariant | undefined;
|
||||
}
|
||||
| {
|
||||
displayedMaxRows?: number | undefined;
|
||||
}
|
||||
| null;
|
||||
|
||||
type DefaultValueTestCase = UniversalFlatFieldMetadata<
|
||||
| FieldMetadataType.RELATION
|
||||
| FieldMetadataType.NUMBER
|
||||
| FieldMetadataType.TEXT
|
||||
| FieldMetadataType.LINKS
|
||||
| FieldMetadataType.CURRENCY
|
||||
>['defaultValue'];
|
||||
|
||||
type DefaultValueExpectedResult =
|
||||
| string
|
||||
| number
|
||||
| null
|
||||
| {
|
||||
amountMicros: string | null;
|
||||
currencyCode: string | null;
|
||||
}
|
||||
| {
|
||||
primaryLinkLabel: string | null;
|
||||
primaryLinkUrl: string | null;
|
||||
secondaryLinks: LinkMetadata[] | null;
|
||||
};
|
||||
|
||||
type OptionsTestCase =
|
||||
UniversalFlatFieldMetadata<FieldMetadataType.RATING>['options'];
|
||||
|
||||
type OptionsExpectedResult = FieldMetadataDefaultOption[];
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type Assertions = [
|
||||
Expect<Equal<SettingsTestCase, SettingsExpectedResult>>,
|
||||
Expect<Equal<NarrowedTestCase, NarrowedExpectedResult>>,
|
||||
Expect<Equal<DefaultValueTestCase, DefaultValueExpectedResult>>,
|
||||
Expect<Equal<OptionsTestCase, OptionsExpectedResult>>,
|
||||
];
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { type JSONB_PROPERTY_BRAND } from './jsonb-property.type';
|
||||
|
||||
export type HasJsonbPropertyBrand<T> =
|
||||
typeof JSONB_PROPERTY_BRAND extends keyof T ? true : false;
|
||||
|
||||
// Distributive check: returns `true` if any member of a union has the brand
|
||||
type HasJsonbBrandInUnion<T> = T extends unknown
|
||||
? HasJsonbPropertyBrand<T>
|
||||
: never;
|
||||
|
||||
export type ExtractJsonbProperties<T> = NonNullable<
|
||||
{
|
||||
[P in keyof T]-?: true extends HasJsonbBrandInUnion<NonNullable<T[P]>>
|
||||
? P
|
||||
: never;
|
||||
}[keyof T]
|
||||
>;
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { type ExtractSerializedRelationProperties } from 'twenty-shared/types';
|
||||
|
||||
import { type HasJsonbPropertyBrand } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/extract-jsonb-properties.type';
|
||||
import { type JSONB_PROPERTY_BRAND } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
import { type RemoveSuffix } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/remove-suffix.type';
|
||||
|
||||
export type FormatJsonbSerializedRelation<T> = T extends unknown
|
||||
? T extends (infer U)[]
|
||||
? FormatJsonbSerializedRelation<U>[]
|
||||
: HasJsonbPropertyBrand<T> extends true
|
||||
? Omit<
|
||||
{
|
||||
[P in keyof T as P extends ExtractSerializedRelationProperties<T> &
|
||||
string
|
||||
? `${RemoveSuffix<P, 'Id'>}UniversalIdentifier`
|
||||
: P]: T[P];
|
||||
},
|
||||
typeof JSONB_PROPERTY_BRAND
|
||||
>
|
||||
: T
|
||||
: never;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
export const JSONB_PROPERTY_BRAND = '__JsonbPropertyBrand__' as const;
|
||||
|
||||
export type JsonbProperty<T> = T extends unknown
|
||||
? T extends object
|
||||
? T & { [JSONB_PROPERTY_BRAND]?: never }
|
||||
: T
|
||||
: never;
|
||||
+7
@@ -6,6 +6,8 @@ import { type ExtractEntityRelatedEntityProperties } from 'src/engine/metadata-m
|
||||
import { type FromMetadataEntityToMetadataName } from 'src/engine/metadata-modules/flat-entity/types/from-metadata-entity-to-metadata-name.type';
|
||||
import { type MetadataManyToOneJoinColumn } from 'src/engine/metadata-modules/flat-entity/types/metadata-many-to-one-join-column.type';
|
||||
import { type SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';
|
||||
import { type ExtractJsonbProperties } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/extract-jsonb-properties.type';
|
||||
import { type FormatJsonbSerializedRelation } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/format-jsonb-serialized-relation.type';
|
||||
import { type RemoveSuffix } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/remove-suffix.type';
|
||||
|
||||
// TODO Handle universal settings
|
||||
@@ -22,6 +24,7 @@ export type UniversalFlatEntityFrom<
|
||||
| ExtractEntityRelatedEntityProperties<TEntity>
|
||||
| Extract<MetadataManyToOneJoinColumn<TMetadataName>, keyof TEntity>
|
||||
| keyof CastRecordTypeOrmDatePropertiesToString<TEntity>
|
||||
| ExtractJsonbProperties<TEntity>
|
||||
> &
|
||||
CastRecordTypeOrmDatePropertiesToString<TEntity> & {
|
||||
[P in ExtractEntityOneToManyEntityRelationProperties<
|
||||
@@ -34,4 +37,8 @@ export type UniversalFlatEntityFrom<
|
||||
string as `${RemoveSuffix<P, 'Id'>}UniversalIdentifier`]: TEntity[P];
|
||||
} & {
|
||||
applicationUniversalIdentifier: string;
|
||||
} & {
|
||||
[P in ExtractJsonbProperties<TEntity>]: FormatJsonbSerializedRelation<
|
||||
TEntity[P]
|
||||
>;
|
||||
};
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
import { type ColumnType } from 'typeorm';
|
||||
|
||||
import { type FieldMetadataDefaultSerializableValue } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
|
||||
import { type FieldMetadataDefaultValueForAnyType } from 'twenty-shared/types';
|
||||
|
||||
import {
|
||||
FieldMetadataException,
|
||||
@@ -11,7 +10,7 @@ import { serializeFunctionDefaultValue } from 'src/engine/metadata-modules/field
|
||||
import { removeSqlDDLInjection } from 'src/engine/workspace-manager/workspace-migration/utils/remove-sql-injection.util';
|
||||
|
||||
type SerializeDefaultValueArgs = {
|
||||
defaultValue?: FieldMetadataDefaultSerializableValue;
|
||||
defaultValue?: FieldMetadataDefaultValueForAnyType;
|
||||
columnType?: ColumnType;
|
||||
schemaName: string;
|
||||
tableName: string;
|
||||
|
||||
Reference in New Issue
Block a user