feat: populate relation join column (#10212)

Fix
https://github.com/twentyhq/core-team-issues/issues/241#issue-2793030259
This commit is contained in:
Jérémy M
2025-02-25 11:24:05 +01:00
committed by GitHub
parent dde70ee3b0
commit a1eea40cf7
49 changed files with 677 additions and 496 deletions

View File

@ -64,9 +64,7 @@ registerEnumType(FieldMetadataType, {
@Relation('object', () => ObjectMetadataDTO, {
nullable: true,
})
export class FieldMetadataDTO<
T extends FieldMetadataType | 'default' = 'default',
> {
export class FieldMetadataDTO<T extends FieldMetadataType = FieldMetadataType> {
@IsUUID()
@IsNotEmpty()
@IDField(() => UUIDScalarType)
@ -75,7 +73,7 @@ export class FieldMetadataDTO<
@IsEnum(FieldMetadataType)
@IsNotEmpty()
@Field(() => FieldMetadataType)
type: FieldMetadataType;
type: T;
@IsString()
@IsNotEmpty()

View File

@ -44,7 +44,7 @@ class TextSettingsValidation {
@Injectable()
export class FieldMetadataValidationService<
T extends FieldMetadataType | 'default' = 'default',
T extends FieldMetadataType = FieldMetadataType,
> {
constructor() {}

View File

@ -36,7 +36,7 @@ import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-met
'relationTargetObjectMetadataId',
])
export class FieldMetadataEntity<
T extends FieldMetadataType | 'default' = 'default',
T extends FieldMetadataType = FieldMetadataType,
> implements FieldMetadataInterface<T>
{
@PrimaryGeneratedColumn('uuid')
@ -59,7 +59,7 @@ export class FieldMetadataEntity<
nullable: false,
type: 'varchar',
})
type: FieldMetadataType;
type: T;
@Column({ nullable: false })
name: string;

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from 'twenty-shared';
import { FieldMetadataType, IsExactly } from 'twenty-shared';
import {
FieldMetadataDefaultActor,
@ -60,17 +60,14 @@ export type FieldMetadataFunctionDefaultValue = ExtractValueType<
FieldMetadataDefaultValueUuidFunction | FieldMetadataDefaultValueNowFunction
>;
type DefaultValueByFieldMetadata<T extends FieldMetadataType | 'default'> = [
T,
] extends [keyof FieldMetadataDefaultValueMapping]
? ExtractValueType<FieldMetadataDefaultValueMapping[T]> | null
: T extends 'default'
? ExtractValueType<UnionOfValues<FieldMetadataDefaultValueMapping>> | null
: never;
export type FieldMetadataDefaultValue<
T extends FieldMetadataType | 'default' = 'default',
> = DefaultValueByFieldMetadata<T>;
T extends FieldMetadataType = FieldMetadataType,
> =
IsExactly<T, FieldMetadataType> extends true
? ExtractValueType<UnionOfValues<FieldMetadataDefaultValueMapping>> | null
: T extends keyof FieldMetadataDefaultValueMapping
? ExtractValueType<FieldMetadataDefaultValueMapping[T]> | null
: never;
type FieldMetadataDefaultValueExtractedTypes = {
[K in keyof FieldMetadataDefaultValueMapping]: ExtractValueType<

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from 'twenty-shared';
import { FieldMetadataType, IsExactly } from 'twenty-shared';
import {
FieldMetadataComplexOption,
@ -11,13 +11,11 @@ type FieldMetadataOptionsMapping = {
[FieldMetadataType.MULTI_SELECT]: FieldMetadataComplexOption[];
};
type OptionsByFieldMetadata<T extends FieldMetadataType | 'default'> =
T extends keyof FieldMetadataOptionsMapping
? FieldMetadataOptionsMapping[T]
: T extends 'default'
? FieldMetadataDefaultOption[] | FieldMetadataComplexOption[]
: never;
export type FieldMetadataOptions<
T extends FieldMetadataType | 'default' = 'default',
> = OptionsByFieldMetadata<T>;
T extends FieldMetadataType = FieldMetadataType,
> =
IsExactly<T, FieldMetadataType> extends true
? FieldMetadataDefaultOption[] | FieldMetadataComplexOption[]
: T extends keyof FieldMetadataOptionsMapping
? FieldMetadataOptionsMapping[T]
: never;

View File

@ -1,4 +1,4 @@
import { FieldMetadataType } from 'twenty-shared';
import { FieldMetadataType, IsExactly } from 'twenty-shared';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
@ -36,6 +36,7 @@ export type FieldMetadataDateTimeSettings = {
export type FieldMetadataRelationSettings = {
relationType: RelationType;
onDelete?: RelationOnDeleteAction;
joinColumnName?: string;
};
type FieldMetadataSettingsMapping = {
@ -46,13 +47,11 @@ type FieldMetadataSettingsMapping = {
[FieldMetadataType.RELATION]: FieldMetadataRelationSettings;
};
type SettingsByFieldMetadata<T extends FieldMetadataType | 'default'> =
T extends keyof FieldMetadataSettingsMapping
? FieldMetadataSettingsMapping[T] & FieldMetadataDefaultSettings
: T extends 'default'
? FieldMetadataDefaultSettings
: never;
export type FieldMetadataSettings<
T extends FieldMetadataType | 'default' = 'default',
> = SettingsByFieldMetadata<T>;
T extends FieldMetadataType = FieldMetadataType,
> =
IsExactly<T, FieldMetadataType> extends true
? FieldMetadataDefaultSettings
: T extends keyof FieldMetadataSettingsMapping
? FieldMetadataSettingsMapping[T] & FieldMetadataDefaultSettings
: never;

View File

@ -9,10 +9,10 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat
import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
export interface FieldMetadataInterface<
T extends FieldMetadataType | 'default' = 'default',
T extends FieldMetadataType = FieldMetadataType,
> {
id: string;
type: FieldMetadataType;
type: T;
name: string;
label: string;
defaultValue?: FieldMetadataDefaultValue<T>;

View File

@ -21,12 +21,12 @@ export function computeColumnName(
fieldName: string,
options?: ComputeColumnNameOptions,
): string;
export function computeColumnName<T extends FieldMetadataType | 'default'>(
export function computeColumnName<T extends FieldMetadataType>(
fieldMetadata: FieldMetadataInterface<T>,
ioptions?: ComputeColumnNameOptions,
): string;
// TODO: If we need to implement custom name logic for columns, we can do it here
export function computeColumnName<T extends FieldMetadataType | 'default'>(
export function computeColumnName<T extends FieldMetadataType>(
fieldMetadataOrFieldName: FieldMetadataInterface<T> | string,
options?: ComputeColumnNameOptions,
): string {
@ -51,15 +51,11 @@ export function computeCompositeColumnName(
fieldName: string,
compositeProperty: CompositeProperty,
): string;
export function computeCompositeColumnName<
T extends FieldMetadataType | 'default',
>(
export function computeCompositeColumnName<T extends FieldMetadataType>(
fieldMetadata: FieldTypeAndNameMetadata | FieldMetadataInterface<T>,
compositeProperty: CompositeProperty,
): string;
export function computeCompositeColumnName<
T extends FieldMetadataType | 'default',
>(
export function computeCompositeColumnName<T extends FieldMetadataType>(
fieldMetadataOrFieldName:
| FieldTypeAndNameMetadata
| FieldMetadataInterface<T>

View File

@ -67,9 +67,7 @@ export class CreateObjectInput {
@IsOptional()
@Field(() => GraphQLJSON, { nullable: true })
primaryKeyFieldMetadataSettings?: FieldMetadataSettings<
FieldMetadataType | 'default'
>;
primaryKeyFieldMetadataSettings?: FieldMetadataSettings<FieldMetadataType>;
@IsBoolean()
@IsOptional()

View File

@ -73,7 +73,7 @@ export class ObjectMetadataRelationService {
createdObjectMetadata: ObjectMetadataEntity,
objectPrimaryKeyType: FieldMetadataType,
objectPrimaryKeyFieldSettings:
| FieldMetadataSettings<FieldMetadataType | 'default'>
| FieldMetadataSettings<FieldMetadataType>
| undefined,
relationObjectMetadataStandardId: string,
) {
@ -109,7 +109,7 @@ export class ObjectMetadataRelationService {
relatedObjectMetadata: ObjectMetadataEntity,
objectPrimaryKeyType: FieldMetadataType,
objectPrimaryKeyFieldSettings:
| FieldMetadataSettings<FieldMetadataType | 'default'>
| FieldMetadataSettings<FieldMetadataType>
| undefined,
) {
return this.fieldMetadataRepository.save([
@ -340,7 +340,7 @@ export class ObjectMetadataRelationService {
relatedObjectMetadata: ObjectMetadataEntity,
objectPrimaryKeyType: FieldMetadataType,
objectPrimaryKeyFieldSettings:
| FieldMetadataSettings<FieldMetadataType | 'default'>
| FieldMetadataSettings<FieldMetadataType>
| undefined,
isUpdate = false,
) {

View File

@ -147,7 +147,7 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
toObjectMetadata,
[
foreignKeyFieldMetadata,
deletedAtFieldMetadata as FieldMetadataEntity<'default'>,
deletedAtFieldMetadata as FieldMetadataEntity<FieldMetadataType>,
],
false,
false,
@ -451,7 +451,7 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
relationMetadata.toObjectMetadata,
[
foreignKeyFieldMetadata,
deletedAtFieldMetadata as FieldMetadataEntity<'default'>,
deletedAtFieldMetadata as FieldMetadataEntity<FieldMetadataType>,
],
);
@ -570,7 +570,7 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
}
private throwIfDeletedAtFieldMetadataNotFound(
deletedAtFieldMetadata?: FieldMetadataEntity<'default'> | null,
deletedAtFieldMetadata?: FieldMetadataEntity<FieldMetadataType> | null,
) {
if (!isDefined(deletedAtFieldMetadata)) {
throw new RelationMetadataException(

View File

@ -36,7 +36,7 @@ export class RemoteTableRelationsService {
workspaceId: string,
remoteObjectMetadata: ObjectMetadataEntity,
objectPrimaryKeyFieldSettings:
| FieldMetadataSettings<FieldMetadataType | 'default'>
| FieldMetadataSettings<FieldMetadataType>
| undefined,
objectPrimaryKeyColumnType?: string,
) {
@ -150,7 +150,7 @@ export class RemoteTableRelationsService {
createdObjectMetadata: ObjectMetadataEntity,
objectPrimaryKeyType: FieldMetadataType,
objectPrimaryKeyFieldSettings:
| FieldMetadataSettings<FieldMetadataType | 'default'>
| FieldMetadataSettings<FieldMetadataType>
| undefined,
) {
const attachmentObjectMetadata =
@ -190,7 +190,7 @@ export class RemoteTableRelationsService {
createdObjectMetadata: ObjectMetadataEntity,
objectPrimaryKeyType: FieldMetadataType,
objectPrimaryKeyFieldSettings:
| FieldMetadataSettings<FieldMetadataType | 'default'>
| FieldMetadataSettings<FieldMetadataType>
| undefined,
) {
const timelineActivityObjectMetadata =
@ -230,7 +230,7 @@ export class RemoteTableRelationsService {
createdObjectMetadata: ObjectMetadataEntity,
objectPrimaryKeyType: FieldMetadataType,
objectPrimaryKeyFieldSettings:
| FieldMetadataSettings<FieldMetadataType | 'default'>
| FieldMetadataSettings<FieldMetadataType>
| undefined,
) {
const favoriteObjectMetadata =

View File

@ -37,12 +37,12 @@ export const mapUdtNameToFieldSettings = (
case 'int4':
return {
dataType: NumberDataType.INT,
} satisfies FieldMetadataSettings<FieldMetadataType.NUMBER>;
} as FieldMetadataSettings<FieldMetadataType.NUMBER>;
case 'int8':
case 'bigint':
return {
dataType: NumberDataType.BIGINT,
} satisfies FieldMetadataSettings<FieldMetadataType.NUMBER>;
} as FieldMetadataSettings<FieldMetadataType.NUMBER>;
default:
return undefined;
}

View File

@ -18,9 +18,8 @@ import {
WorkspaceMigrationExceptionCode,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.exception';
export class ColumnActionAbstractFactory<
T extends FieldMetadataType | 'default',
> implements WorkspaceColumnActionFactory<T>
export class ColumnActionAbstractFactory<T extends FieldMetadataType>
implements WorkspaceColumnActionFactory<T>
{
protected readonly logger = new Logger(ColumnActionAbstractFactory.name);

View File

@ -8,9 +8,7 @@ import {
WorkspaceMigrationColumnActionType,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
export interface WorkspaceColumnActionFactory<
T extends FieldMetadataType | 'default',
> {
export interface WorkspaceColumnActionFactory<T extends FieldMetadataType> {
create(
action:
| WorkspaceMigrationColumnActionType.CREATE