Files
twenty/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts
T
Charles Bochet f6423f5925 Remove DataSourceService and clean up datasource migration logic (#19532)
## Summary

- **Drop the `objectMetadata.dataSourceId` foreign key and index** via a
1-22 fast instance command — column kept nullable for data preservation
- **Delete `DataSourceService`, `DataSourceModule`, and
`DataSourceException`** — all code now uses `workspace.databaseSchema`
directly
- **Remove `IS_DATASOURCE_MIGRATED` feature flag** from default flags
and all branching logic
- **Simplify workspace/object creation pipelines** —
`WorkspaceManagerService`, `DevSeederService`, and the object creation
action handler no longer route through `DataSourceService`
- **Keep `DataSourceEntity` and the `dataSource` table** for historical
data — entity stripped of all ORM relations
2026-04-10 07:34:05 +00:00

159 lines
5.5 KiB
TypeScript

import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
import {
GenerateSdkClientJob,
GenerateSdkClientJobData,
} from 'src/engine/core-modules/sdk-client/jobs/generate-sdk-client.job';
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { STANDARD_ROLE } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-role.constant';
import { TwentyStandardApplicationService } from 'src/engine/workspace-manager/twenty-standard-application/services/twenty-standard-application.service';
@Injectable()
export class WorkspaceManagerService {
private readonly logger = new Logger(WorkspaceManagerService.name);
constructor(
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
@InjectRepository(UserWorkspaceEntity)
private readonly userWorkspaceRepository: Repository<UserWorkspaceEntity>,
private readonly roleService: RoleService,
private readonly userRoleService: UserRoleService,
private readonly twentyStandardApplicationService: TwentyStandardApplicationService,
@InjectRepository(WorkspaceEntity)
private readonly workspaceRepository: Repository<WorkspaceEntity>,
@InjectRepository(RoleEntity)
private readonly roleRepository: Repository<RoleEntity>,
private readonly applicationService: ApplicationService,
@InjectMessageQueue(MessageQueue.workspaceQueue)
private readonly messageQueueService: MessageQueueService,
) {}
public async init({
workspace,
userId,
}: {
workspace: WorkspaceEntity;
userId: string;
}): Promise<void> {
const workspaceId = workspace.id;
const schemaCreationStart = performance.now();
const schemaName =
await this.workspaceDataSourceService.createWorkspaceDBSchema(
workspaceId,
);
const schemaCreationEnd = performance.now();
this.logger.log(
`Schema creation took ${schemaCreationEnd - schemaCreationStart}ms`,
);
const dataSourceMetadataCreationStart = performance.now();
await this.workspaceRepository.update(workspaceId, {
databaseSchema: schemaName,
});
await this.applicationService.createTwentyStandardApplication({
workspaceId,
});
await this.twentyStandardApplicationService.synchronizeTwentyStandardApplicationOrThrow(
{
workspaceId,
},
);
const dataSourceMetadataCreationEnd = performance.now();
this.logger.log(
`Metadata creation took ${dataSourceMetadataCreationEnd - dataSourceMetadataCreationStart}ms`,
);
const { workspaceCustomFlatApplication, twentyStandardFlatApplication } =
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
{
workspaceId,
},
);
await Promise.all([
this.messageQueueService.add<GenerateSdkClientJobData>(
GenerateSdkClientJob.name,
{
workspaceId,
applicationId: twentyStandardFlatApplication.id,
applicationUniversalIdentifier:
twentyStandardFlatApplication.universalIdentifier,
},
),
this.messageQueueService.add<GenerateSdkClientJobData>(
GenerateSdkClientJob.name,
{
workspaceId,
applicationId: workspaceCustomFlatApplication.id,
applicationUniversalIdentifier:
workspaceCustomFlatApplication.universalIdentifier,
},
),
]);
await this.setupDefaultRoles({
workspaceId,
userId,
workspaceCustomFlatApplication,
});
}
private async setupDefaultRoles({
userId,
workspaceId,
workspaceCustomFlatApplication,
}: {
workspaceId: string;
userId: string;
workspaceCustomFlatApplication: FlatApplication;
}): Promise<void> {
const adminRole = await this.roleRepository.findOne({
where: {
universalIdentifier: STANDARD_ROLE.admin.universalIdentifier,
workspaceId,
},
});
if (adminRole) {
const userWorkspace = await this.userWorkspaceRepository.findOneOrFail({
where: { workspaceId, userId },
});
await this.userRoleService.assignRoleToManyUserWorkspace({
workspaceId,
userWorkspaceIds: [userWorkspace.id],
roleId: adminRole.id,
});
}
const memberRole = await this.roleService.createMemberRole({
workspaceId,
ownerFlatApplication: workspaceCustomFlatApplication,
});
await this.workspaceRepository.update(workspaceId, {
defaultRoleId: memberRole.id,
});
}
}