Remove objectMetadata isSoftDeletable

This commit is contained in:
Weiko
2024-09-16 13:40:10 +02:00
parent 37d85a716a
commit 31dea498e9
20 changed files with 53 additions and 118 deletions

View File

@@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class RemoveObjectMetadataIsSoftDeletable1726486735275
implements MigrationInterface
{
name = 'RemoveObjectMetadataIsSoftDeletable1726486735275';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "metadata"."objectMetadata" DROP COLUMN "isSoftDeletable"`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "metadata"."objectMetadata" ADD "isSoftDeletable" boolean`,
);
}
}

View File

@@ -33,7 +33,6 @@ export class GraphqlQueryParser {
parseFilter(
recordFilter: RecordFilter,
shouldAddDefaultSoftDeleteCondition = false,
): FindOptionsWhere<ObjectLiteral> | FindOptionsWhere<ObjectLiteral>[] {
const graphqlQueryFilterParser = new GraphqlQueryFilterParser(
this.fieldMetadataMap,
@@ -41,10 +40,7 @@ export class GraphqlQueryParser {
const parsedFilter = graphqlQueryFilterParser.parse(recordFilter);
if (
!shouldAddDefaultSoftDeleteCondition ||
!('deletedAt' in this.fieldMetadataMap)
) {
if (!('deletedAt' in this.fieldMetadataMap)) {
return parsedFilter;
}

View File

@@ -70,10 +70,7 @@ export class GraphqlQueryFindManyResolverService {
args.orderBy ?? [],
isForwardPagination,
);
const where = graphqlQueryParser.parseFilter(
args.filter ?? ({} as Filter),
objectMetadataItem.isSoftDeletable ?? false,
);
const where = graphqlQueryParser.parseFilter(args.filter ?? ({} as Filter));
const cursor = this.getCursor(args);
const limit = args.first ?? args.last ?? QUERY_MAX_RECORDS;

View File

@@ -55,10 +55,7 @@ export class GraphqlQueryFindOneResolverService {
objectMetadataItem,
graphqlFields(info),
);
const where = graphqlQueryParser.parseFilter(
args.filter ?? ({} as Filter),
objectMetadataItem.isSoftDeletable ?? false,
);
const where = graphqlQueryParser.parseFilter(args.filter ?? ({} as Filter));
const objectRecord = await repository.findOne({ where, select, relations });

View File

@@ -34,7 +34,7 @@ export class FindManyQueryFactory {
const argsString = this.argsStringFactory.create(
args,
options.fieldMetadataCollection,
!options.withSoftDeleted && !!options.objectMetadataItem.isSoftDeletable,
!options.withSoftDeleted,
);
return `

View File

@@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceQueryBuilderOptions } from 'src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface';
import { RecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
import { WorkspaceQueryBuilderOptions } from 'src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface';
import { FindOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
@@ -29,7 +29,7 @@ export class FindOneQueryFactory {
const argsString = this.argsStringFactory.create(
args,
options.fieldMetadataCollection,
!options.withSoftDeleted && !!options.objectMetadataItem.isSoftDeletable,
!options.withSoftDeleted,
);
return `

View File

@@ -5,18 +5,18 @@ import { GraphQLResolveInfo } from 'graphql';
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
import { getFieldArgumentsByKey } from 'src/engine/api/graphql/workspace-query-builder/utils/get-field-arguments-by-key.util';
import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import { RelationMetadataType } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
import {
deduceRelationDirection,
RelationDirection,
} from 'src/engine/utils/deduce-relation-direction.util';
import { getFieldArgumentsByKey } from 'src/engine/api/graphql/workspace-query-builder/utils/get-field-arguments-by-key.util';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
import { FieldsStringFactory } from './fields-string.factory';
import { ArgsStringFactory } from './args-string.factory';
import { FieldsStringFactory } from './fields-string.factory';
@Injectable()
export class RelationFieldAliasFactory {
@@ -101,7 +101,7 @@ export class RelationFieldAliasFactory {
const argsString = this.argsStringFactory.create(
args,
referencedObjectMetadata.fields ?? [],
!withSoftDeleted && !!referencedObjectMetadata.isSoftDeletable,
!withSoftDeleted,
);
const fieldsString =
await this.fieldsStringFactory.createFieldsStringRecursive(

View File

@@ -548,7 +548,6 @@ export class WorkspaceQueryRunnerService {
options: WorkspaceQueryRunnerOptions,
): Promise<Record[] | undefined> {
const { authContext, objectMetadataItem } = options;
let query: string;
assertMutationNotOnRemoteObject(objectMetadataItem);
@@ -564,25 +563,18 @@ export class WorkspaceQueryRunnerService {
args,
);
if (objectMetadataItem.isSoftDeletable) {
query = await this.workspaceQueryBuilderFactory.updateMany(
{
filter: hookedArgs.filter,
data: {
deletedAt: new Date().toISOString(),
},
const query = await this.workspaceQueryBuilderFactory.updateMany(
{
filter: hookedArgs.filter,
data: {
deletedAt: new Date().toISOString(),
},
{
...options,
atMost: maximumRecordAffected,
},
);
} else {
query = await this.workspaceQueryBuilderFactory.deleteMany(hookedArgs, {
},
{
...options,
atMost: maximumRecordAffected,
});
}
},
);
const repository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
@@ -603,7 +595,7 @@ export class WorkspaceQueryRunnerService {
await this.parseResult<PGGraphQLMutation<Record>>(
result,
objectMetadataItem,
objectMetadataItem.isSoftDeletable ? 'update' : 'deleteFrom',
'update',
authContext.workspace.id,
)
)?.records;
@@ -648,13 +640,6 @@ export class WorkspaceQueryRunnerService {
assertMutationNotOnRemoteObject(objectMetadataItem);
if (!objectMetadataItem.isSoftDeletable) {
throw new WorkspaceQueryRunnerException(
'This method is reserved to objects that can be soft-deleted, use delete instead',
WorkspaceQueryRunnerExceptionCode.DATA_NOT_FOUND,
);
}
const maximumRecordAffected = this.environmentService.get(
'MUTATION_MAXIMUM_AFFECTED_RECORDS',
);
@@ -711,13 +696,6 @@ export class WorkspaceQueryRunnerService {
assertMutationNotOnRemoteObject(objectMetadataItem);
if (!objectMetadataItem.isSoftDeletable) {
throw new WorkspaceQueryRunnerException(
'This method is reserved to objects that can be soft-deleted',
WorkspaceQueryRunnerExceptionCode.DATA_NOT_FOUND,
);
}
const maximumRecordAffected = this.environmentService.get(
'MUTATION_MAXIMUM_AFFECTED_RECORDS',
);
@@ -792,7 +770,6 @@ export class WorkspaceQueryRunnerService {
authContext.workspace.id,
objectMetadataItem.nameSingular,
);
let query: string;
assertMutationNotOnRemoteObject(objectMetadataItem);
assertIsValidUuid(args.id);
@@ -805,22 +782,15 @@ export class WorkspaceQueryRunnerService {
args,
);
if (objectMetadataItem.isSoftDeletable) {
query = await this.workspaceQueryBuilderFactory.updateOne(
{
id: hookedArgs.id,
data: {
deletedAt: new Date().toISOString(),
},
const query = await this.workspaceQueryBuilderFactory.updateOne(
{
id: hookedArgs.id,
data: {
deletedAt: new Date().toISOString(),
},
options,
);
} else {
query = await this.workspaceQueryBuilderFactory.deleteOne(
hookedArgs,
options,
);
}
},
options,
);
const existingRecord = await repository.findOne({
where: { id: args.id },
@@ -832,7 +802,7 @@ export class WorkspaceQueryRunnerService {
await this.parseResult<PGGraphQLMutation<Record>>(
result,
objectMetadataItem,
objectMetadataItem.isSoftDeletable ? 'update' : 'deleteFrom',
'update',
authContext.workspace.id,
)
)?.records;

View File

@@ -20,5 +20,4 @@ export interface ObjectMetadataInterface {
isAuditLogged: boolean;
labelIdentifierFieldMetadataId?: string | null;
imageIdentifierFieldMetadataId?: string | null;
isSoftDeletable?: boolean | null;
}

View File

@@ -69,9 +69,6 @@ export class ObjectMetadataEntity implements ObjectMetadataInterface {
@Column({ default: true })
isAuditLogged: boolean;
@Column({ nullable: true, type: 'boolean' })
isSoftDeletable?: boolean | null;
@Column({ nullable: true, type: 'uuid' })
labelIdentifierFieldMetadataId?: string | null;

View File

@@ -215,7 +215,6 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
isCustom: isCustom,
isSystem: false,
isRemote: objectMetadataInput.isRemote,
isSoftDeletable: true,
fields: isCustom
? // Creating default fields.
// No need to create a custom migration for this though as the default columns are already

View File

@@ -21,9 +21,7 @@ import { NoteTargetWorkspaceEntity } from 'src/modules/note/standard-objects/not
import { TaskTargetWorkspaceEntity } from 'src/modules/task/standard-objects/task-target.workspace-entity';
import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity';
@WorkspaceCustomEntity({
softDelete: true,
})
@WorkspaceCustomEntity()
export class CustomWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceField({
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.name,

View File

@@ -1,13 +1,7 @@
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
import { TypedReflect } from 'src/utils/typed-reflect';
interface WorkspaceCustomEntityOptions {
softDelete?: boolean;
}
export function WorkspaceCustomEntity(
options: WorkspaceCustomEntityOptions = {},
): ClassDecorator {
export function WorkspaceCustomEntity(options = {}): ClassDecorator {
return (target) => {
const gate = TypedReflect.getMetadata(
'workspace:gate-metadata-args',
@@ -17,7 +11,6 @@ export function WorkspaceCustomEntity(
metadataArgsStorage.addExtendedEntities({
target,
gate,
softDelete: options.softDelete,
});
};
}

View File

@@ -12,7 +12,6 @@ interface WorkspaceEntityOptions {
icon?: string;
labelIdentifierStandardId?: string;
imageIdentifierStandardId?: string;
softDelete?: boolean;
}
export function WorkspaceEntity(
@@ -48,7 +47,6 @@ export function WorkspaceEntity(
isAuditLogged,
isSystem,
gate,
softDelete: options.softDelete ?? true,
});
};
}

View File

@@ -20,10 +20,7 @@ type EntitySchemaColumnMap = {
@Injectable()
export class EntitySchemaColumnFactory {
create(
fieldMetadataMap: FieldMetadataMap,
softDelete: boolean,
): EntitySchemaColumnMap {
create(fieldMetadataMap: FieldMetadataMap): EntitySchemaColumnMap {
let entitySchemaColumnMap: EntitySchemaColumnMap = {};
const fieldMetadataCollection = Object.values(fieldMetadataMap);
@@ -31,11 +28,6 @@ export class EntitySchemaColumnFactory {
for (const fieldMetadata of fieldMetadataCollection) {
const key = fieldMetadata.name;
// Skip deletedAt column if soft delete is not enabled
if (!softDelete && key === 'deletedAt') {
continue;
}
if (isRelationFieldMetadataType(fieldMetadata.type)) {
const relationMetadata =
fieldMetadata.fromRelationMetadata ??

View File

@@ -26,7 +26,6 @@ export class EntitySchemaFactory {
): Promise<EntitySchema> {
const columns = this.entitySchemaColumnFactory.create(
objectMetadata.fields,
objectMetadata.isSoftDeletable ?? false,
);
const relations = await this.entitySchemaRelationFactory.create(

View File

@@ -60,9 +60,4 @@ export interface WorkspaceEntityMetadataArgs {
* Image identifier.
*/
readonly imageIdentifierStandardId: string | null;
/**
* Enable soft delete.
*/
readonly softDelete: boolean;
}

View File

@@ -13,9 +13,4 @@ export interface WorkspaceExtendedEntityMetadataArgs {
* Entity gate.
*/
readonly gate?: Gate;
/**
* Enable soft delete.
*/
readonly softDelete?: boolean;
}

View File

@@ -150,14 +150,6 @@ export class StandardFieldFactory {
return [];
}
if (
workspaceFieldMetadataArgs.name === 'deletedAt' &&
workspaceEntityMetadataArgs &&
!workspaceEntityMetadataArgs.softDelete
) {
return [];
}
return [
{
type: workspaceFieldMetadataArgs.type,

View File

@@ -54,7 +54,6 @@ export class StandardObjectFactory {
isCustom: false,
isRemote: false,
isSystem: workspaceEntityMetadataArgs.isSystem ?? false,
isSoftDeletable: workspaceEntityMetadataArgs.softDelete,
};
}
}