Compare commits

...

4 Commits

Author SHA1 Message Date
Charles Bochet 42d0fdeeeb Refactor new relation sync (#11711)
In this PR:
- this should fix the sync metadata for new relation system

This goes with the recent PR:
https://github.com/twentyhq/twenty/pull/11725

What we want:
- ONE_TO_MANY relations should have no joinColumn and no onDelete
- MANY_TO_ONE should have both
2025-04-25 01:04:15 +02:00
martmull 8d95166af8 Fix missing on delete cascade for relation (#11725)
Follow up from https://github.com/twentyhq/twenty/pull/10217
Adding onDelete action on Many_to_one sides
2025-04-25 01:04:04 +02:00
Félix Malfait 676866a554 Fix json type in clickhouse migrations (#11710)
Settings in clickhouse are only set for the duration of the session so
we need to keep the same client
2025-04-23 22:09:46 +02:00
Félix Malfait fc6aafd3c6 Fix clickhouse migration not in dist (#11709)
Clickhouse migrations were not correctly copied to the dist folder (for
command yarn clickhouse:migrate:prod)
2025-04-23 21:23:31 +02:00
28 changed files with 363 additions and 180 deletions
+4
View File
@@ -25,6 +25,10 @@
{
"include": "**/serverless/drivers/constants/executor/index.mjs",
"outDir": "dist/assets"
},
{
"include": "**/database/clickhouse/migrations/*.sql",
"outDir": "dist/src"
}
],
"watchAssets": true
@@ -30,30 +30,6 @@ async function ensureDatabaseExists() {
query: `CREATE DATABASE IF NOT EXISTS "${database}"`,
});
let jsonTypeEnabled = false;
try {
await client.command({
query: `SET enable_json_type = 1`,
});
jsonTypeEnabled = true;
} catch (error) {
// Intentionally empty - will try alternative method
}
try {
await client.command({
query: `SET allow_experimental_json_type = 1`,
});
jsonTypeEnabled = true;
} catch (error) {
// Intentionally empty - failure handled by jsonTypeEnabled check
}
if (!jsonTypeEnabled) {
console.error('Failed to enable JSON type');
}
await client.close();
}
@@ -99,6 +75,9 @@ async function runMigrations() {
const client = createClient({
url: clickhouseUrl(),
clickhouse_settings: {
allow_experimental_json_type: 1,
},
});
await ensureMigrationTable(client);
@@ -129,8 +129,14 @@ export class MigrateRelationsToFieldMetadataCommand extends ActiveOrSuspendedWor
...fieldMetadata,
settings: {
relationType,
onDelete: relationMetadata.onDeleteAction,
joinColumnName: joinColumnFieldMetadata?.name,
onDelete:
relationType === RelationType.MANY_TO_ONE
? relationMetadata.onDeleteAction
: undefined,
joinColumnName:
relationType === RelationType.MANY_TO_ONE
? joinColumnFieldMetadata?.name
: undefined,
},
relationTargetFieldMetadataId,
relationTargetObjectMetadataId,
@@ -72,6 +72,9 @@ export class AccessTokenService {
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkspaceMemberWorkspaceEntity>(
workspaceId,
'workspaceMember',
{
shouldFailIfMetadataNotFound: false,
},
);
const workspaceMember = await workspaceMemberRepository.findOne({
@@ -355,7 +355,7 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
});
if (fieldMetadata.type === FieldMetadataType.RELATION) {
const isManyToManyRelation =
const isManyToOneRelation =
(fieldMetadata as FieldMetadataEntity<FieldMetadataType.RELATION>)
.settings?.relationType === RelationType.MANY_TO_ONE;
@@ -385,7 +385,7 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
columns: [
{
action: WorkspaceMigrationColumnActionType.DROP,
columnName: isManyToManyRelation
columnName: isManyToOneRelation
? `${(fieldMetadata as FieldMetadataEntity<FieldMetadataType.RELATION>).settings?.joinColumnName}`
: `${(targetFieldMetadata as FieldMetadataEntity<FieldMetadataType.RELATION>).settings?.joinColumnName}`,
} satisfies WorkspaceMigrationColumnDrop,
@@ -100,7 +100,6 @@ export class ObjectMetadataFieldRelationService {
...sourceFieldMetadata,
settings: {
relationType: RelationType.ONE_TO_MANY,
onDelete: RelationOnDeleteAction.CASCADE,
},
relationTargetObjectMetadataId: targetObjectMetadata.id,
relationTargetFieldMetadataId: targetFieldMetadata.id,
@@ -55,6 +55,12 @@ export class RelationColumnActionFactory extends ColumnActionAbstractFactory<Fie
return [];
}
if (
currentFieldMetadata.settings.relationType === RelationType.ONE_TO_MANY
) {
return [];
}
const currentJoinColumnName = currentFieldMetadata.settings.joinColumnName;
const alteredJoinColumnName = alteredFieldMetadata.settings.joinColumnName;
@@ -1,110 +1,232 @@
import { Injectable } from '@nestjs/common';
import { isDefined } from 'class-validator';
import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface';
import { WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity';
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
import { getJoinColumn } from 'src/engine/twenty-orm/utils/get-join-column.util';
import { convertClassNameToObjectMetadataName } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util';
import { isGatedAndNotEnabled } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
import { assert } from 'src/utils/assert';
interface CustomRelationFactory {
object: ObjectMetadataEntity;
metadata: typeof BaseWorkspaceEntity;
}
@Injectable()
export class StandardFieldRelationFactory {
createFieldRelationForCustomObject(
customObjectFactories: CustomRelationFactory[],
context: WorkspaceSyncContext,
computeRelationFieldsForCustomObject(
customObjectMetadata: ObjectMetadataEntity,
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
): FieldMetadataEntity<FieldMetadataType.RELATION>[] {
return customObjectFactories.flatMap((customObjectFactory) =>
this.updateFieldRelationMetadata(
customObjectFactory,
context,
originalObjectMetadataMap,
),
);
}
createFieldRelationForStandardObject(
standardObjectMetadataDefinitions: (typeof BaseWorkspaceEntity)[],
context: WorkspaceSyncContext,
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
): Map<string, FieldMetadataEntity<FieldMetadataType.RELATION>[]> {
return standardObjectMetadataDefinitions.reduce(
(acc, standardObjectMetadata) => {
const workspaceEntityMetadataArgs = metadataArgsStorage.filterEntities(
standardObjectMetadata,
);
if (!workspaceEntityMetadataArgs) {
return acc;
}
if (
isGatedAndNotEnabled(
workspaceEntityMetadataArgs.gate,
context.featureFlags,
)
) {
return acc;
}
acc.set(
workspaceEntityMetadataArgs.standardId,
this.updateFieldRelationMetadata(
standardObjectMetadata,
context,
originalObjectMetadataMap,
),
);
return acc;
},
new Map<string, FieldMetadataEntity<FieldMetadataType.RELATION>[]>(),
);
}
private updateFieldRelationMetadata(
workspaceEntityOrCustomRelationFactory:
| typeof BaseWorkspaceEntity
| CustomRelationFactory,
context: WorkspaceSyncContext,
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
): FieldMetadataEntity<FieldMetadataType.RELATION>[] {
const target =
'metadata' in workspaceEntityOrCustomRelationFactory
? workspaceEntityOrCustomRelationFactory.metadata
: workspaceEntityOrCustomRelationFactory;
const workspaceEntity =
'metadata' in workspaceEntityOrCustomRelationFactory
? metadataArgsStorage.filterExtendedEntities(target)
: metadataArgsStorage.filterEntities(target);
const workspaceRelationMetadataArgsCollection =
metadataArgsStorage.filterRelations(target);
metadataArgsStorage.filterRelations(CustomWorkspaceEntity);
if (!workspaceEntity) {
const joinColumnsMetadataArgsCollection =
metadataArgsStorage.filterJoinColumns(CustomWorkspaceEntity);
const objectNameSingular = customObjectMetadata.nameSingular;
const sourceObjectMetadata = originalObjectMetadataMap[objectNameSingular];
if (!isDefined(sourceObjectMetadata)) {
throw new Error(
`Object metadata decorator not found, can't parse ${target.name}`,
`Source object ${objectNameSingular} not found in database while parsing ${objectNameSingular} relations`,
);
}
return workspaceRelationMetadataArgsCollection.map(
(workspaceRelationMetadataArgs) => {
const inverseSideTarget =
workspaceRelationMetadataArgs.inverseSideTarget();
const targetObjectNameSingular = convertClassNameToObjectMetadataName(
inverseSideTarget.name,
);
const targetObjectMetadata =
originalObjectMetadataMap[targetObjectNameSingular];
if (!isDefined(targetObjectMetadata)) {
throw new Error(
`Target object ${targetObjectNameSingular} not found in database while parsing ${objectNameSingular} relations`,
);
}
const sourceFieldMetadataName = workspaceRelationMetadataArgs.name;
const targetFieldMetadataName =
workspaceRelationMetadataArgs.inverseSideFieldKey ??
objectNameSingular;
const targetFieldMetadata = targetObjectMetadata.fields.find(
(field) => field.name === targetFieldMetadataName,
) as FieldMetadataEntity<FieldMetadataType.RELATION>;
if (!isDefined(targetFieldMetadata)) {
throw new Error(
`Target field ${targetFieldMetadataName} not found in object ${targetObjectNameSingular} for relation ${workspaceRelationMetadataArgs.name} of type ${workspaceRelationMetadataArgs.type}`,
);
}
const joinColumnName =
workspaceRelationMetadataArgs.type === RelationType.MANY_TO_ONE
? getJoinColumn(
joinColumnsMetadataArgsCollection,
workspaceRelationMetadataArgs as WorkspaceRelationMetadataArgs,
)
: undefined;
const sourceFieldMetadata = sourceObjectMetadata.fields.find(
(field) => field.name === sourceFieldMetadataName,
) as FieldMetadataEntity<FieldMetadataType.RELATION>;
if (!isDefined(sourceFieldMetadata)) {
throw new Error(
`Source field ${sourceFieldMetadataName} not found in object ${sourceFieldMetadata.name} for relation ${workspaceRelationMetadataArgs.name} of type ${workspaceRelationMetadataArgs.type}`,
);
}
return {
...sourceFieldMetadata,
type: FieldMetadataType.RELATION,
settings: {
relationType: workspaceRelationMetadataArgs.type,
onDelete:
workspaceRelationMetadataArgs.type === RelationType.MANY_TO_ONE
? workspaceRelationMetadataArgs.onDelete
: undefined,
joinColumnName,
},
relationTargetObjectMetadataId: targetObjectMetadata.id,
relationTargetFieldMetadataId: targetFieldMetadata.id,
isNullable: workspaceRelationMetadataArgs.isNullable,
} satisfies FieldMetadataEntity<FieldMetadataType.RELATION>;
},
);
}
computeRelationFieldsForStandardObject(
standardObjectMetadataWorkspaceEntity: typeof BaseWorkspaceEntity,
context: WorkspaceSyncContext,
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
): FieldMetadataEntity<FieldMetadataType.RELATION>[] {
const workspaceEntityMetadataArgs = metadataArgsStorage.filterEntities(
standardObjectMetadataWorkspaceEntity,
);
if (!workspaceEntityMetadataArgs) {
return [];
}
if (
!workspaceRelationMetadataArgsCollection ||
isGatedAndNotEnabled(workspaceEntity?.gate, context.featureFlags)
isGatedAndNotEnabled(
workspaceEntityMetadataArgs.gate,
context.featureFlags,
)
) {
return [];
}
return workspaceRelationMetadataArgsCollection
const sourceObjectNameSingular = workspaceEntityMetadataArgs.nameSingular;
const workspaceStaticRelationMetadataArgsCollection =
metadataArgsStorage.filterRelations(
standardObjectMetadataWorkspaceEntity,
);
const workspaceDynamicRelationMetadataArgsCollection =
metadataArgsStorage.filterDynamicRelations(
standardObjectMetadataWorkspaceEntity,
);
const joinColumnsMetadataArgsCollection =
metadataArgsStorage.filterJoinColumns(
standardObjectMetadataWorkspaceEntity,
);
if (
!isDefined(workspaceStaticRelationMetadataArgsCollection) &&
!isDefined(workspaceDynamicRelationMetadataArgsCollection)
) {
throw new Error(
`No relations found for object ${sourceObjectNameSingular}`,
);
}
const sourceObjectMetadata =
originalObjectMetadataMap[sourceObjectNameSingular];
if (!isDefined(sourceObjectMetadata)) {
throw new Error(
`Source object ${sourceObjectNameSingular} not found in database while parsing relations`,
);
}
const relationsFromDynamicRelations =
workspaceDynamicRelationMetadataArgsCollection
.filter(
(workspaceDynamicRelationMetadataArgs) =>
!isGatedAndNotEnabled(
workspaceDynamicRelationMetadataArgs.gate,
context.featureFlags,
),
)
.flatMap((workspaceDynamicRelationMetadataArgs) => {
const customObjectMetadataItems = Object.values(
originalObjectMetadataMap,
).filter((objectMetadata) => objectMetadata.isCustom);
// TODO: this is hacky and needs to be simplified
return customObjectMetadataItems.flatMap((targetObjectMetadata) => {
const relationMetadataArgs =
workspaceDynamicRelationMetadataArgs.argsFactory(
targetObjectMetadata,
);
const sourceFieldMetadata = sourceObjectMetadata?.fields.find(
(field) => field.name === relationMetadataArgs.name,
) as FieldMetadataEntity<FieldMetadataType.RELATION>;
const targetFieldMetadata = targetObjectMetadata?.fields.find(
(field) =>
field.name ===
workspaceDynamicRelationMetadataArgs.inverseSideFieldKey,
) as FieldMetadataEntity<FieldMetadataType.RELATION>;
if (!isDefined(sourceFieldMetadata)) {
throw new Error(
`Source field ${relationMetadataArgs.name} not found in object ${sourceObjectNameSingular} for relation ${relationMetadataArgs.name} of type ${relationMetadataArgs}`,
);
}
if (!isDefined(targetFieldMetadata)) {
throw new Error(
`Target field ${workspaceDynamicRelationMetadataArgs.inverseSideFieldKey} not found in object ${targetObjectMetadata.nameSingular} for relation ${relationMetadataArgs.name} of type ${workspaceDynamicRelationMetadataArgs.type}`,
);
}
return {
...sourceFieldMetadata,
type: FieldMetadataType.RELATION,
settings: {
relationType: workspaceDynamicRelationMetadataArgs.type,
onDelete:
workspaceDynamicRelationMetadataArgs.type ===
RelationType.MANY_TO_ONE
? workspaceDynamicRelationMetadataArgs.onDelete
: undefined,
joinColumnName: relationMetadataArgs.joinColumn,
},
relationTargetObjectMetadataId: targetObjectMetadata.id,
relationTargetFieldMetadataId: targetFieldMetadata.id,
isNullable: workspaceDynamicRelationMetadataArgs.isNullable,
} satisfies FieldMetadataEntity<FieldMetadataType.RELATION>;
});
});
const staticRelations = workspaceStaticRelationMetadataArgsCollection
.filter(
(workspaceRelationMetadataArgs) =>
!isGatedAndNotEnabled(
@@ -113,13 +235,6 @@ export class StandardFieldRelationFactory {
),
)
.map((workspaceRelationMetadataArgs) => {
// Compute reflect relation metadata
const sourceObjectNameSingular =
'object' in workspaceEntityOrCustomRelationFactory
? workspaceEntityOrCustomRelationFactory.object.nameSingular
: convertClassNameToObjectMetadataName(
workspaceRelationMetadataArgs.target.name,
);
const inverseSideTarget =
workspaceRelationMetadataArgs.inverseSideTarget();
const targetObjectNameSingular = convertClassNameToObjectMetadataName(
@@ -127,60 +242,62 @@ export class StandardFieldRelationFactory {
);
const sourceFieldMetadataName = workspaceRelationMetadataArgs.name;
const targetFieldMetadataName =
(workspaceRelationMetadataArgs.inverseSideFieldKey as
| string
| undefined) ?? sourceObjectNameSingular;
const sourceObjectMetadata =
originalObjectMetadataMap[sourceObjectNameSingular];
const joinColumnsMetadataArgsCollection =
metadataArgsStorage.filterJoinColumns(target);
const joinColumnName = getJoinColumn(
joinColumnsMetadataArgsCollection,
workspaceRelationMetadataArgs,
);
workspaceRelationMetadataArgs.inverseSideFieldKey ??
sourceObjectNameSingular;
assert(
sourceObjectMetadata,
`Source object ${sourceObjectNameSingular} not found in databse for relation ${workspaceRelationMetadataArgs.name} of type ${workspaceRelationMetadataArgs.type}`,
);
const targetObjectMetadata =
originalObjectMetadataMap[targetObjectNameSingular];
assert(
targetObjectMetadata,
`Target object ${targetObjectNameSingular} not found in databse for relation ${workspaceRelationMetadataArgs.name} of type ${workspaceRelationMetadataArgs.type}`,
);
const joinColumnName =
workspaceRelationMetadataArgs.type === RelationType.MANY_TO_ONE
? getJoinColumn(
joinColumnsMetadataArgsCollection,
workspaceRelationMetadataArgs as WorkspaceRelationMetadataArgs,
)
: undefined;
const sourceFieldMetadata = sourceObjectMetadata?.fields.find(
(field) => field.name === sourceFieldMetadataName,
) as FieldMetadataEntity<FieldMetadataType.RELATION>;
assert(
sourceFieldMetadata,
`Source field ${sourceFieldMetadataName} not found in object ${sourceObjectNameSingular} for relation ${workspaceRelationMetadataArgs.name} of type ${workspaceRelationMetadataArgs.type}`,
);
if (!isDefined(sourceFieldMetadata)) {
throw new Error(
`Source field ${sourceFieldMetadataName} not found in object ${sourceObjectNameSingular} for relation ${workspaceRelationMetadataArgs.name} of type ${workspaceRelationMetadataArgs.type}`,
);
}
const targetFieldMetadata = targetObjectMetadata?.fields.find(
const targetObjectMetadata =
originalObjectMetadataMap[targetObjectNameSingular];
if (!isDefined(targetObjectMetadata)) {
throw new Error(
`Target object ${targetObjectNameSingular} not found in database for relation ${workspaceRelationMetadataArgs.name} of type ${workspaceRelationMetadataArgs.type}`,
);
}
const targetFieldMetadata = targetObjectMetadata.fields.find(
(field) => field.name === targetFieldMetadataName,
) as FieldMetadataEntity<FieldMetadataType.RELATION>;
assert(
targetFieldMetadata,
`Target field ${targetFieldMetadataName} not found in object ${targetObjectNameSingular} for relation ${workspaceRelationMetadataArgs.name} of type ${workspaceRelationMetadataArgs.type}`,
);
if (!isDefined(targetFieldMetadata)) {
throw new Error(
`Target field ${targetFieldMetadataName} not found in object ${targetObjectNameSingular} for relation ${workspaceRelationMetadataArgs.name} of type ${workspaceRelationMetadataArgs.type}`,
);
}
return {
...sourceFieldMetadata,
type: FieldMetadataType.RELATION,
settings: {
relationType: workspaceRelationMetadataArgs.type,
onDelete: workspaceRelationMetadataArgs.onDelete,
onDelete:
workspaceRelationMetadataArgs.type === RelationType.MANY_TO_ONE
? workspaceRelationMetadataArgs.onDelete
: undefined,
joinColumnName,
},
relationTargetObjectMetadataId: targetObjectMetadata.id,
relationTargetFieldMetadataId: targetFieldMetadata.id,
} satisfies FieldMetadataEntity<FieldMetadataType.RELATION>;
});
return [...staticRelations, ...relationsFromDynamicRelations];
}
}
@@ -13,7 +13,7 @@ import { WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-syn
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity';
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
import { WorkspaceMigrationFieldRelationFactory } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-field-relation.factory';
import {
FieldMetadataUpdate,
@@ -150,26 +150,30 @@ export class WorkspaceSyncFieldMetadataRelationService {
originalObjectMetadataMapByName: Record<string, ObjectMetadataEntity>,
storage: WorkspaceSyncStorage,
): Promise<void> {
// Create standard field metadata map
const standardFieldMetadataRelationCollection =
this.standardFieldRelationFactory.createFieldRelationForStandardObject(
standardObjectMetadataDefinitions,
context,
originalObjectMetadataMapByName,
);
// Create map of original and standard object metadata by standard ids
const originalObjectMetadataMap = mapObjectMetadataByUniqueIdentifier(
originalObjectMetadataCollection,
);
// Loop over all standard objects and compare them with the objects in DB
for (const [
standardObjectId,
standardFieldMetadataCollection,
] of standardFieldMetadataRelationCollection) {
for (const standardObjectMetadataDefinition of standardObjectMetadataDefinitions) {
const workspaceEntityMetadataArgs = metadataArgsStorage.filterEntities(
standardObjectMetadataDefinition,
);
if (!workspaceEntityMetadataArgs) {
continue;
}
const standardFieldMetadataRelationCollection =
this.standardFieldRelationFactory.computeRelationFieldsForStandardObject(
standardObjectMetadataDefinition,
context,
originalObjectMetadataMapByName,
);
const originalObjectMetadata =
originalObjectMetadataMap[standardObjectId];
originalObjectMetadataMap[workspaceEntityMetadataArgs.standardId];
const originalFieldRelationMetadataCollection =
(originalObjectMetadata?.fields.filter(
@@ -183,7 +187,7 @@ export class WorkspaceSyncFieldMetadataRelationService {
const fieldComparatorResults =
this.workspaceFieldRelationComparator.compare(
originalFieldRelationMetadataCollection,
standardFieldMetadataCollection,
standardFieldMetadataRelationCollection,
);
this.storeComparatorResults(fieldComparatorResults, storage);
@@ -196,25 +200,22 @@ export class WorkspaceSyncFieldMetadataRelationService {
originalObjectMetadataMapByName: Record<string, ObjectMetadataEntity>,
storage: WorkspaceSyncStorage,
): Promise<void> {
// Create standard field metadata collection
const customFieldMetadataRelationCollection =
this.standardFieldRelationFactory.createFieldRelationForCustomObject(
customObjectMetadataCollection.map((objectMetadata) => ({
object: objectMetadata,
metadata: CustomWorkspaceEntity,
})),
context,
originalObjectMetadataMapByName,
);
// Loop over all custom objects from the DB and compare their fields with standard fields
for (const customObjectMetadata of customObjectMetadataCollection) {
/**
* COMPARE FIELD METADATA
*/
const originalFieldRelationMetadataCollection =
(customObjectMetadata.fields.filter(
(field) => field.type === FieldMetadataType.RELATION,
) ?? []) as FieldMetadataEntity<FieldMetadataType.RELATION>[];
const customFieldMetadataRelationCollection =
this.standardFieldRelationFactory.computeRelationFieldsForCustomObject(
customObjectMetadata,
originalObjectMetadataMapByName,
);
const fieldComparatorResults =
this.workspaceFieldRelationComparator.compare(
customObjectMetadata.fields as FieldMetadataEntity<FieldMetadataType.RELATION>[],
originalFieldRelationMetadataCollection,
customFieldMetadataRelationCollection,
);
@@ -233,9 +234,6 @@ export class WorkspaceSyncFieldMetadataRelationService {
await objectMetadataRepository.find({
where: {
workspaceId: context.workspaceId,
fields: {
type: FieldMetadataType.RELATION,
},
},
relations: ['dataSource', 'fields'],
});
@@ -3,6 +3,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity';
@@ -69,6 +70,7 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconCircleUser',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'authoredAttachments',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
author: Relation<WorkspaceMemberWorkspaceEntity> | null;
@@ -84,6 +86,7 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconNotes',
inverseSideTarget: () => TaskWorkspaceEntity,
inverseSideFieldKey: 'attachments',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
task: Relation<TaskWorkspaceEntity> | null;
@@ -99,6 +102,7 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconNotes',
inverseSideTarget: () => NoteWorkspaceEntity,
inverseSideFieldKey: 'attachments',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
note: Relation<NoteWorkspaceEntity> | null;
@@ -114,6 +118,7 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconUser',
inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'attachments',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null;
@@ -129,6 +134,7 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconBuildingSkyscraper',
inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'attachments',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null;
@@ -144,6 +150,7 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconBuildingSkyscraper',
inverseSideTarget: () => OpportunityWorkspaceEntity,
inverseSideFieldKey: 'attachments',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
opportunity: Relation<OpportunityWorkspaceEntity> | null;
@@ -163,6 +170,7 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity {
}),
inverseSideTarget: () => CustomWorkspaceEntity,
inverseSideFieldKey: 'attachments',
onDelete: RelationOnDeleteAction.CASCADE,
})
custom: Relation<CustomWorkspaceEntity>;
}
@@ -3,6 +3,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
@@ -45,6 +46,7 @@ export class BlocklistWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconCircleUser',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'blocklist',
onDelete: RelationOnDeleteAction.SET_NULL,
})
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity>;
@@ -3,6 +3,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
@@ -57,6 +58,7 @@ export class CalendarChannelEventAssociationWorkspaceEntity extends BaseWorkspac
icon: 'IconCalendar',
inverseSideTarget: () => CalendarChannelWorkspaceEntity,
inverseSideFieldKey: 'calendarChannelEventAssociations',
onDelete: RelationOnDeleteAction.CASCADE,
})
calendarChannel: Relation<CalendarChannelWorkspaceEntity>;
@@ -72,6 +74,7 @@ export class CalendarChannelEventAssociationWorkspaceEntity extends BaseWorkspac
icon: 'IconCalendar',
inverseSideTarget: () => CalendarEventWorkspaceEntity,
inverseSideFieldKey: 'calendarChannelEventAssociations',
onDelete: RelationOnDeleteAction.CASCADE,
})
calendarEvent: Relation<CalendarEventWorkspaceEntity>;
@@ -307,6 +307,7 @@ export class CalendarChannelWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconUserCircle',
inverseSideTarget: () => ConnectedAccountWorkspaceEntity,
inverseSideFieldKey: 'calendarChannels',
onDelete: RelationOnDeleteAction.CASCADE,
})
connectedAccount: Relation<ConnectedAccountWorkspaceEntity>;
@@ -3,6 +3,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
@@ -111,6 +112,7 @@ export class CalendarEventParticipantWorkspaceEntity extends BaseWorkspaceEntity
icon: 'IconCalendar',
inverseSideTarget: () => CalendarEventWorkspaceEntity,
inverseSideFieldKey: 'calendarEventParticipants',
onDelete: RelationOnDeleteAction.CASCADE,
})
calendarEvent: Relation<CalendarEventWorkspaceEntity>;
@@ -125,6 +127,7 @@ export class CalendarEventParticipantWorkspaceEntity extends BaseWorkspaceEntity
icon: 'IconUser',
inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'calendarEventParticipants',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null;
@@ -140,6 +143,7 @@ export class CalendarEventParticipantWorkspaceEntity extends BaseWorkspaceEntity
icon: 'IconUser',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'calendarEventParticipants',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null;
@@ -117,6 +117,7 @@ export class ConnectedAccountWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconUserCircle',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'connectedAccounts',
onDelete: RelationOnDeleteAction.CASCADE,
})
accountOwner: Relation<WorkspaceMemberWorkspaceEntity>;
@@ -61,6 +61,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconCircleUser',
inverseSideFieldKey: 'favorites',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
forWorkspaceMember: Relation<WorkspaceMemberWorkspaceEntity>;
@@ -76,6 +77,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconUser',
inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'favorites',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null;
@@ -91,6 +93,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconBuildingSkyscraper',
inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'favorites',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null;
@@ -106,6 +109,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconFolder',
inverseSideTarget: () => FavoriteFolderWorkspaceEntity,
inverseSideFieldKey: 'favorites',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
favoriteFolder: Relation<FavoriteFolderWorkspaceEntity> | null;
@@ -121,6 +125,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconTargetArrow',
inverseSideTarget: () => OpportunityWorkspaceEntity,
inverseSideFieldKey: 'favorites',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
opportunity: Relation<OpportunityWorkspaceEntity> | null;
@@ -136,6 +141,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconSettingsAutomation',
inverseSideTarget: () => WorkflowWorkspaceEntity,
inverseSideFieldKey: 'favorites',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
workflow: Relation<WorkflowWorkspaceEntity> | null;
@@ -151,6 +157,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconSettingsAutomation',
inverseSideTarget: () => WorkflowVersionWorkspaceEntity,
inverseSideFieldKey: 'favorites',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
workflowVersion: Relation<WorkflowVersionWorkspaceEntity> | null;
@@ -166,6 +173,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconSettingsAutomation',
inverseSideTarget: () => WorkflowRunWorkspaceEntity,
inverseSideFieldKey: 'favorites',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
workflowRun: Relation<WorkflowRunWorkspaceEntity> | null;
@@ -181,6 +189,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconCheckbox',
inverseSideTarget: () => TaskWorkspaceEntity,
inverseSideFieldKey: 'favorites',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
task: Relation<TaskWorkspaceEntity> | null;
@@ -196,6 +205,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconNotes',
inverseSideTarget: () => NoteWorkspaceEntity,
inverseSideFieldKey: 'favorites',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
note: Relation<NoteWorkspaceEntity> | null;
@@ -231,6 +241,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
}),
inverseSideTarget: () => CustomWorkspaceEntity,
inverseSideFieldKey: 'favorites',
onDelete: RelationOnDeleteAction.CASCADE,
})
custom: Relation<CustomWorkspaceEntity>;
}
@@ -3,6 +3,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
@@ -93,6 +94,7 @@ export class MessageChannelMessageAssociationWorkspaceEntity extends BaseWorkspa
icon: 'IconHash',
inverseSideTarget: () => MessageChannelWorkspaceEntity,
inverseSideFieldKey: 'messageChannelMessageAssociations',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
messageChannel: Relation<MessageChannelWorkspaceEntity> | null;
@@ -108,6 +110,7 @@ export class MessageChannelMessageAssociationWorkspaceEntity extends BaseWorkspa
icon: 'IconHash',
inverseSideTarget: () => MessageWorkspaceEntity,
inverseSideFieldKey: 'messageChannelMessageAssociations',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
message: Relation<MessageWorkspaceEntity> | null;
@@ -359,6 +359,7 @@ export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconUserCircle',
inverseSideTarget: () => ConnectedAccountWorkspaceEntity,
inverseSideFieldKey: 'messageChannels',
onDelete: RelationOnDeleteAction.CASCADE,
})
connectedAccount: Relation<ConnectedAccountWorkspaceEntity>;
@@ -3,6 +3,7 @@ import { Relation } from 'typeorm';
import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
@@ -44,6 +45,7 @@ export class MessageFolderWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconMessage',
inverseSideTarget: () => MessageChannelWorkspaceEntity,
inverseSideFieldKey: 'messageFolders',
onDelete: RelationOnDeleteAction.CASCADE,
})
messageChannel: Relation<MessageChannelWorkspaceEntity>;
@@ -3,6 +3,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
@@ -73,6 +74,7 @@ export class MessageParticipantWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconMessage',
inverseSideTarget: () => MessageWorkspaceEntity,
inverseSideFieldKey: 'messageParticipants',
onDelete: RelationOnDeleteAction.CASCADE,
})
message: Relation<MessageWorkspaceEntity>;
@@ -87,6 +89,7 @@ export class MessageParticipantWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconUser',
inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'messageParticipants',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null;
@@ -102,6 +105,7 @@ export class MessageParticipantWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconCircleUser',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'messageParticipants',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null;
@@ -2,6 +2,7 @@ import { msg } from '@lingui/core/macro';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity';
@@ -37,6 +38,7 @@ export class NoteTargetWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconNotes',
inverseSideTarget: () => NoteWorkspaceEntity,
inverseSideFieldKey: 'noteTargets',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
note: Relation<NoteWorkspaceEntity> | null;
@@ -52,6 +54,7 @@ export class NoteTargetWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconUser',
inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'noteTargets',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null;
@@ -67,6 +70,7 @@ export class NoteTargetWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconBuildingSkyscraper',
inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'noteTargets',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null;
@@ -82,6 +86,7 @@ export class NoteTargetWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconTargetArrow',
inverseSideTarget: () => OpportunityWorkspaceEntity,
inverseSideFieldKey: 'noteTargets',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
opportunity: Relation<OpportunityWorkspaceEntity> | null;
@@ -101,6 +106,7 @@ export class NoteTargetWorkspaceEntity extends BaseWorkspaceEntity {
}),
inverseSideTarget: () => CustomWorkspaceEntity,
inverseSideFieldKey: 'noteTargets',
onDelete: RelationOnDeleteAction.CASCADE,
})
custom: Relation<CustomWorkspaceEntity>;
}
@@ -185,6 +185,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconBuildingSkyscraper',
inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'people',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null;
@@ -2,6 +2,7 @@ import { msg } from '@lingui/core/macro';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity';
@@ -37,6 +38,7 @@ export class TaskTargetWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconCheckbox',
inverseSideTarget: () => TaskWorkspaceEntity,
inverseSideFieldKey: 'taskTargets',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
task: Relation<TaskWorkspaceEntity> | null;
@@ -52,6 +54,7 @@ export class TaskTargetWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconUser',
inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'taskTargets',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null;
@@ -67,6 +70,7 @@ export class TaskTargetWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconBuildingSkyscraper',
inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'taskTargets',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null;
@@ -82,6 +86,7 @@ export class TaskTargetWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconTargetArrow',
inverseSideTarget: () => OpportunityWorkspaceEntity,
inverseSideFieldKey: 'taskTargets',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
opportunity: Relation<OpportunityWorkspaceEntity> | null;
@@ -101,6 +106,7 @@ export class TaskTargetWorkspaceEntity extends BaseWorkspaceEntity {
}),
inverseSideTarget: () => CustomWorkspaceEntity,
inverseSideFieldKey: 'taskTargets',
onDelete: RelationOnDeleteAction.CASCADE,
})
custom: Relation<CustomWorkspaceEntity>;
}
@@ -3,6 +3,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
@@ -92,6 +93,7 @@ export class AuditLogWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconCircleUser',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'auditLogs',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null;
@@ -3,6 +3,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { CustomWorkspaceEntity } from 'src/engine/twenty-orm/custom.workspace-entity';
@@ -106,6 +107,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconCircleUser',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null;
@@ -121,6 +123,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconUser',
inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null;
@@ -136,6 +139,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconBuildingSkyscraper',
inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
company: Relation<CompanyWorkspaceEntity> | null;
@@ -151,6 +155,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconTargetArrow',
inverseSideTarget: () => OpportunityWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
opportunity: Relation<OpportunityWorkspaceEntity> | null;
@@ -166,6 +171,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconTargetArrow',
inverseSideTarget: () => NoteWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
note: Relation<NoteWorkspaceEntity> | null;
@@ -181,6 +187,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconTargetArrow',
inverseSideTarget: () => TaskWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
task: Relation<TaskWorkspaceEntity> | null;
@@ -196,6 +203,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconTargetArrow',
inverseSideTarget: () => WorkflowWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
workflow: Relation<WorkflowWorkspaceEntity> | null;
@@ -211,6 +219,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconTargetArrow',
inverseSideTarget: () => WorkflowVersionWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
workflowVersion: Relation<WorkflowVersionWorkspaceEntity> | null;
@@ -226,6 +235,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconTargetArrow',
inverseSideTarget: () => WorkflowRunWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
workflowRun: Relation<WorkflowRunWorkspaceEntity> | null;
@@ -245,6 +255,7 @@ export class TimelineActivityWorkspaceEntity extends BaseWorkspaceEntity {
}),
inverseSideTarget: () => CustomWorkspaceEntity,
inverseSideFieldKey: 'timelineActivities',
onDelete: RelationOnDeleteAction.CASCADE,
})
custom: Relation<CustomWorkspaceEntity>;
}
@@ -3,6 +3,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
@@ -45,6 +46,7 @@ export class WorkflowEventListenerWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconSettingsAutomation',
inverseSideTarget: () => WorkflowWorkspaceEntity,
inverseSideFieldKey: 'eventListeners',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
workflow: Relation<WorkflowWorkspaceEntity>;
@@ -169,6 +169,7 @@ export class WorkflowRunWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconVersions',
inverseSideTarget: () => WorkflowVersionWorkspaceEntity,
inverseSideFieldKey: 'runs',
onDelete: RelationOnDeleteAction.SET_NULL,
})
workflowVersion: Relation<WorkflowVersionWorkspaceEntity>;
@@ -183,6 +184,7 @@ export class WorkflowRunWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconSettingsAutomation',
inverseSideTarget: () => WorkflowWorkspaceEntity,
inverseSideFieldKey: 'runs',
onDelete: RelationOnDeleteAction.CASCADE,
})
workflow: Relation<WorkflowWorkspaceEntity>;
@@ -127,6 +127,7 @@ export class WorkflowVersionWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconSettingsAutomation',
inverseSideTarget: () => WorkflowWorkspaceEntity,
inverseSideFieldKey: 'versions',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsNullable()
workflow: Relation<WorkflowWorkspaceEntity>;