feat: refactor folder structure (#4498)
* feat: wip refactor folder structure * Fix * fix position --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -0,0 +1,880 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import console from 'console';
|
||||
|
||||
import { FindManyOptions, FindOneOptions, Repository } from 'typeorm';
|
||||
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { Query, QueryOptions } from '@ptc-org/nestjs-query-core';
|
||||
|
||||
import { WorkspaceMigrationService } from 'src/engine-metadata/workspace-migration/workspace-migration.service';
|
||||
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service';
|
||||
import {
|
||||
WorkspaceMigrationColumnActionType,
|
||||
WorkspaceMigrationColumnCreate,
|
||||
WorkspaceMigrationColumnDrop,
|
||||
WorkspaceMigrationTableAction,
|
||||
} from 'src/engine-metadata/workspace-migration/workspace-migration.entity';
|
||||
import {
|
||||
FieldMetadataEntity,
|
||||
FieldMetadataType,
|
||||
} from 'src/engine-metadata/field-metadata/field-metadata.entity';
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { DataSourceService } from 'src/engine-metadata/data-source/data-source.service';
|
||||
import {
|
||||
RelationMetadataEntity,
|
||||
RelationMetadataType,
|
||||
RelationOnDeleteAction,
|
||||
} from 'src/engine-metadata/relation-metadata/relation-metadata.entity';
|
||||
import { computeCustomName } from 'src/engine-workspace/utils/compute-custom-name.util';
|
||||
import { computeObjectTargetTable } from 'src/engine-workspace/utils/compute-object-target-table.util';
|
||||
import { DeleteOneObjectInput } from 'src/engine-metadata/object-metadata/dtos/delete-object.input';
|
||||
import { RelationToDelete } from 'src/engine-metadata/relation-metadata/types/relation-to-delete';
|
||||
import { generateMigrationName } from 'src/engine-metadata/workspace-migration/utils/generate-migration-name.util';
|
||||
import {
|
||||
activityTargetStandardFieldIds,
|
||||
attachmentStandardFieldIds,
|
||||
baseObjectStandardFieldIds,
|
||||
customObjectStandardFieldIds,
|
||||
favoriteStandardFieldIds,
|
||||
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
|
||||
import { createDeterministicUuid } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util';
|
||||
|
||||
import { ObjectMetadataEntity } from './object-metadata.entity';
|
||||
|
||||
import { CreateObjectInput } from './dtos/create-object.input';
|
||||
|
||||
@Injectable()
|
||||
export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEntity> {
|
||||
constructor(
|
||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
||||
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
|
||||
@InjectRepository(FieldMetadataEntity, 'metadata')
|
||||
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
||||
|
||||
@InjectRepository(RelationMetadataEntity, 'metadata')
|
||||
private readonly relationMetadataRepository: Repository<RelationMetadataEntity>,
|
||||
|
||||
private readonly dataSourceService: DataSourceService,
|
||||
private readonly typeORMService: TypeORMService,
|
||||
private readonly workspaceMigrationService: WorkspaceMigrationService,
|
||||
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
|
||||
) {
|
||||
super(objectMetadataRepository);
|
||||
}
|
||||
|
||||
override async query(
|
||||
query: Query<ObjectMetadataEntity>,
|
||||
opts?: QueryOptions<ObjectMetadataEntity> | undefined,
|
||||
): Promise<ObjectMetadataEntity[]> {
|
||||
const start = performance.now();
|
||||
|
||||
const result = super.query(query, opts);
|
||||
|
||||
const end = performance.now();
|
||||
|
||||
console.log(`metadata query time: ${end - start} ms`);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async deleteOneObject(
|
||||
input: DeleteOneObjectInput,
|
||||
workspaceId: string,
|
||||
): Promise<ObjectMetadataEntity> {
|
||||
const objectMetadata = await this.objectMetadataRepository.findOne({
|
||||
relations: [
|
||||
'fromRelations.fromFieldMetadata',
|
||||
'fromRelations.toFieldMetadata',
|
||||
'toRelations.fromFieldMetadata',
|
||||
'toRelations.toFieldMetadata',
|
||||
'fromRelations.fromObjectMetadata',
|
||||
'fromRelations.toObjectMetadata',
|
||||
'toRelations.fromObjectMetadata',
|
||||
'toRelations.toObjectMetadata',
|
||||
],
|
||||
where: {
|
||||
id: input.id,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!objectMetadata) {
|
||||
throw new NotFoundException('Object does not exist');
|
||||
}
|
||||
|
||||
const relationsToDelete: RelationToDelete[] = [];
|
||||
|
||||
// TODO: Most of this logic should be moved to relation-metadata.service.ts
|
||||
for (const relation of [
|
||||
...objectMetadata.fromRelations,
|
||||
...objectMetadata.toRelations,
|
||||
]) {
|
||||
relationsToDelete.push({
|
||||
id: relation.id,
|
||||
fromFieldMetadataId: relation.fromFieldMetadata.id,
|
||||
toFieldMetadataId: relation.toFieldMetadata.id,
|
||||
fromFieldMetadataName: relation.fromFieldMetadata.name,
|
||||
toFieldMetadataName: relation.toFieldMetadata.name,
|
||||
fromObjectMetadataId: relation.fromObjectMetadata.id,
|
||||
toObjectMetadataId: relation.toObjectMetadata.id,
|
||||
fromObjectName: relation.fromObjectMetadata.nameSingular,
|
||||
toObjectName: relation.toObjectMetadata.nameSingular,
|
||||
toFieldMetadataIsCustom: relation.toFieldMetadata.isCustom,
|
||||
toObjectMetadataIsCustom: relation.toObjectMetadata.isCustom,
|
||||
direction:
|
||||
relation.fromObjectMetadata.nameSingular ===
|
||||
objectMetadata.nameSingular
|
||||
? 'from'
|
||||
: 'to',
|
||||
});
|
||||
}
|
||||
|
||||
await this.relationMetadataRepository.delete(
|
||||
relationsToDelete.map((relation) => relation.id),
|
||||
);
|
||||
|
||||
for (const relationToDelete of relationsToDelete) {
|
||||
const foreignKeyFieldsToDelete = await this.fieldMetadataRepository.find({
|
||||
where: {
|
||||
name: `${relationToDelete.toFieldMetadataName}Id`,
|
||||
objectMetadataId: relationToDelete.toObjectMetadataId,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
const foreignKeyFieldsToDeleteIds = foreignKeyFieldsToDelete.map(
|
||||
(field) => field.id,
|
||||
);
|
||||
|
||||
await this.fieldMetadataRepository.delete([
|
||||
...foreignKeyFieldsToDeleteIds,
|
||||
relationToDelete.fromFieldMetadataId,
|
||||
relationToDelete.toFieldMetadataId,
|
||||
]);
|
||||
|
||||
if (relationToDelete.direction === 'from') {
|
||||
await this.workspaceMigrationService.createCustomMigration(
|
||||
generateMigrationName(
|
||||
`delete-${relationToDelete.fromObjectName}-${relationToDelete.toObjectName}`,
|
||||
),
|
||||
workspaceId,
|
||||
[
|
||||
{
|
||||
name: computeCustomName(
|
||||
relationToDelete.toObjectName,
|
||||
relationToDelete.toObjectMetadataIsCustom,
|
||||
),
|
||||
action: 'alter',
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.DROP,
|
||||
columnName: computeCustomName(
|
||||
`${relationToDelete.toFieldMetadataName}Id`,
|
||||
relationToDelete.toFieldMetadataIsCustom,
|
||||
),
|
||||
} satisfies WorkspaceMigrationColumnDrop,
|
||||
],
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await this.objectMetadataRepository.delete(objectMetadata.id);
|
||||
|
||||
// DROP TABLE
|
||||
await this.workspaceMigrationService.createCustomMigration(
|
||||
generateMigrationName(`delete-${objectMetadata.nameSingular}`),
|
||||
workspaceId,
|
||||
[
|
||||
{
|
||||
name: computeObjectTargetTable(objectMetadata),
|
||||
action: 'drop',
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
return objectMetadata;
|
||||
}
|
||||
|
||||
override async createOne(
|
||||
objectMetadataInput: CreateObjectInput,
|
||||
): Promise<ObjectMetadataEntity> {
|
||||
const lastDataSourceMetadata =
|
||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
||||
objectMetadataInput.workspaceId,
|
||||
);
|
||||
|
||||
if (
|
||||
objectMetadataInput.nameSingular.toLowerCase() ===
|
||||
objectMetadataInput.namePlural.toLowerCase()
|
||||
) {
|
||||
throw new BadRequestException(
|
||||
'The singular and plural name cannot be the same for an object',
|
||||
);
|
||||
}
|
||||
|
||||
const createdObjectMetadata = await super.createOne({
|
||||
...objectMetadataInput,
|
||||
dataSourceId: lastDataSourceMetadata.id,
|
||||
targetTableName: 'DEPRECATED',
|
||||
isActive: true,
|
||||
isCustom: true,
|
||||
isSystem: false,
|
||||
fields:
|
||||
// Creating default fields.
|
||||
// No need to create a custom migration for this though as the default columns are already
|
||||
// created with default values which is not supported yet by workspace migrations.
|
||||
[
|
||||
{
|
||||
standardId: baseObjectStandardFieldIds.id,
|
||||
type: FieldMetadataType.UUID,
|
||||
name: 'id',
|
||||
label: 'Id',
|
||||
targetColumnMap: {
|
||||
value: 'id',
|
||||
},
|
||||
icon: 'Icon123',
|
||||
description: 'Id',
|
||||
isNullable: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
workspaceId: objectMetadataInput.workspaceId,
|
||||
defaultValue: { type: 'uuid' },
|
||||
},
|
||||
{
|
||||
standardId: customObjectStandardFieldIds.name,
|
||||
type: FieldMetadataType.TEXT,
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
targetColumnMap: {
|
||||
value: 'name',
|
||||
},
|
||||
icon: 'IconAbc',
|
||||
description: 'Name',
|
||||
isNullable: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
workspaceId: objectMetadataInput.workspaceId,
|
||||
defaultValue: { value: 'Untitled' },
|
||||
},
|
||||
{
|
||||
standardId: baseObjectStandardFieldIds.createdAt,
|
||||
type: FieldMetadataType.DATE_TIME,
|
||||
name: 'createdAt',
|
||||
label: 'Creation date',
|
||||
targetColumnMap: {
|
||||
value: 'createdAt',
|
||||
},
|
||||
icon: 'IconCalendar',
|
||||
description: 'Creation date',
|
||||
isNullable: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
workspaceId: objectMetadataInput.workspaceId,
|
||||
defaultValue: { type: 'now' },
|
||||
},
|
||||
{
|
||||
standardId: baseObjectStandardFieldIds.updatedAt,
|
||||
type: FieldMetadataType.DATE_TIME,
|
||||
name: 'updatedAt',
|
||||
label: 'Update date',
|
||||
targetColumnMap: {
|
||||
value: 'updatedAt',
|
||||
},
|
||||
icon: 'IconCalendar',
|
||||
description: 'Update date',
|
||||
isNullable: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
workspaceId: objectMetadataInput.workspaceId,
|
||||
defaultValue: { type: 'now' },
|
||||
},
|
||||
{
|
||||
standardId: customObjectStandardFieldIds.position,
|
||||
type: FieldMetadataType.POSITION,
|
||||
name: 'position',
|
||||
label: 'Position',
|
||||
targetColumnMap: {
|
||||
value: 'position',
|
||||
},
|
||||
icon: 'IconHierarchy2',
|
||||
description: 'Position',
|
||||
isNullable: true,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
workspaceId: objectMetadataInput.workspaceId,
|
||||
defaultValue: null,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { activityTargetObjectMetadata } =
|
||||
await this.createActivityTargetRelation(
|
||||
objectMetadataInput.workspaceId,
|
||||
createdObjectMetadata,
|
||||
);
|
||||
|
||||
const { favoriteObjectMetadata } = await this.createFavoriteRelation(
|
||||
objectMetadataInput.workspaceId,
|
||||
createdObjectMetadata,
|
||||
);
|
||||
|
||||
const { attachmentObjectMetadata } = await this.createAttachmentRelation(
|
||||
objectMetadataInput.workspaceId,
|
||||
createdObjectMetadata,
|
||||
);
|
||||
|
||||
await this.workspaceMigrationService.createCustomMigration(
|
||||
generateMigrationName(`create-${createdObjectMetadata.nameSingular}`),
|
||||
createdObjectMetadata.workspaceId,
|
||||
[
|
||||
{
|
||||
name: computeObjectTargetTable(createdObjectMetadata),
|
||||
action: 'create',
|
||||
} satisfies WorkspaceMigrationTableAction,
|
||||
// Add activity target relation
|
||||
{
|
||||
name: computeObjectTargetTable(activityTargetObjectMetadata),
|
||||
action: 'alter',
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.CREATE,
|
||||
columnName: `${computeCustomName(
|
||||
createdObjectMetadata.nameSingular,
|
||||
false,
|
||||
)}Id`,
|
||||
columnType: 'uuid',
|
||||
isNullable: true,
|
||||
} satisfies WorkspaceMigrationColumnCreate,
|
||||
],
|
||||
},
|
||||
{
|
||||
name: computeObjectTargetTable(activityTargetObjectMetadata),
|
||||
action: 'alter',
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
|
||||
columnName: `${computeCustomName(
|
||||
createdObjectMetadata.nameSingular,
|
||||
false,
|
||||
)}Id`,
|
||||
referencedTableName: computeObjectTargetTable(
|
||||
createdObjectMetadata,
|
||||
),
|
||||
referencedTableColumnName: 'id',
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Add attachment relation
|
||||
{
|
||||
name: computeObjectTargetTable(attachmentObjectMetadata),
|
||||
action: 'alter',
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.CREATE,
|
||||
columnName: `${computeCustomName(
|
||||
createdObjectMetadata.nameSingular,
|
||||
false,
|
||||
)}Id`,
|
||||
columnType: 'uuid',
|
||||
isNullable: true,
|
||||
} satisfies WorkspaceMigrationColumnCreate,
|
||||
],
|
||||
},
|
||||
{
|
||||
name: computeObjectTargetTable(attachmentObjectMetadata),
|
||||
action: 'alter',
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
|
||||
columnName: `${computeCustomName(
|
||||
createdObjectMetadata.nameSingular,
|
||||
false,
|
||||
)}Id`,
|
||||
referencedTableName: computeObjectTargetTable(
|
||||
createdObjectMetadata,
|
||||
),
|
||||
referencedTableColumnName: 'id',
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Add favorite relation
|
||||
{
|
||||
name: computeObjectTargetTable(favoriteObjectMetadata),
|
||||
action: 'alter',
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.CREATE,
|
||||
columnName: `${computeCustomName(
|
||||
createdObjectMetadata.nameSingular,
|
||||
false,
|
||||
)}Id`,
|
||||
columnType: 'uuid',
|
||||
isNullable: true,
|
||||
} satisfies WorkspaceMigrationColumnCreate,
|
||||
],
|
||||
},
|
||||
{
|
||||
name: computeObjectTargetTable(favoriteObjectMetadata),
|
||||
action: 'alter',
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
|
||||
columnName: `${computeCustomName(
|
||||
createdObjectMetadata.nameSingular,
|
||||
false,
|
||||
)}Id`,
|
||||
referencedTableName: computeObjectTargetTable(
|
||||
createdObjectMetadata,
|
||||
),
|
||||
referencedTableColumnName: 'id',
|
||||
onDelete: RelationOnDeleteAction.CASCADE,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: computeObjectTargetTable(createdObjectMetadata),
|
||||
action: 'alter',
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.CREATE,
|
||||
columnName: 'position',
|
||||
columnType: 'float',
|
||||
isNullable: true,
|
||||
} satisfies WorkspaceMigrationColumnCreate,
|
||||
],
|
||||
} satisfies WorkspaceMigrationTableAction,
|
||||
// This is temporary until we implement mainIdentifier
|
||||
{
|
||||
name: computeObjectTargetTable(createdObjectMetadata),
|
||||
action: 'alter',
|
||||
columns: [
|
||||
{
|
||||
action: WorkspaceMigrationColumnActionType.CREATE,
|
||||
columnName: 'name',
|
||||
columnType: 'text',
|
||||
defaultValue: "'Untitled'",
|
||||
} satisfies WorkspaceMigrationColumnCreate,
|
||||
],
|
||||
} satisfies WorkspaceMigrationTableAction,
|
||||
],
|
||||
);
|
||||
|
||||
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
|
||||
createdObjectMetadata.workspaceId,
|
||||
);
|
||||
|
||||
const dataSourceMetadata =
|
||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
||||
createdObjectMetadata.workspaceId,
|
||||
);
|
||||
|
||||
const workspaceDataSource =
|
||||
await this.typeORMService.connectToDataSource(dataSourceMetadata);
|
||||
|
||||
const view = await workspaceDataSource?.query(
|
||||
`INSERT INTO ${dataSourceMetadata.schema}."view"
|
||||
("objectMetadataId", "type", "name")
|
||||
VALUES ('${createdObjectMetadata.id}', 'table', 'All ${createdObjectMetadata.namePlural}') RETURNING *`,
|
||||
);
|
||||
|
||||
createdObjectMetadata.fields.map(async (field, index) => {
|
||||
if (field.name === 'id') {
|
||||
return;
|
||||
}
|
||||
|
||||
await workspaceDataSource?.query(
|
||||
`INSERT INTO ${dataSourceMetadata.schema}."viewField"
|
||||
("fieldMetadataId", "position", "isVisible", "size", "viewId")
|
||||
VALUES ('${field.id}', '${index - 1}', true, 180, '${
|
||||
view[0].id
|
||||
}') RETURNING *`,
|
||||
);
|
||||
});
|
||||
|
||||
return createdObjectMetadata;
|
||||
}
|
||||
|
||||
public async findOneWithinWorkspace(
|
||||
workspaceId: string,
|
||||
options: FindOneOptions<ObjectMetadataEntity>,
|
||||
): Promise<ObjectMetadataEntity | null> {
|
||||
return this.objectMetadataRepository.findOne({
|
||||
relations: [
|
||||
'fields',
|
||||
'fields.fromRelationMetadata',
|
||||
'fields.toRelationMetadata',
|
||||
],
|
||||
...options,
|
||||
where: {
|
||||
...options.where,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public async findOneOrFailWithinWorkspace(
|
||||
workspaceId: string,
|
||||
options: FindOneOptions<ObjectMetadataEntity>,
|
||||
): Promise<ObjectMetadataEntity> {
|
||||
return this.objectMetadataRepository.findOneOrFail({
|
||||
relations: [
|
||||
'fields',
|
||||
'fields.fromRelationMetadata',
|
||||
'fields.toRelationMetadata',
|
||||
],
|
||||
...options,
|
||||
where: {
|
||||
...options.where,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public async findManyWithinWorkspace(
|
||||
workspaceId: string,
|
||||
options?: FindManyOptions<ObjectMetadataEntity>,
|
||||
) {
|
||||
return this.objectMetadataRepository.find({
|
||||
relations: [
|
||||
'fields.object',
|
||||
'fields',
|
||||
'fields.fromRelationMetadata',
|
||||
'fields.toRelationMetadata',
|
||||
'fields.fromRelationMetadata.toObjectMetadata',
|
||||
],
|
||||
...options,
|
||||
where: {
|
||||
...options?.where,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public async findMany(options?: FindManyOptions<ObjectMetadataEntity>) {
|
||||
return this.objectMetadataRepository.find({
|
||||
relations: [
|
||||
'fields',
|
||||
'fields.fromRelationMetadata',
|
||||
'fields.toRelationMetadata',
|
||||
'fields.fromRelationMetadata.toObjectMetadata',
|
||||
],
|
||||
...options,
|
||||
where: {
|
||||
...options?.where,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public async deleteObjectsMetadata(workspaceId: string) {
|
||||
await this.objectMetadataRepository.delete({ workspaceId });
|
||||
}
|
||||
|
||||
private async createActivityTargetRelation(
|
||||
workspaceId: string,
|
||||
createdObjectMetadata: ObjectMetadataEntity,
|
||||
) {
|
||||
const activityTargetObjectMetadata =
|
||||
await this.objectMetadataRepository.findOneByOrFail({
|
||||
nameSingular: 'activityTarget',
|
||||
workspaceId: workspaceId,
|
||||
});
|
||||
|
||||
const activityTargetRelationFieldMetadata =
|
||||
await this.fieldMetadataRepository.save([
|
||||
// FROM
|
||||
{
|
||||
standardId: customObjectStandardFieldIds.activityTargets,
|
||||
objectMetadataId: createdObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.RELATION,
|
||||
name: 'activityTargets',
|
||||
label: 'Activities',
|
||||
targetColumnMap: {},
|
||||
description: `Activities tied to the ${createdObjectMetadata.labelSingular}`,
|
||||
icon: 'IconCheckbox',
|
||||
isNullable: true,
|
||||
},
|
||||
// TO
|
||||
{
|
||||
standardId: activityTargetStandardFieldIds.custom,
|
||||
objectMetadataId: activityTargetObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.RELATION,
|
||||
name: createdObjectMetadata.nameSingular,
|
||||
label: createdObjectMetadata.labelSingular,
|
||||
targetColumnMap: {},
|
||||
description: `ActivityTarget ${createdObjectMetadata.labelSingular}`,
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
},
|
||||
// Foreign key
|
||||
{
|
||||
standardId: createDeterministicUuid(
|
||||
activityTargetStandardFieldIds.custom,
|
||||
),
|
||||
objectMetadataId: activityTargetObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.UUID,
|
||||
name: `${createdObjectMetadata.nameSingular}Id`,
|
||||
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
|
||||
targetColumnMap: {
|
||||
value: `${computeCustomName(
|
||||
createdObjectMetadata.nameSingular,
|
||||
false,
|
||||
)}Id`,
|
||||
},
|
||||
description: `ActivityTarget ${createdObjectMetadata.labelSingular} id foreign key`,
|
||||
icon: undefined,
|
||||
isNullable: true,
|
||||
isSystem: true,
|
||||
defaultValue: undefined,
|
||||
},
|
||||
]);
|
||||
|
||||
const activityTargetRelationFieldMetadataMap =
|
||||
activityTargetRelationFieldMetadata.reduce(
|
||||
(acc, fieldMetadata: FieldMetadataEntity) => {
|
||||
if (fieldMetadata.type === FieldMetadataType.RELATION) {
|
||||
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
await this.relationMetadataRepository.save([
|
||||
{
|
||||
workspaceId: workspaceId,
|
||||
relationType: RelationMetadataType.ONE_TO_MANY,
|
||||
fromObjectMetadataId: createdObjectMetadata.id,
|
||||
toObjectMetadataId: activityTargetObjectMetadata.id,
|
||||
fromFieldMetadataId:
|
||||
activityTargetRelationFieldMetadataMap[createdObjectMetadata.id].id,
|
||||
toFieldMetadataId:
|
||||
activityTargetRelationFieldMetadataMap[
|
||||
activityTargetObjectMetadata.id
|
||||
].id,
|
||||
onDeleteAction: RelationOnDeleteAction.CASCADE,
|
||||
},
|
||||
]);
|
||||
|
||||
return { activityTargetObjectMetadata };
|
||||
}
|
||||
|
||||
private async createAttachmentRelation(
|
||||
workspaceId: string,
|
||||
createdObjectMetadata: ObjectMetadataEntity,
|
||||
) {
|
||||
const attachmentObjectMetadata =
|
||||
await this.objectMetadataRepository.findOneByOrFail({
|
||||
nameSingular: 'attachment',
|
||||
workspaceId: workspaceId,
|
||||
});
|
||||
|
||||
const attachmentRelationFieldMetadata =
|
||||
await this.fieldMetadataRepository.save([
|
||||
// FROM
|
||||
{
|
||||
standardId: customObjectStandardFieldIds.attachments,
|
||||
objectMetadataId: createdObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.RELATION,
|
||||
name: 'attachments',
|
||||
label: 'Attachments',
|
||||
targetColumnMap: {},
|
||||
description: `Attachments tied to the ${createdObjectMetadata.labelSingular}`,
|
||||
icon: 'IconFileImport',
|
||||
isNullable: true,
|
||||
},
|
||||
// TO
|
||||
{
|
||||
standardId: attachmentStandardFieldIds.custom,
|
||||
objectMetadataId: attachmentObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.RELATION,
|
||||
name: createdObjectMetadata.nameSingular,
|
||||
label: createdObjectMetadata.labelSingular,
|
||||
targetColumnMap: {},
|
||||
description: `Attachment ${createdObjectMetadata.labelSingular}`,
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
},
|
||||
// Foreign key
|
||||
{
|
||||
standardId: createDeterministicUuid(
|
||||
attachmentStandardFieldIds.custom,
|
||||
),
|
||||
objectMetadataId: attachmentObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.UUID,
|
||||
name: `${createdObjectMetadata.nameSingular}Id`,
|
||||
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
|
||||
targetColumnMap: {
|
||||
value: `${computeCustomName(
|
||||
createdObjectMetadata.nameSingular,
|
||||
false,
|
||||
)}Id`,
|
||||
},
|
||||
description: `Attachment ${createdObjectMetadata.labelSingular} id foreign key`,
|
||||
icon: undefined,
|
||||
isNullable: true,
|
||||
isSystem: true,
|
||||
defaultValue: undefined,
|
||||
},
|
||||
]);
|
||||
|
||||
const attachmentRelationFieldMetadataMap =
|
||||
attachmentRelationFieldMetadata.reduce(
|
||||
(acc, fieldMetadata: FieldMetadataEntity) => {
|
||||
if (fieldMetadata.type === FieldMetadataType.RELATION) {
|
||||
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
await this.relationMetadataRepository.save([
|
||||
{
|
||||
workspaceId: workspaceId,
|
||||
relationType: RelationMetadataType.ONE_TO_MANY,
|
||||
fromObjectMetadataId: createdObjectMetadata.id,
|
||||
toObjectMetadataId: attachmentObjectMetadata.id,
|
||||
fromFieldMetadataId:
|
||||
attachmentRelationFieldMetadataMap[createdObjectMetadata.id].id,
|
||||
toFieldMetadataId:
|
||||
attachmentRelationFieldMetadataMap[attachmentObjectMetadata.id].id,
|
||||
onDeleteAction: RelationOnDeleteAction.CASCADE,
|
||||
},
|
||||
]);
|
||||
|
||||
return { attachmentObjectMetadata };
|
||||
}
|
||||
|
||||
private async createFavoriteRelation(
|
||||
workspaceId: string,
|
||||
createdObjectMetadata: ObjectMetadataEntity,
|
||||
) {
|
||||
const favoriteObjectMetadata =
|
||||
await this.objectMetadataRepository.findOneByOrFail({
|
||||
nameSingular: 'favorite',
|
||||
workspaceId: workspaceId,
|
||||
});
|
||||
|
||||
const favoriteRelationFieldMetadata =
|
||||
await this.fieldMetadataRepository.save([
|
||||
// FROM
|
||||
{
|
||||
standardId: customObjectStandardFieldIds.favorites,
|
||||
objectMetadataId: createdObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
isSystem: true,
|
||||
type: FieldMetadataType.RELATION,
|
||||
name: 'favorites',
|
||||
label: 'Favorites',
|
||||
targetColumnMap: {},
|
||||
description: `Favorites tied to the ${createdObjectMetadata.labelSingular}`,
|
||||
icon: 'IconHeart',
|
||||
isNullable: true,
|
||||
},
|
||||
// TO
|
||||
{
|
||||
standardId: favoriteStandardFieldIds.custom,
|
||||
objectMetadataId: favoriteObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.RELATION,
|
||||
name: createdObjectMetadata.nameSingular,
|
||||
label: createdObjectMetadata.labelSingular,
|
||||
targetColumnMap: {},
|
||||
description: `Favorite ${createdObjectMetadata.labelSingular}`,
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
isNullable: true,
|
||||
},
|
||||
// Foreign key
|
||||
{
|
||||
standardId: createDeterministicUuid(favoriteStandardFieldIds.custom),
|
||||
objectMetadataId: favoriteObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.UUID,
|
||||
name: `${createdObjectMetadata.nameSingular}Id`,
|
||||
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
|
||||
targetColumnMap: {
|
||||
value: `${computeCustomName(
|
||||
createdObjectMetadata.nameSingular,
|
||||
false,
|
||||
)}Id`,
|
||||
},
|
||||
description: `Favorite ${createdObjectMetadata.labelSingular} id foreign key`,
|
||||
icon: undefined,
|
||||
isNullable: true,
|
||||
isSystem: true,
|
||||
defaultValue: undefined,
|
||||
},
|
||||
]);
|
||||
|
||||
const favoriteRelationFieldMetadataMap =
|
||||
favoriteRelationFieldMetadata.reduce(
|
||||
(acc, fieldMetadata: FieldMetadataEntity) => {
|
||||
if (fieldMetadata.type === FieldMetadataType.RELATION) {
|
||||
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
await this.relationMetadataRepository.save([
|
||||
{
|
||||
workspaceId: workspaceId,
|
||||
relationType: RelationMetadataType.ONE_TO_MANY,
|
||||
fromObjectMetadataId: createdObjectMetadata.id,
|
||||
toObjectMetadataId: favoriteObjectMetadata.id,
|
||||
fromFieldMetadataId:
|
||||
favoriteRelationFieldMetadataMap[createdObjectMetadata.id].id,
|
||||
toFieldMetadataId:
|
||||
favoriteRelationFieldMetadataMap[favoriteObjectMetadata.id].id,
|
||||
onDeleteAction: RelationOnDeleteAction.CASCADE,
|
||||
},
|
||||
]);
|
||||
|
||||
return { favoriteObjectMetadata };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user