MORPH for relationDecorator (#15420)
# Adding MORPH support to the relationDecorator
Extends the @WorkspaceRelation decorator to support morph relations by
adding isMorphRelation and morphId options
The implementation enforces type safety through TypeScript discriminated
unions, ensuring morphId is required when isMorphRelation: true, and
includes runtime validation that throws a descriptive error if morphId
is missing.
The morph relation metadata is properly stored in metadataArgsStorage
and integrates seamlessly with the existing StandardFieldRelationFactory
to convert decorated fields into FieldMetadataType.MORPH_RELATION
entities with appropriate database constraints.
To test :
in person entity, add
```ts
@WorkspaceRelation({
standardId: PERSON_STANDARD_FIELD_IDS.testRelatedRecordCompany,
type: RelationType.MANY_TO_ONE,
label: msg`Test Related Record of Company`,
description: msg`Test relation to company`,
icon: 'IconLink',
inverseSideTarget: () => CompanyWorkspaceEntity,
inverseSideFieldKey: 'testRelatedPeople',
onDelete: RelationOnDeleteAction.CASCADE,
isMorphRelation: true,
morphId: PERSON_STANDARD_FIELD_IDS.testRelatedRecordMorphId,
})
@WorkspaceIsNullable()
@WorkspaceIsSystem()
testRelatedRecordCompany: Relation<CompanyWorkspaceEntity> | null;
@WorkspaceJoinColumn('testRelatedRecordCompany')
testRelatedRecordCompanyId: string | null;
@WorkspaceRelation({
standardId: PERSON_STANDARD_FIELD_IDS.testRelatedRecordOpportunity,
type: RelationType.MANY_TO_ONE,
label: msg`Test Related Record of Opportunity`,
description: msg`Test relation to opportunity`,
icon: 'IconLink',
inverseSideTarget: () => OpportunityWorkspaceEntity,
inverseSideFieldKey: 'testRelatedPeople',
onDelete: RelationOnDeleteAction.CASCADE,
isMorphRelation: true,
morphId: PERSON_STANDARD_FIELD_IDS.testRelatedRecordMorphId,
})
@WorkspaceIsNullable()
@WorkspaceIsSystem()
testRelatedRecordOpportunity: Relation<OpportunityWorkspaceEntity> | null;
@WorkspaceJoinColumn('testRelatedRecordOpportunity')
testRelatedRecordOpportunityId: string | null;
```
in opportunity,
```ts
@WorkspaceRelation({
standardId: OPPORTUNITY_STANDARD_FIELD_IDS.testRelatedPeople,
type: RelationType.ONE_TO_MANY,
label: msg`Test Related People`,
description: msg`People linked to the opportunity via Test Related Record`,
icon: 'IconUsers',
inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'testRelatedRecordOpportunity',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
@WorkspaceIsSystem()
testRelatedPeople: Relation<PersonWorkspaceEntity[]>;
```
in company,
```ts
@WorkspaceRelation({
standardId: COMPANY_STANDARD_FIELD_IDS.testRelatedPeople,
type: RelationType.ONE_TO_MANY,
label: msg`Test Related People`,
description: msg`People linked to the company via Test Related Record`,
icon: 'IconUsers',
inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'testRelatedRecordCompany',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsNullable()
@WorkspaceIsSystem()
testRelatedPeople: Relation<PersonWorkspaceEntity[]>;
```
In constants/standard-field-ids.ts, add the standard fields ids
```ts
// COMPANY_STANDARD_FIELD_IDS
testRelatedPeople: '20202020-7a90-47e9-b31f-916a716fd212',
// OPPORTUNITY_STANDARD_FIELD_IDS
testRelatedPeople: '20202020-7a90-47e9-b31f-916a716fd213',
// PERSON_STANDARD_FIELD_IDS
testRelatedRecordOpportunity: '20202020-5a90-47e9-b31f-916a716fd211',
testRelatedRecordCompany: '20202020-1eb2-4298-910b-66b015b36d72',
testRelatedRecordMorphId: '20202020-6ccf-48e3-bb92-bc9961bc011e',
```
This commit is contained in:
+41
-8
@@ -1,4 +1,6 @@
|
||||
import { type MessageDescriptor } from '@lingui/core';
|
||||
import { isDefined, isUUID } from 'class-validator';
|
||||
import { CustomError } from 'twenty-shared/utils';
|
||||
import { type ObjectType } from 'typeorm';
|
||||
|
||||
import { type RelationOnDeleteAction } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-on-delete-action.interface';
|
||||
@@ -9,7 +11,7 @@ import { computeMetadataNameFromLabel } from 'src/engine/metadata-modules/utils/
|
||||
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
|
||||
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||
|
||||
interface WorkspaceRelationBaseOptions<TClass> {
|
||||
interface WorkspaceRelationMinimumBaseOptions<TClass> {
|
||||
standardId: string;
|
||||
label: MessageDescriptor;
|
||||
description?:
|
||||
@@ -21,17 +23,32 @@ interface WorkspaceRelationBaseOptions<TClass> {
|
||||
onDelete?: RelationOnDeleteAction;
|
||||
}
|
||||
|
||||
interface WorkspaceOtherRelationOptions<TClass>
|
||||
extends WorkspaceRelationBaseOptions<TClass> {
|
||||
type: RelationType.ONE_TO_MANY;
|
||||
interface WorkspaceRegularRelationBaseOptions<TClass>
|
||||
extends WorkspaceRelationMinimumBaseOptions<TClass> {
|
||||
isMorphRelation?: false;
|
||||
}
|
||||
|
||||
interface WorkspaceManyToOneRelationOptions<TClass extends object>
|
||||
extends WorkspaceRelationBaseOptions<TClass> {
|
||||
type: RelationType.MANY_TO_ONE;
|
||||
inverseSideFieldKey: keyof TClass;
|
||||
interface WorkspaceMorphRelationBaseOptions<TClass>
|
||||
extends WorkspaceRelationMinimumBaseOptions<TClass> {
|
||||
isMorphRelation: true;
|
||||
morphId: string;
|
||||
}
|
||||
|
||||
type WorkspaceRelationBaseOptions<TClass> =
|
||||
| WorkspaceRegularRelationBaseOptions<TClass>
|
||||
| WorkspaceMorphRelationBaseOptions<TClass>;
|
||||
|
||||
type WorkspaceOtherRelationOptions<TClass> =
|
||||
WorkspaceRelationBaseOptions<TClass> & {
|
||||
type: RelationType.ONE_TO_MANY;
|
||||
};
|
||||
|
||||
type WorkspaceManyToOneRelationOptions<TClass extends object> =
|
||||
WorkspaceRelationBaseOptions<TClass> & {
|
||||
type: RelationType.MANY_TO_ONE;
|
||||
inverseSideFieldKey: keyof TClass;
|
||||
};
|
||||
|
||||
type WorkspaceRelationOptions<TClass extends object> =
|
||||
| WorkspaceOtherRelationOptions<TClass>
|
||||
| WorkspaceManyToOneRelationOptions<TClass>;
|
||||
@@ -73,6 +90,20 @@ export function WorkspaceRelation<TClass extends object>(
|
||||
const label = options.label.message ?? '';
|
||||
const isLabelSyncedWithName = computeMetadataNameFromLabel(label) === name;
|
||||
|
||||
if (options.isMorphRelation && !isDefined(options.morphId)) {
|
||||
throw new CustomError(
|
||||
'Morph relation must have a morph id',
|
||||
'MORPH_RELATION_MUST_HAVE_MORPH_ID',
|
||||
);
|
||||
}
|
||||
|
||||
if (options.isMorphRelation && !isUUID(options.morphId)) {
|
||||
throw new CustomError(
|
||||
'Morph ID must be a valid UUID',
|
||||
'INVALID_MORPH_ID_FORMAT',
|
||||
);
|
||||
}
|
||||
|
||||
metadataArgsStorage.addRelations({
|
||||
target: object.constructor,
|
||||
standardId: options.standardId,
|
||||
@@ -97,6 +128,8 @@ export function WorkspaceRelation<TClass extends object>(
|
||||
isSystem,
|
||||
isUIReadOnly,
|
||||
gate,
|
||||
isMorphRelation: options.isMorphRelation ?? false,
|
||||
morphId: options.isMorphRelation ? options.morphId : undefined,
|
||||
isLabelSyncedWithName,
|
||||
});
|
||||
};
|
||||
|
||||
+10
@@ -91,4 +91,14 @@ export interface WorkspaceRelationMetadataArgs {
|
||||
readonly isActive?: boolean;
|
||||
|
||||
readonly isLabelSyncedWithName: boolean;
|
||||
|
||||
/**
|
||||
* Is morph relation.
|
||||
*/
|
||||
readonly isMorphRelation: boolean;
|
||||
|
||||
/**
|
||||
* Morph id.
|
||||
*/
|
||||
readonly morphId?: string;
|
||||
}
|
||||
|
||||
+4
@@ -57,6 +57,10 @@ export const createIndexMigration = async (
|
||||
isFieldMetadataEntityOfType(
|
||||
fieldMetadata,
|
||||
FieldMetadataType.RELATION,
|
||||
) ||
|
||||
isFieldMetadataEntityOfType(
|
||||
fieldMetadata,
|
||||
FieldMetadataType.MORPH_RELATION,
|
||||
)
|
||||
) {
|
||||
if (!fieldMetadata.settings) {
|
||||
|
||||
+12
-4
@@ -26,7 +26,9 @@ export class WorkspaceMigrationFieldRelationFactory {
|
||||
|
||||
async create(
|
||||
originalObjectMetadataCollection: ObjectMetadataEntity[],
|
||||
fieldMetadataCollection: FieldMetadataEntity<FieldMetadataType.RELATION>[],
|
||||
fieldMetadataCollection: FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[],
|
||||
action:
|
||||
| WorkspaceMigrationBuilderAction.CREATE
|
||||
| WorkspaceMigrationBuilderAction.DELETE,
|
||||
@@ -34,7 +36,9 @@ export class WorkspaceMigrationFieldRelationFactory {
|
||||
|
||||
async create(
|
||||
originalObjectMetadataCollection: ObjectMetadataEntity[],
|
||||
fieldMetadataUpdateCollection: FieldMetadataUpdate<FieldMetadataType.RELATION>[],
|
||||
fieldMetadataUpdateCollection: FieldMetadataUpdate<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[],
|
||||
action: WorkspaceMigrationBuilderAction.UPDATE,
|
||||
): Promise<Partial<WorkspaceMigrationEntity>[]>;
|
||||
|
||||
@@ -44,8 +48,12 @@ export class WorkspaceMigrationFieldRelationFactory {
|
||||
async create(
|
||||
originalObjectMetadataCollection: ObjectMetadataEntity[],
|
||||
fieldMetadataCollectionOrFieldMetadataUpdateCollection:
|
||||
| FieldMetadataEntity<FieldMetadataType.RELATION>[]
|
||||
| FieldMetadataUpdate<FieldMetadataType.RELATION>[],
|
||||
| FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[]
|
||||
| FieldMetadataUpdate<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[],
|
||||
action: WorkspaceMigrationBuilderAction,
|
||||
): Promise<Partial<WorkspaceMigrationEntity>[]> {
|
||||
const originalObjectMetadataMap = originalObjectMetadataCollection.reduce(
|
||||
|
||||
+3
-1
@@ -189,10 +189,12 @@ export class WorkspaceMigrationRunnerService {
|
||||
|
||||
case WorkspaceMigrationTableActionType.ALTER_INDEXES:
|
||||
if (tableMigration.indexes && tableMigration.indexes.length > 0) {
|
||||
const tableName = tableMigration.newName ?? tableMigration.name;
|
||||
|
||||
await this.handleIndexesChanges(
|
||||
queryRunner,
|
||||
schemaName,
|
||||
tableMigration.newName ?? tableMigration.name,
|
||||
tableName,
|
||||
tableMigration.indexes,
|
||||
);
|
||||
}
|
||||
|
||||
+20
-4
@@ -25,13 +25,21 @@ export class WorkspaceFieldRelationComparator {
|
||||
constructor() {}
|
||||
|
||||
public compare(
|
||||
originalFieldMetadataCollection: FieldMetadataEntity<FieldMetadataType.RELATION>[],
|
||||
standardFieldMetadataCollection: FieldMetadataEntity<FieldMetadataType.RELATION>[],
|
||||
originalFieldMetadataCollection: FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[],
|
||||
standardFieldMetadataCollection: FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[],
|
||||
): FieldRelationComparatorResult[] {
|
||||
const result: FieldRelationComparatorResult[] = [];
|
||||
const propertiesMap: Record<
|
||||
string,
|
||||
Partial<FieldMetadataEntity<FieldMetadataType.RELATION>>
|
||||
Partial<
|
||||
FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>
|
||||
>
|
||||
> = {};
|
||||
|
||||
// Double security to only compare non-custom fields
|
||||
@@ -103,7 +111,9 @@ export class WorkspaceFieldRelationComparator {
|
||||
fieldMetadataDifferenceMap,
|
||||
)) {
|
||||
const findField = (
|
||||
field: FieldMetadataEntity<FieldMetadataType.RELATION>,
|
||||
field: FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>,
|
||||
) => {
|
||||
return field.standardId === fieldId;
|
||||
};
|
||||
@@ -211,6 +221,8 @@ export class WorkspaceFieldRelationComparator {
|
||||
standardId: standardFieldMetadata.standardId ?? undefined,
|
||||
description: relationFieldMetadata.description ?? undefined,
|
||||
icon: relationFieldMetadata.icon ?? undefined,
|
||||
type: standardFieldMetadata.type,
|
||||
morphId: standardFieldMetadata.morphId ?? undefined,
|
||||
},
|
||||
});
|
||||
} else if (allOldPropertiesAreNull) {
|
||||
@@ -222,6 +234,8 @@ export class WorkspaceFieldRelationComparator {
|
||||
standardId: standardFieldMetadata.standardId ?? undefined,
|
||||
description: relationFieldMetadata.description ?? undefined,
|
||||
icon: relationFieldMetadata.icon ?? undefined,
|
||||
type: standardFieldMetadata.type,
|
||||
morphId: standardFieldMetadata.morphId ?? undefined,
|
||||
},
|
||||
});
|
||||
} else if (allNewPropertiesAreNull) {
|
||||
@@ -238,6 +252,8 @@ export class WorkspaceFieldRelationComparator {
|
||||
standardId: standardFieldMetadata.standardId ?? undefined,
|
||||
description: relationFieldMetadata.description ?? undefined,
|
||||
icon: relationFieldMetadata.icon ?? undefined,
|
||||
type: standardFieldMetadata.type,
|
||||
morphId: standardFieldMetadata.morphId ?? undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
+13
-4
@@ -21,7 +21,9 @@ export class StandardFieldRelationFactory {
|
||||
computeRelationFieldsForCustomObject(
|
||||
customObjectMetadata: ObjectMetadataEntity,
|
||||
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
|
||||
): FieldMetadataEntity<FieldMetadataType.RELATION>[] {
|
||||
): FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[] {
|
||||
const workspaceRelationMetadataArgsCollection =
|
||||
metadataArgsStorage.filterRelations(CustomWorkspaceEntity);
|
||||
|
||||
@@ -111,7 +113,9 @@ export class StandardFieldRelationFactory {
|
||||
standardObjectMetadataWorkspaceEntity: typeof BaseWorkspaceEntity,
|
||||
context: WorkspaceSyncContext,
|
||||
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
|
||||
): FieldMetadataEntity<FieldMetadataType.RELATION>[] {
|
||||
): FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[] {
|
||||
const workspaceEntityMetadataArgs = metadataArgsStorage.filterEntities(
|
||||
standardObjectMetadataWorkspaceEntity,
|
||||
);
|
||||
@@ -282,9 +286,13 @@ export class StandardFieldRelationFactory {
|
||||
);
|
||||
}
|
||||
|
||||
const type = workspaceRelationMetadataArgs.isMorphRelation
|
||||
? FieldMetadataType.MORPH_RELATION
|
||||
: FieldMetadataType.RELATION;
|
||||
|
||||
return {
|
||||
...sourceFieldMetadata,
|
||||
type: FieldMetadataType.RELATION,
|
||||
type,
|
||||
settings: {
|
||||
relationType: workspaceRelationMetadataArgs.type,
|
||||
onDelete:
|
||||
@@ -293,9 +301,10 @@ export class StandardFieldRelationFactory {
|
||||
: undefined,
|
||||
joinColumnName,
|
||||
},
|
||||
morphId: workspaceRelationMetadataArgs.morphId ?? null,
|
||||
relationTargetObjectMetadataId: targetObjectMetadata.id,
|
||||
relationTargetFieldMetadataId: targetFieldMetadata.id,
|
||||
} satisfies FieldMetadataEntity<FieldMetadataType.RELATION>;
|
||||
} satisfies FieldMetadataEntity<typeof type>;
|
||||
});
|
||||
|
||||
return [...staticRelations, ...relationsFromDynamicRelations];
|
||||
|
||||
+17
-3
@@ -56,16 +56,30 @@ export type FieldComparatorResult =
|
||||
export type FieldRelationComparatorResult =
|
||||
| ComparatorSkipResult
|
||||
| ComparatorCreateResult<
|
||||
Partial<ComputedPartialFieldMetadata<FieldMetadataType.RELATION>> & {
|
||||
Partial<
|
||||
ComputedPartialFieldMetadata<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>
|
||||
> & {
|
||||
id: string;
|
||||
type: FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION;
|
||||
}
|
||||
>
|
||||
| ComparatorUpdateResult<
|
||||
Partial<ComputedPartialFieldMetadata<FieldMetadataType.RELATION>> & {
|
||||
Partial<
|
||||
ComputedPartialFieldMetadata<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>
|
||||
> & {
|
||||
id: string;
|
||||
type: FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION;
|
||||
}
|
||||
>
|
||||
| ComparatorDeleteResult<FieldMetadataEntity<FieldMetadataType.RELATION>>;
|
||||
| ComparatorDeleteResult<
|
||||
FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>
|
||||
>;
|
||||
|
||||
export type IndexComparatorResult =
|
||||
| ComparatorCreateResult<Partial<IndexMetadataEntity>>
|
||||
|
||||
+32
-12
@@ -17,6 +17,7 @@ import { type PartialFieldMetadata } from 'src/engine/workspace-manager/workspac
|
||||
import { type PartialIndexMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-index-metadata.interface';
|
||||
import { type UpdaterOptions } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/updater-options.interface';
|
||||
|
||||
import { isFieldMetadataRelationOrMorphRelation } from 'src/engine/api/graphql/workspace-schema-builder/utils/is-field-metadata-relation-or-morph-relation.utils';
|
||||
import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types';
|
||||
import { type FieldMetadataComplexOption } from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
@@ -212,21 +213,31 @@ export class WorkspaceMetadataUpdaterService {
|
||||
storage: WorkspaceSyncStorage,
|
||||
options?: UpdaterOptions,
|
||||
): Promise<{
|
||||
createdFieldRelationMetadataCollection: FieldMetadataUpdate<FieldMetadataType.RELATION>[];
|
||||
updatedFieldRelationMetadataCollection: FieldMetadataUpdate<FieldMetadataType.RELATION>[];
|
||||
deletedFieldRelationMetadataCollection: FieldMetadataUpdate<FieldMetadataType.RELATION>[];
|
||||
createdFieldRelationMetadataCollection: FieldMetadataUpdate<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[];
|
||||
updatedFieldRelationMetadataCollection: FieldMetadataUpdate<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[];
|
||||
deletedFieldRelationMetadataCollection: FieldMetadataUpdate<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[];
|
||||
}> {
|
||||
let createdFieldRelationMetadataCollection: FieldMetadataUpdate<FieldMetadataType.RELATION>[] =
|
||||
[];
|
||||
let updatedFieldRelationMetadataCollection: FieldMetadataUpdate<FieldMetadataType.RELATION>[] =
|
||||
[];
|
||||
let createdFieldRelationMetadataCollection: FieldMetadataUpdate<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[] = [];
|
||||
let updatedFieldRelationMetadataCollection: FieldMetadataUpdate<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[] = [];
|
||||
|
||||
/**
|
||||
* Create field relation metadata
|
||||
*/
|
||||
if (!options || options.actions.includes('create')) {
|
||||
createdFieldRelationMetadataCollection = await this.updateEntities<
|
||||
FieldMetadataEntity<FieldMetadataType.RELATION>
|
||||
FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>
|
||||
>(
|
||||
manager,
|
||||
FieldMetadataEntity,
|
||||
@@ -240,7 +251,9 @@ export class WorkspaceMetadataUpdaterService {
|
||||
*/
|
||||
if (!options || options.actions.includes('update')) {
|
||||
updatedFieldRelationMetadataCollection = await this.updateEntities<
|
||||
FieldMetadataEntity<FieldMetadataType.RELATION>
|
||||
FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>
|
||||
>(
|
||||
manager,
|
||||
FieldMetadataEntity,
|
||||
@@ -320,14 +333,21 @@ export class WorkspaceMetadataUpdaterService {
|
||||
const fieldMetadata = originalObjectMetadataCollection
|
||||
.find((object) => object.id === indexMetadata.objectMetadataId)
|
||||
?.fields.find((field) => {
|
||||
if (
|
||||
isFieldMetadataEntityOfType(field, FieldMetadataType.RELATION)
|
||||
) {
|
||||
if (isFieldMetadataRelationOrMorphRelation(field)) {
|
||||
if (field.settings?.joinColumnName === column) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
isFieldMetadataEntityOfType(
|
||||
field,
|
||||
FieldMetadataType.MORPH_RELATION,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (field.name === column) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+12
-4
@@ -177,8 +177,12 @@ export class WorkspaceSyncFieldMetadataRelationService {
|
||||
|
||||
const originalFieldRelationMetadataCollection =
|
||||
(originalObjectMetadata?.fields.filter(
|
||||
(field) => field.type === FieldMetadataType.RELATION,
|
||||
) ?? []) as FieldMetadataEntity<FieldMetadataType.RELATION>[];
|
||||
(field) =>
|
||||
field.type === FieldMetadataType.RELATION ||
|
||||
field.type === FieldMetadataType.MORPH_RELATION,
|
||||
) ?? []) as FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[];
|
||||
|
||||
if (originalFieldRelationMetadataCollection.length === 0) {
|
||||
continue;
|
||||
@@ -204,8 +208,12 @@ export class WorkspaceSyncFieldMetadataRelationService {
|
||||
for (const customObjectMetadata of customObjectMetadataCollection) {
|
||||
const originalFieldRelationMetadataCollection =
|
||||
(customObjectMetadata.fields.filter(
|
||||
(field) => field.type === FieldMetadataType.RELATION,
|
||||
) ?? []) as FieldMetadataEntity<FieldMetadataType.RELATION>[];
|
||||
(field) =>
|
||||
field.type === FieldMetadataType.RELATION ||
|
||||
field.type === FieldMetadataType.MORPH_RELATION,
|
||||
) ?? []) as FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[];
|
||||
|
||||
const customFieldMetadataRelationCollection =
|
||||
this.standardFieldRelationFactory.computeRelationFieldsForCustomObject(
|
||||
|
||||
+26
-7
@@ -30,17 +30,24 @@ export class WorkspaceSyncStorage {
|
||||
|
||||
// Field relation metadata
|
||||
private readonly _fieldRelationMetadataCreateCollection: (Partial<
|
||||
ComputedPartialFieldMetadata<FieldMetadataType.RELATION>
|
||||
ComputedPartialFieldMetadata<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>
|
||||
> & {
|
||||
id: string;
|
||||
type?: FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION;
|
||||
})[] = [];
|
||||
private readonly _fieldRelationMetadataUpdateCollection: (Partial<
|
||||
ComputedPartialFieldMetadata<FieldMetadataType.RELATION>
|
||||
ComputedPartialFieldMetadata<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>
|
||||
> & {
|
||||
id: string;
|
||||
type?: FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION;
|
||||
})[] = [];
|
||||
private readonly _fieldRelationMetadataDeleteCollection: FieldMetadataEntity<FieldMetadataType.RELATION>[] =
|
||||
[];
|
||||
private readonly _fieldRelationMetadataDeleteCollection: FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>[] = [];
|
||||
|
||||
// Index metadata
|
||||
private readonly _indexMetadataCreateCollection: Partial<IndexMetadataEntity>[] =
|
||||
@@ -124,23 +131,35 @@ export class WorkspaceSyncStorage {
|
||||
}
|
||||
|
||||
addCreateFieldRelationMetadata(
|
||||
field: Partial<ComputedPartialFieldMetadata<FieldMetadataType.RELATION>> & {
|
||||
field: Partial<
|
||||
ComputedPartialFieldMetadata<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>
|
||||
> & {
|
||||
id: string;
|
||||
type: FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION;
|
||||
},
|
||||
) {
|
||||
this._fieldRelationMetadataCreateCollection.push(field);
|
||||
}
|
||||
|
||||
addUpdateFieldRelationMetadata(
|
||||
field: Partial<ComputedPartialFieldMetadata<FieldMetadataType.RELATION>> & {
|
||||
field: Partial<
|
||||
ComputedPartialFieldMetadata<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>
|
||||
> & {
|
||||
id: string;
|
||||
type: FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION;
|
||||
},
|
||||
) {
|
||||
this._fieldRelationMetadataUpdateCollection.push(field);
|
||||
}
|
||||
|
||||
addDeleteFieldRelationMetadata(
|
||||
field: FieldMetadataEntity<FieldMetadataType.RELATION>,
|
||||
field: FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>,
|
||||
) {
|
||||
this._fieldRelationMetadataDeleteCollection.push(field);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user