From c04e866de392a56fd7a01e1ebbf6160abe88fc16 Mon Sep 17 00:00:00 2001 From: Weiko Date: Thu, 26 Oct 2023 17:32:27 +0200 Subject: [PATCH] Remove Metadata SoftDelete and page limit size (#2237) * Remove Metadata SoftDelete and page limit size * add cascade deletion * add missing queryRunner release --- .../data-source/data-source.service.ts | 2 + .../field-metadata/field-metadata.entity.ts | 15 ++++---- .../services/field-metadata.service.ts | 27 +++++++++++++- server/src/metadata/metadata.datasource.ts | 2 + .../1698328717102-removeMetadataSoftDelete.ts | 37 +++++++++++++++++++ .../object-metadata/object-metadata.entity.ts | 9 ++--- .../services/object-metadata.service.ts | 32 +++++++++++++++- 7 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 server/src/metadata/migrations/1698328717102-removeMetadataSoftDelete.ts diff --git a/server/src/metadata/data-source/data-source.service.ts b/server/src/metadata/data-source/data-source.service.ts index cf60a5110..3000f138b 100644 --- a/server/src/metadata/data-source/data-source.service.ts +++ b/server/src/metadata/data-source/data-source.service.ts @@ -42,6 +42,8 @@ export class DataSourceService implements OnModuleInit, OnModuleDestroy { await queryRunner.createSchema(schemaName, true); + await queryRunner.release(); + return schemaName; } diff --git a/server/src/metadata/field-metadata/field-metadata.entity.ts b/server/src/metadata/field-metadata/field-metadata.entity.ts index 89f68ee3c..d7bc49550 100644 --- a/server/src/metadata/field-metadata/field-metadata.entity.ts +++ b/server/src/metadata/field-metadata/field-metadata.entity.ts @@ -3,7 +3,6 @@ import { Field, ID, ObjectType } from '@nestjs/graphql'; import { Column, CreateDateColumn, - DeleteDateColumn, Entity, JoinColumn, ManyToOne, @@ -35,11 +34,14 @@ export type FieldMetadataTargetColumnMap = { }) @QueryOptions({ defaultResultSize: 10, - maxResultsSize: 100, disableFilter: true, disableSort: true, }) -@Unique('IndexOnNameAndWorkspaceIdUnique', ['name', 'objectId', 'workspaceId']) +@Unique('IndexOnNameObjectIdAndWorkspaceIdUnique', [ + 'name', + 'objectId', + 'workspaceId', +]) export class FieldMetadata { @IDField(() => ID) @PrimaryGeneratedColumn('uuid') @@ -92,7 +94,9 @@ export class FieldMetadata { @Column({ nullable: false, name: 'workspace_id' }) workspaceId: string; - @ManyToOne(() => ObjectMetadata, (object) => object.fields) + @ManyToOne(() => ObjectMetadata, (object) => object.fields, { + onDelete: 'CASCADE', + }) @JoinColumn({ name: 'object_id' }) object: ObjectMetadata; @@ -103,7 +107,4 @@ export class FieldMetadata { @Field() @UpdateDateColumn({ name: 'updated_at' }) updatedAt: Date; - - @DeleteDateColumn({ name: 'deleted_at' }) - deletedAt?: Date; } diff --git a/server/src/metadata/field-metadata/services/field-metadata.service.ts b/server/src/metadata/field-metadata/services/field-metadata.service.ts index 83f8fcf43..3fda59b7b 100644 --- a/server/src/metadata/field-metadata/services/field-metadata.service.ts +++ b/server/src/metadata/field-metadata/services/field-metadata.service.ts @@ -1,4 +1,5 @@ import { + BadRequestException, ConflictException, Injectable, NotFoundException, @@ -7,6 +8,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; +import { DeleteOneOptions } from '@ptc-org/nestjs-query-core'; import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; import { @@ -28,7 +30,30 @@ export class FieldMetadataService extends TypeOrmQueryService { private readonly tenantMigrationService: TenantMigrationService, private readonly migrationRunnerService: MigrationRunnerService, ) { - super(fieldMetadataRepository, { useSoftDelete: true }); + super(fieldMetadataRepository); + } + + override async deleteOne( + id: string, + opts?: DeleteOneOptions | undefined, + ): Promise { + const fieldMetadata = await this.fieldMetadataRepository.findOne({ + where: { id }, + }); + + if (!fieldMetadata) { + throw new NotFoundException('Field does not exist'); + } + + if (!fieldMetadata.isCustom) { + throw new BadRequestException("Standard fields can't be deleted"); + } + + if (fieldMetadata.isActive) { + throw new BadRequestException("Active fields can't be deleted"); + } + + return super.deleteOne(id, opts); } override async createOne(record: FieldMetadata): Promise { diff --git a/server/src/metadata/metadata.datasource.ts b/server/src/metadata/metadata.datasource.ts index 7f9d9a49e..1bbd11ca0 100644 --- a/server/src/metadata/metadata.datasource.ts +++ b/server/src/metadata/metadata.datasource.ts @@ -13,6 +13,7 @@ import { AddSoftDelete1697474804403 } from './migrations/1697474804403-addSoftDe import { RemoveSingularPluralFromFieldLabelAndName1697534910933 } from './migrations/1697534910933-removeSingularPluralFromFieldLabelAndName'; import { AddNameAndIsCustomToTenantMigration1697622715467 } from './migrations/1697622715467-addNameAndIsCustomToTenantMigration'; import { AddUniqueConstraintsOnFieldObjectMetadata1697630766924 } from './migrations/1697630766924-addUniqueConstraintsOnFieldObjectMetadata'; +import { RemoveMetadataSoftDelete1698328717102 } from './migrations/1698328717102-removeMetadataSoftDelete'; config(); @@ -37,6 +38,7 @@ export const typeORMMetadataModuleOptions: TypeOrmModuleOptions = { RemoveSingularPluralFromFieldLabelAndName1697534910933, AddNameAndIsCustomToTenantMigration1697622715467, AddUniqueConstraintsOnFieldObjectMetadata1697630766924, + RemoveMetadataSoftDelete1698328717102, ], }; diff --git a/server/src/metadata/migrations/1698328717102-removeMetadataSoftDelete.ts b/server/src/metadata/migrations/1698328717102-removeMetadataSoftDelete.ts new file mode 100644 index 000000000..1f960e711 --- /dev/null +++ b/server/src/metadata/migrations/1698328717102-removeMetadataSoftDelete.ts @@ -0,0 +1,37 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class RemoveMetadataSoftDelete1698328717102 + implements MigrationInterface +{ + name = 'RemoveMetadataSoftDelete1698328717102'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "metadata"."field_metadata" DROP CONSTRAINT "FK_38179b299795e48887fc99f937a"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "deleted_at"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "deleted_at"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."field_metadata" ADD CONSTRAINT "FK_38179b299795e48887fc99f937a" FOREIGN KEY ("object_id") REFERENCES "metadata"."object_metadata"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "metadata"."field_metadata" DROP CONSTRAINT "FK_38179b299795e48887fc99f937a"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."field_metadata" ADD "deleted_at" TIMESTAMP`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."object_metadata" ADD "deleted_at" TIMESTAMP`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."field_metadata" ADD CONSTRAINT "FK_38179b299795e48887fc99f937a" FOREIGN KEY ("object_id") REFERENCES "metadata"."object_metadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + } +} diff --git a/server/src/metadata/object-metadata/object-metadata.entity.ts b/server/src/metadata/object-metadata/object-metadata.entity.ts index e501ae762..e8aa9ab7b 100644 --- a/server/src/metadata/object-metadata/object-metadata.entity.ts +++ b/server/src/metadata/object-metadata/object-metadata.entity.ts @@ -3,7 +3,6 @@ import { ObjectType, ID, Field } from '@nestjs/graphql'; import { Column, CreateDateColumn, - DeleteDateColumn, Entity, OneToMany, PrimaryGeneratedColumn, @@ -32,7 +31,6 @@ import { BeforeCreateOneObject } from './hooks/before-create-one-object.hook'; }) @QueryOptions({ defaultResultSize: 10, - maxResultsSize: 100, disableFilter: true, disableSort: true, }) @@ -89,7 +87,9 @@ export class ObjectMetadata { @Column({ nullable: false, name: 'workspace_id' }) workspaceId: string; - @OneToMany(() => FieldMetadata, (field) => field.object) + @OneToMany(() => FieldMetadata, (field) => field.object, { + cascade: true, + }) fields: FieldMetadata[]; @Field() @@ -99,7 +99,4 @@ export class ObjectMetadata { @Field() @UpdateDateColumn({ name: 'updated_at' }) updatedAt: Date; - - @DeleteDateColumn({ name: 'deleted_at' }) - deletedAt?: Date; } diff --git a/server/src/metadata/object-metadata/services/object-metadata.service.ts b/server/src/metadata/object-metadata/services/object-metadata.service.ts index f1648a29c..6200534b3 100644 --- a/server/src/metadata/object-metadata/services/object-metadata.service.ts +++ b/server/src/metadata/object-metadata/services/object-metadata.service.ts @@ -1,8 +1,13 @@ -import { Injectable } from '@nestjs/common'; +import { + BadRequestException, + Injectable, + NotFoundException, +} from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; +import { DeleteOneOptions } from '@ptc-org/nestjs-query-core'; import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; import { TenantMigrationTableAction } from 'src/metadata/tenant-migration/tenant-migration.entity'; @@ -18,7 +23,30 @@ export class ObjectMetadataService extends TypeOrmQueryService { private readonly tenantMigrationService: TenantMigrationService, private readonly migrationRunnerService: MigrationRunnerService, ) { - super(objectMetadataRepository, { useSoftDelete: true }); + super(objectMetadataRepository); + } + + override async deleteOne( + id: string, + opts?: DeleteOneOptions | undefined, + ): Promise { + const objectMetadata = await this.objectMetadataRepository.findOne({ + where: { id }, + }); + + if (!objectMetadata) { + throw new NotFoundException('Object does not exist'); + } + + if (!objectMetadata.isCustom) { + throw new BadRequestException("Standard Objects can't be deleted"); + } + + if (objectMetadata.isActive) { + throw new BadRequestException("Active objects can't be deleted"); + } + + return super.deleteOne(id, opts); } override async createOne(record: ObjectMetadata): Promise {