94 lines
3.2 KiB
TypeScript
94 lines
3.2 KiB
TypeScript
import { InjectRepository } from '@nestjs/typeorm';
|
|
|
|
import { Command } from 'nest-commander';
|
|
import { In, type Repository } from 'typeorm';
|
|
|
|
import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
|
import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner';
|
|
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
|
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
|
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
|
import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
|
|
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
|
|
|
@Command({
|
|
name: 'upgrade:1-11:clean-orphaned-role-targets',
|
|
description:
|
|
'Clean up roleTargets records that reference non-existent userWorkspaces',
|
|
})
|
|
export class CleanOrphanedRoleTargetsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
|
private hasRunOnce = false;
|
|
constructor(
|
|
@InjectRepository(RoleTargetEntity)
|
|
private readonly roleTargetRepository: Repository<RoleTargetEntity>,
|
|
@InjectRepository(WorkspaceEntity)
|
|
protected readonly workspaceRepository: Repository<WorkspaceEntity>,
|
|
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
|
protected readonly dataSourceService: DataSourceService,
|
|
) {
|
|
super(workspaceRepository, twentyORMGlobalManager, dataSourceService);
|
|
}
|
|
|
|
override async runOnWorkspace({
|
|
options,
|
|
}: RunOnWorkspaceArgs): Promise<void> {
|
|
if (this.hasRunOnce) {
|
|
this.logger.log('This command has already been run');
|
|
|
|
return;
|
|
}
|
|
const isDryRun = options.dryRun || false;
|
|
|
|
if (isDryRun) {
|
|
this.logger.log('Dry run mode: No changes will be applied');
|
|
}
|
|
|
|
const orphanedRoleTargets = await this.roleTargetRepository
|
|
.createQueryBuilder('roleTarget')
|
|
.leftJoin(
|
|
UserWorkspaceEntity,
|
|
'userWorkspace',
|
|
'userWorkspace.id = roleTarget.userWorkspaceId',
|
|
)
|
|
.where('roleTarget.userWorkspaceId IS NOT NULL')
|
|
.andWhere('userWorkspace.id IS NULL')
|
|
.select([
|
|
'roleTarget.id',
|
|
'roleTarget.userWorkspaceId',
|
|
'roleTarget.workspaceId',
|
|
])
|
|
.getMany();
|
|
|
|
if (orphanedRoleTargets.length === 0) {
|
|
this.logger.log('No orphaned roleTargets found');
|
|
|
|
return;
|
|
}
|
|
|
|
if (isDryRun) {
|
|
this.logger.log(
|
|
`DRY RUN: Would delete ${orphanedRoleTargets.length} orphaned roleTarget(s):`,
|
|
);
|
|
orphanedRoleTargets.forEach((roleTarget) => {
|
|
this.logger.log(
|
|
` - roleTargetId: ${roleTarget.id}, userWorkspaceId: ${roleTarget.userWorkspaceId}, workspaceId: ${roleTarget.workspaceId}`,
|
|
);
|
|
});
|
|
|
|
this.hasRunOnce = true;
|
|
|
|
return;
|
|
}
|
|
|
|
const orphanedIds = orphanedRoleTargets.map((roleTarget) => roleTarget.id);
|
|
|
|
await this.roleTargetRepository.delete({ id: In(orphanedIds) });
|
|
|
|
this.logger.log(
|
|
`Deleted ${orphanedRoleTargets.length} orphaned roleTarget(s)`,
|
|
);
|
|
|
|
this.hasRunOnce = true;
|
|
}
|
|
}
|