Seed morph metadata (#14149)
in thie PR we create the tooling to allow the relation and morph relation creation during the seed process. We use the ObjectMetadataMaps in order to fasten the process Fixes https://github.com/twentyhq/core-team-issues/issues/1179
This commit is contained in:
+4
@@ -83,6 +83,10 @@ export const fromCachedFieldMetadataEntityToFlatFieldMetadata = <
|
||||
!isCachedFieldMetadataEntityOfType(
|
||||
relationTargetCachedFieldMetadata,
|
||||
FieldMetadataType.RELATION,
|
||||
) &&
|
||||
!isCachedFieldMetadataEntityOfType(
|
||||
relationTargetCachedFieldMetadata,
|
||||
FieldMetadataType.MORPH_RELATION,
|
||||
)
|
||||
) {
|
||||
throw new WorkspaceMetadataCacheException(
|
||||
|
||||
@@ -12,6 +12,7 @@ import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadat
|
||||
import { ObjectPermissionModule } from 'src/engine/metadata-modules/object-permission/object-permission.module';
|
||||
import { RoleModule } from 'src/engine/metadata-modules/role/role.module';
|
||||
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
|
||||
import { WorkspaceMetadataCacheModule } from 'src/engine/metadata-modules/workspace-metadata-cache/workspace-metadata-cache.module';
|
||||
import { WorkspacePermissionsCacheModule } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.module';
|
||||
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||
@@ -38,6 +39,7 @@ import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/worksp
|
||||
TypeOrmModule.forFeature([Workspace, ObjectMetadataEntity]),
|
||||
ObjectPermissionModule,
|
||||
WorkspacePermissionsCacheModule,
|
||||
WorkspaceMetadataCacheModule,
|
||||
],
|
||||
exports: [DevSeederService],
|
||||
providers: [
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { FieldMetadataType, RelationType } from 'twenty-shared/types';
|
||||
|
||||
import { type FieldMetadataSeed } from 'src/engine/workspace-manager/dev-seeder/metadata/types/field-metadata-seed.type';
|
||||
|
||||
export const PET_CUSTOM_RELATION_FIELD_SEEDS: (FieldMetadataSeed & {
|
||||
targetObjectMetadataNames: string[];
|
||||
})[] = [
|
||||
{
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
label: 'Owner of the Pet (rocket or survey)',
|
||||
name: 'owner',
|
||||
icon: 'IconRelationManyToOne',
|
||||
morphRelationsCreationPayload: [
|
||||
{
|
||||
type: RelationType.MANY_TO_ONE,
|
||||
targetObjectMetadataId: 'to-be-resolved-later',
|
||||
targetFieldLabel: 'Owned by',
|
||||
targetFieldIcon: 'IconRelationOneToMany',
|
||||
},
|
||||
],
|
||||
targetObjectMetadataNames: ['surveyResult', 'rocket'],
|
||||
},
|
||||
];
|
||||
+117
@@ -1,11 +1,15 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
import { type DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||
import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service';
|
||||
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service';
|
||||
import {
|
||||
SEED_APPLE_WORKSPACE_ID,
|
||||
SEED_YCOMBINATOR_WORKSPACE_ID,
|
||||
@@ -13,6 +17,7 @@ import {
|
||||
import { COMPANY_CUSTOM_FIELD_SEEDS } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-fields/constants/company-custom-field-seeds.constant';
|
||||
import { PERSON_CUSTOM_FIELD_SEEDS } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-fields/constants/person-custom-field-seeds.constant';
|
||||
import { PET_CUSTOM_FIELD_SEEDS } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-fields/constants/pet-custom-field-seeds.constant';
|
||||
import { PET_CUSTOM_RELATION_FIELD_SEEDS } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-fields/constants/pet-custom-relation-field-seeds.constant';
|
||||
import { SURVEY_RESULT_CUSTOM_FIELD_SEEDS } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-fields/constants/survey-results-field-seeds.constant';
|
||||
import { PET_CUSTOM_OBJECT_SEED } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-objects/constants/pet-custom-object-seed.constant';
|
||||
import { ROCKET_CUSTOM_OBJECT_SEED } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-objects/constants/rocket-custom-object-seed.constant';
|
||||
@@ -26,6 +31,7 @@ export class DevSeederMetadataService {
|
||||
constructor(
|
||||
private readonly objectMetadataService: ObjectMetadataService,
|
||||
private readonly fieldMetadataService: FieldMetadataService,
|
||||
private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
) {}
|
||||
@@ -35,6 +41,10 @@ export class DevSeederMetadataService {
|
||||
{
|
||||
objects: { seed: ObjectMetadataSeed; fields?: FieldMetadataSeed[] }[];
|
||||
fields: { objectName: string; seeds: FieldMetadataSeed[] }[];
|
||||
relations?: {
|
||||
objectName: string;
|
||||
seeds: (FieldMetadataSeed & { targetObjectMetadataNames: string[] })[];
|
||||
}[];
|
||||
}
|
||||
> = {
|
||||
[SEED_APPLE_WORKSPACE_ID]: {
|
||||
@@ -50,6 +60,9 @@ export class DevSeederMetadataService {
|
||||
{ objectName: 'company', seeds: COMPANY_CUSTOM_FIELD_SEEDS },
|
||||
{ objectName: 'person', seeds: PERSON_CUSTOM_FIELD_SEEDS },
|
||||
],
|
||||
relations: [
|
||||
{ objectName: 'pet', seeds: PET_CUSTOM_RELATION_FIELD_SEEDS },
|
||||
],
|
||||
},
|
||||
[SEED_YCOMBINATOR_WORKSPACE_ID]: {
|
||||
objects: [
|
||||
@@ -169,4 +182,108 @@ export class DevSeederMetadataService {
|
||||
schemaName: dataSourceMetadata.schema,
|
||||
});
|
||||
}
|
||||
|
||||
public async seedRelations({ workspaceId }: { workspaceId: string }) {
|
||||
const config = this.workspaceConfigs[workspaceId];
|
||||
|
||||
if (!config) {
|
||||
throw new Error(
|
||||
`Workspace configuration not found for workspaceId: ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!config.relations) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const relation of config.relations) {
|
||||
await this.seedCustomRelation({
|
||||
workspaceId,
|
||||
relation,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async seedCustomRelation({
|
||||
workspaceId,
|
||||
relation,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
relation: {
|
||||
objectName: string;
|
||||
seeds: (FieldMetadataSeed & { targetObjectMetadataNames: string[] })[];
|
||||
};
|
||||
}): Promise<void> {
|
||||
const { objectMetadataMaps } =
|
||||
await this.workspaceMetadataCacheService.getExistingOrRecomputeMetadataMaps(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
const relationFieldInputs = this.createFieldInputs({
|
||||
relation,
|
||||
objectMetadataMaps,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
await this.fieldMetadataService.createMany(relationFieldInputs);
|
||||
}
|
||||
|
||||
private createFieldInputs({
|
||||
relation,
|
||||
objectMetadataMaps,
|
||||
workspaceId,
|
||||
}: {
|
||||
relation: {
|
||||
objectName: string;
|
||||
seeds: (FieldMetadataSeed & { targetObjectMetadataNames: string[] })[];
|
||||
};
|
||||
objectMetadataMaps: ObjectMetadataMaps;
|
||||
workspaceId: string;
|
||||
}): CreateFieldInput[] {
|
||||
const objectMetadataId =
|
||||
objectMetadataMaps.idByNameSingular[relation.objectName];
|
||||
|
||||
if (!isDefined(objectMetadataId)) {
|
||||
throw new Error(
|
||||
`Object metadata id not found for: ${relation.objectName}`,
|
||||
);
|
||||
}
|
||||
|
||||
const relationFieldInputs = relation.seeds.map((seed) => ({
|
||||
type: seed.type,
|
||||
label: seed.label,
|
||||
name: seed.name,
|
||||
objectMetadataId,
|
||||
workspaceId,
|
||||
morphRelationsCreationPayload: seed.targetObjectMetadataNames.map(
|
||||
(targetObjectMetadataName) => {
|
||||
const targetObjectMetadataId =
|
||||
objectMetadataMaps.idByNameSingular[targetObjectMetadataName];
|
||||
|
||||
if (!isDefined(targetObjectMetadataId)) {
|
||||
throw new Error(
|
||||
`Target object metadata id not found for: ${targetObjectMetadataName}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!isDefined(seed.morphRelationsCreationPayload)) {
|
||||
throw new Error('Morph relations creation payload is not defined');
|
||||
}
|
||||
|
||||
return {
|
||||
type: seed.morphRelationsCreationPayload[0].type,
|
||||
targetFieldLabel:
|
||||
seed.morphRelationsCreationPayload[0].targetFieldLabel,
|
||||
targetFieldIcon:
|
||||
seed.morphRelationsCreationPayload[0].targetFieldIcon,
|
||||
targetObjectMetadataId,
|
||||
};
|
||||
},
|
||||
),
|
||||
}));
|
||||
|
||||
return relationFieldInputs;
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -66,6 +66,10 @@ export class DevSeederService {
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
await this.devSeederMetadataService.seedRelations({
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
await this.devSeederPermissionsService.initPermissions(workspaceId);
|
||||
|
||||
await this.devSeederDataService.seed({
|
||||
|
||||
Reference in New Issue
Block a user