Remove typeorm service (#14116)
## Context To simplify the way we inject our default datasource, I've recently removed the token injection that was confusion since we only had once configured on the module level. Now I'm removing TypeORM service which allows us to instantiate a new Datasource with the same parameters as the default one, it was redundant and confusing.
This commit is contained in:
-12
@@ -5,7 +5,6 @@ import { type DataSource, type Repository } from 'typeorm';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { type ApprovedAccessDomain } from 'src/engine/core-modules/approved-access-domain/approved-access-domain.entity';
|
||||
import { ApprovedAccessDomainService } from 'src/engine/core-modules/approved-access-domain/services/approved-access-domain.service';
|
||||
import { AuthException } from 'src/engine/core-modules/auth/auth.exception';
|
||||
@@ -33,7 +32,6 @@ describe('UserWorkspaceService', () => {
|
||||
let service: UserWorkspaceService;
|
||||
let userWorkspaceRepository: Repository<UserWorkspace>;
|
||||
let userRepository: Repository<User>;
|
||||
let typeORMService: TypeORMService;
|
||||
let workspaceInvitationService: WorkspaceInvitationService;
|
||||
let approvedAccessDomainService: ApprovedAccessDomainService;
|
||||
let twentyORMGlobalManager: TwentyORMGlobalManager;
|
||||
@@ -75,12 +73,6 @@ describe('UserWorkspaceService', () => {
|
||||
getLastDataSourceMetadataFromWorkspaceIdOrFail: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: TypeORMService,
|
||||
useValue: {
|
||||
getMainDataSource: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: WorkspaceInvitationService,
|
||||
useValue: {
|
||||
@@ -142,7 +134,6 @@ describe('UserWorkspaceService', () => {
|
||||
fileService = module.get<FileService>(FileService);
|
||||
userWorkspaceRepository = module.get(getRepositoryToken(UserWorkspace));
|
||||
userRepository = module.get(getRepositoryToken(User));
|
||||
typeORMService = module.get<TypeORMService>(TypeORMService);
|
||||
workspaceInvitationService = module.get<WorkspaceInvitationService>(
|
||||
WorkspaceInvitationService,
|
||||
);
|
||||
@@ -346,9 +337,6 @@ describe('UserWorkspaceService', () => {
|
||||
find: jest.fn().mockResolvedValue(workspaceMember),
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(typeORMService, 'getMainDataSource')
|
||||
.mockReturnValue(mainDataSource);
|
||||
jest
|
||||
.spyOn(mainDataSource, 'query')
|
||||
.mockResolvedValueOnce(undefined)
|
||||
|
||||
@@ -5,7 +5,6 @@ import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql';
|
||||
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||
|
||||
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { AuditModule } from 'src/engine/core-modules/audit/audit.module';
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module';
|
||||
@@ -53,11 +52,6 @@ import { UserService } from './services/user.service';
|
||||
UserWorkspaceModule,
|
||||
],
|
||||
exports: [UserService, WorkspaceMemberTranspiler],
|
||||
providers: [
|
||||
UserService,
|
||||
UserResolver,
|
||||
TypeORMService,
|
||||
WorkspaceMemberTranspiler,
|
||||
],
|
||||
providers: [UserService, UserResolver, WorkspaceMemberTranspiler],
|
||||
})
|
||||
export class UserModule {}
|
||||
|
||||
+7
-12
@@ -1,11 +1,12 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { type Query, type QueryOptions } from '@ptc-org/nestjs-query-core';
|
||||
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
DataSource,
|
||||
In,
|
||||
Repository,
|
||||
type FindManyOptions,
|
||||
@@ -47,7 +48,6 @@ import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/wor
|
||||
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
|
||||
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
|
||||
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service';
|
||||
import { CUSTOM_OBJECT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
|
||||
import { isSearchableFieldType } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-searchable-field.util';
|
||||
@@ -72,7 +72,8 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
private readonly objectMetadataRelatedRecordsService: ObjectMetadataRelatedRecordsService,
|
||||
private readonly indexMetadataService: IndexMetadataService,
|
||||
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
private readonly objectMetadataServiceV2: ObjectMetadataServiceV2,
|
||||
) {
|
||||
@@ -129,9 +130,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
return createdObjectMetadata;
|
||||
}
|
||||
|
||||
const mainDataSource =
|
||||
await this.workspaceDataSourceService.connectToMainDataSource();
|
||||
const queryRunner = mainDataSource.createQueryRunner();
|
||||
const queryRunner = this.coreDataSource.createQueryRunner();
|
||||
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
@@ -290,9 +289,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
updateObjectInput: UpdateOneObjectInput,
|
||||
workspaceId: string,
|
||||
): Promise<ObjectMetadataEntity> {
|
||||
const mainDataSource =
|
||||
await this.workspaceDataSourceService.connectToMainDataSource();
|
||||
const queryRunner = mainDataSource.createQueryRunner();
|
||||
const queryRunner = this.coreDataSource.createQueryRunner();
|
||||
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
@@ -467,9 +464,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
});
|
||||
}
|
||||
|
||||
const mainDataSource =
|
||||
await this.workspaceDataSourceService.connectToMainDataSource();
|
||||
const queryRunner = mainDataSource.createQueryRunner();
|
||||
const queryRunner = this.coreDataSource.createQueryRunner();
|
||||
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
+1
-1
@@ -7,6 +7,7 @@ import { v4 } from 'uuid';
|
||||
|
||||
import { ForeignDataWrapperServerQueryFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/foreign-data-wrapper-server-query.factory';
|
||||
import { encryptText } from 'src/engine/core-modules/auth/auth.util';
|
||||
import { JwtTokenTypeEnum } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
||||
import { type CreateRemoteServerInput } from 'src/engine/metadata-modules/remote-server/dtos/create-remote-server.input';
|
||||
@@ -28,7 +29,6 @@ import {
|
||||
import { validateRemoteServerType } from 'src/engine/metadata-modules/remote-server/utils/validate-remote-server-type.util';
|
||||
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import { JwtTokenTypeEnum } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
|
||||
@Injectable()
|
||||
export class RemoteServerService<T extends RemoteServerType> {
|
||||
|
||||
+5
-7
@@ -1,6 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
|
||||
import { type EntityManager } from 'typeorm';
|
||||
import { DataSource, type EntityManager } from 'typeorm';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import {
|
||||
@@ -15,12 +16,12 @@ import { type DistantTables } from 'src/engine/metadata-modules/remote-server/re
|
||||
import { STRIPE_DISTANT_TABLES } from 'src/engine/metadata-modules/remote-server/remote-table/distant-table/utils/stripe-distant-tables.util';
|
||||
import { type PostgresTableSchemaColumn } from 'src/engine/metadata-modules/remote-server/types/postgres-table-schema-column';
|
||||
import { isQueryTimeoutError } from 'src/engine/utils/query-timeout.util';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
|
||||
@Injectable()
|
||||
export class DistantTableService {
|
||||
constructor(
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
) {}
|
||||
|
||||
public async fetchDistantTables(
|
||||
@@ -68,11 +69,8 @@ export class DistantTableService {
|
||||
const tmpSchemaId = v4();
|
||||
const tmpSchemaName = `${workspaceId}_${remoteServer.id}_${tmpSchemaId}`;
|
||||
|
||||
const mainDataSource =
|
||||
await this.workspaceDataSourceService.connectToMainDataSource();
|
||||
|
||||
try {
|
||||
const distantTables = await mainDataSource.transaction(
|
||||
const distantTables = await this.coreDataSource.transaction(
|
||||
async (entityManager: EntityManager) => {
|
||||
await entityManager.query(`CREATE SCHEMA "${tmpSchemaName}"`);
|
||||
|
||||
|
||||
+6
-4
@@ -1,4 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
import {
|
||||
type RemoteServerEntity,
|
||||
@@ -31,18 +34,17 @@ export class ForeignTableService {
|
||||
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
) {}
|
||||
|
||||
public async fetchForeignTableNamesWithinWorkspace(
|
||||
_workspaceId: string,
|
||||
foreignDataWrapperId: string,
|
||||
): Promise<string[]> {
|
||||
const mainDataSource =
|
||||
await this.workspaceDataSourceService.connectToMainDataSource();
|
||||
|
||||
return (
|
||||
(
|
||||
await mainDataSource.query(
|
||||
await this.coreDataSource.query(
|
||||
`SELECT foreign_table_name, foreign_server_name FROM information_schema.foreign_tables WHERE foreign_server_name = $1`,
|
||||
[foreignDataWrapperId],
|
||||
)
|
||||
|
||||
+5
-6
@@ -1,9 +1,9 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { plural } from 'pluralize';
|
||||
import { Repository } from 'typeorm';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
@@ -63,6 +63,8 @@ export class RemoteTableService {
|
||||
private readonly foreignTableService: ForeignTableService,
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
private readonly remoteTableSchemaUpdateService: RemoteTableSchemaUpdateService,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
) {}
|
||||
|
||||
public async findDistantTablesWithStatus(
|
||||
@@ -182,14 +184,11 @@ export class RemoteTableService {
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
const mainDataSource =
|
||||
await this.workspaceDataSourceService.connectToMainDataSource();
|
||||
|
||||
const { baseName: localTableBaseName, suffix: localTableSuffix } =
|
||||
await getRemoteTableLocalName(
|
||||
input.name,
|
||||
dataSourceMetatada.schema,
|
||||
mainDataSource,
|
||||
this.coreDataSource,
|
||||
);
|
||||
|
||||
const localTableName = localTableSuffix
|
||||
|
||||
+5
-6
@@ -17,11 +17,10 @@ type RemoteTableLocalName = {
|
||||
const isNameAvailable = async (
|
||||
tableName: string,
|
||||
workspaceSchemaName: string,
|
||||
workspaceDataSource: DataSource,
|
||||
coreDataSource: DataSource,
|
||||
) => {
|
||||
// TO DO workspaceDataSource.query method is not allowed, this will throw
|
||||
const numberOfTablesWithSameName = +(
|
||||
await workspaceDataSource.query(
|
||||
await coreDataSource.query(
|
||||
`SELECT count(table_name) FROM information_schema.tables WHERE table_name LIKE '${tableName}' AND table_schema IN ('core', '${workspaceSchemaName}')`,
|
||||
)
|
||||
)[0].count;
|
||||
@@ -32,13 +31,13 @@ const isNameAvailable = async (
|
||||
export const getRemoteTableLocalName = async (
|
||||
distantTableName: string,
|
||||
workspaceSchemaName: string,
|
||||
workspaceDataSource: DataSource,
|
||||
coreDataSource: DataSource,
|
||||
): Promise<RemoteTableLocalName> => {
|
||||
const baseName = singular(camelCase(distantTableName));
|
||||
const isBaseNameValid = await isNameAvailable(
|
||||
baseName,
|
||||
workspaceSchemaName,
|
||||
workspaceDataSource,
|
||||
coreDataSource,
|
||||
);
|
||||
|
||||
if (isBaseNameValid) {
|
||||
@@ -50,7 +49,7 @@ export const getRemoteTableLocalName = async (
|
||||
const isNameWithSuffixValid = await isNameAvailable(
|
||||
name,
|
||||
workspaceSchemaName,
|
||||
workspaceDataSource,
|
||||
coreDataSource,
|
||||
);
|
||||
|
||||
if (isNameWithSuffixValid) {
|
||||
|
||||
+15
-21
@@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
|
||||
import { type DataSource, type EntityManager } from 'typeorm';
|
||||
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
import {
|
||||
PermissionsException,
|
||||
@@ -14,26 +14,10 @@ import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/ge
|
||||
export class WorkspaceDataSourceService {
|
||||
constructor(
|
||||
private readonly dataSourceService: DataSourceService,
|
||||
private readonly typeormService: TypeORMService,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
) {}
|
||||
|
||||
/**
|
||||
*
|
||||
* Connect to the workspace data source
|
||||
*
|
||||
* @param workspaceId
|
||||
* @returns
|
||||
*/
|
||||
public async connectToMainDataSource(): Promise<DataSource> {
|
||||
const dataSource = this.typeormService.getMainDataSource();
|
||||
|
||||
if (!dataSource) {
|
||||
throw new Error(`Could not connect to workspace data source`);
|
||||
}
|
||||
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
public async checkSchemaExists(workspaceId: string) {
|
||||
const dataSource =
|
||||
await this.dataSourceService.getDataSourcesMetadataFromWorkspaceId(
|
||||
@@ -53,7 +37,13 @@ export class WorkspaceDataSourceService {
|
||||
public async createWorkspaceDBSchema(workspaceId: string): Promise<string> {
|
||||
const schemaName = getWorkspaceSchemaName(workspaceId);
|
||||
|
||||
return await this.typeormService.createSchema(schemaName);
|
||||
const queryRunner = this.coreDataSource.createQueryRunner();
|
||||
|
||||
await queryRunner.createSchema(schemaName, true);
|
||||
|
||||
await queryRunner.release();
|
||||
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +56,11 @@ export class WorkspaceDataSourceService {
|
||||
public async deleteWorkspaceDBSchema(workspaceId: string): Promise<void> {
|
||||
const schemaName = getWorkspaceSchemaName(workspaceId);
|
||||
|
||||
return await this.typeormService.deleteSchema(schemaName);
|
||||
const queryRunner = this.coreDataSource.createQueryRunner();
|
||||
|
||||
await queryRunner.dropSchema(schemaName, true);
|
||||
|
||||
await queryRunner.release();
|
||||
}
|
||||
|
||||
public async executeRawQuery(
|
||||
|
||||
+9
@@ -19,6 +19,7 @@ import { RoleService } from 'src/engine/metadata-modules/role/role.service';
|
||||
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
|
||||
import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
|
||||
import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
|
||||
import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service';
|
||||
@@ -124,6 +125,14 @@ describe('WorkspaceManagerService', () => {
|
||||
.mockResolvedValue({ id: 'mock-agent-id' }),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: TwentyORMGlobalManager,
|
||||
useValue: {
|
||||
getDataSourceForWorkspace: jest.fn().mockResolvedValue({
|
||||
transaction: jest.fn(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
+33
-42
@@ -1,10 +1,9 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
|
||||
import { Repository } from 'typeorm';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { FieldPermissionService } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.service';
|
||||
@@ -33,9 +32,10 @@ export class DevSeederPermissionsService {
|
||||
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
@InjectRepository(RoleEntity)
|
||||
private readonly roleRepository: Repository<RoleEntity>,
|
||||
private readonly typeORMService: TypeORMService,
|
||||
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
|
||||
private readonly fieldPermissionService: FieldPermissionService,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
) {}
|
||||
|
||||
public async initPermissions(workspaceId: string) {
|
||||
@@ -52,39 +52,33 @@ export class DevSeederPermissionsService {
|
||||
);
|
||||
}
|
||||
|
||||
const dataSource = this.typeORMService.getMainDataSource();
|
||||
|
||||
if (dataSource) {
|
||||
try {
|
||||
await dataSource
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into('core.roleTargets', ['roleId', 'apiKeyId', 'workspaceId'])
|
||||
.orIgnore()
|
||||
.values([
|
||||
{
|
||||
roleId: adminRole.id,
|
||||
apiKeyId: API_KEY_DATA_SEED_IDS.ID_1,
|
||||
workspaceId: workspaceId,
|
||||
},
|
||||
])
|
||||
.execute();
|
||||
|
||||
await this.workspacePermissionsCacheService.recomputeApiKeyRoleMapCache(
|
||||
try {
|
||||
await this.coreDataSource
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into('core.roleTargets', ['roleId', 'apiKeyId', 'workspaceId'])
|
||||
.orIgnore()
|
||||
.values([
|
||||
{
|
||||
workspaceId,
|
||||
roleId: adminRole.id,
|
||||
apiKeyId: API_KEY_DATA_SEED_IDS.ID_1,
|
||||
workspaceId: workspaceId,
|
||||
},
|
||||
);
|
||||
await this.workspacePermissionsCacheService.recomputeUserWorkspaceRoleMapCache(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Could not assign role to test API key: ${error.message}`,
|
||||
);
|
||||
}
|
||||
])
|
||||
.execute();
|
||||
|
||||
await this.workspacePermissionsCacheService.recomputeApiKeyRoleMapCache({
|
||||
workspaceId,
|
||||
});
|
||||
await this.workspacePermissionsCacheService.recomputeUserWorkspaceRoleMapCache(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Could not assign role to test API key: ${error.message}`,
|
||||
);
|
||||
}
|
||||
|
||||
let adminUserWorkspaceId: string | undefined;
|
||||
@@ -137,13 +131,10 @@ export class DevSeederPermissionsService {
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
await this.typeORMService
|
||||
.getMainDataSource()
|
||||
?.getRepository(Workspace)
|
||||
.update(workspaceId, {
|
||||
defaultRoleId: memberRole.id,
|
||||
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
||||
});
|
||||
await this.coreDataSource.getRepository(Workspace).update(workspaceId, {
|
||||
defaultRoleId: memberRole.id,
|
||||
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
||||
});
|
||||
|
||||
if (memberUserWorkspaceIds) {
|
||||
for (const memberUserWorkspaceId of memberUserWorkspaceIds) {
|
||||
|
||||
+6
-10
@@ -1,10 +1,12 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
|
||||
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
|
||||
import { computeTableName } from 'src/engine/utils/compute-table-name.util';
|
||||
import { shouldSeedWorkspaceFavorite } from 'src/engine/utils/should-seed-workspace-favorite';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import {
|
||||
CALENDAR_CHANNEL_DATA_SEED_COLUMNS,
|
||||
CALENDAR_CHANNEL_DATA_SEEDS,
|
||||
@@ -196,7 +198,8 @@ const RECORD_SEEDS_CONFIGS = [
|
||||
@Injectable()
|
||||
export class DevSeederDataService {
|
||||
constructor(
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
private readonly objectMetadataService: ObjectMetadataService,
|
||||
private readonly timelineActivitySeederService: TimelineActivitySeederService,
|
||||
) {}
|
||||
@@ -208,17 +211,10 @@ export class DevSeederDataService {
|
||||
schemaName: string;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
const mainDataSource =
|
||||
await this.workspaceDataSourceService.connectToMainDataSource();
|
||||
|
||||
if (!mainDataSource) {
|
||||
throw new Error('Could not connect to main data source');
|
||||
}
|
||||
|
||||
const objectMetadataItems =
|
||||
await this.objectMetadataService.findManyWithinWorkspace(workspaceId);
|
||||
|
||||
await mainDataSource.transaction(
|
||||
await this.coreDataSource.transaction(
|
||||
async (entityManager: WorkspaceEntityManager) => {
|
||||
for (const recordSeedsConfig of RECORD_SEEDS_CONFIGS) {
|
||||
const objectMetadata = objectMetadataItems.find(
|
||||
|
||||
+9
-10
@@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
|
||||
import { isDefined } from 'class-validator';
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { type DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||
import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service';
|
||||
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
|
||||
@@ -26,7 +26,8 @@ export class DevSeederMetadataService {
|
||||
constructor(
|
||||
private readonly objectMetadataService: ObjectMetadataService,
|
||||
private readonly fieldMetadataService: FieldMetadataService,
|
||||
private readonly typeORMService: TypeORMService,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
) {}
|
||||
|
||||
private readonly workspaceConfigs: Record<
|
||||
@@ -152,15 +153,13 @@ export class DevSeederMetadataService {
|
||||
}
|
||||
|
||||
private async seedCoreViews(workspaceId: string): Promise<void> {
|
||||
const mainDataSource = this.typeORMService.getMainDataSource();
|
||||
|
||||
if (!isDefined(mainDataSource)) {
|
||||
throw new Error('Could not connect to main data source');
|
||||
}
|
||||
|
||||
const createdObjectMetadata =
|
||||
await this.objectMetadataService.findManyWithinWorkspace(workspaceId);
|
||||
|
||||
await prefillCoreViews(mainDataSource, workspaceId, createdObjectMetadata);
|
||||
await prefillCoreViews(
|
||||
this.coreDataSource,
|
||||
workspaceId,
|
||||
createdObjectMetadata,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-9
@@ -1,6 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
@@ -15,7 +17,6 @@ import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/works
|
||||
@Injectable()
|
||||
export class DevSeederService {
|
||||
constructor(
|
||||
private readonly typeORMService: TypeORMService,
|
||||
private readonly workspaceCacheStorageService: WorkspaceCacheStorageService,
|
||||
private readonly twentyConfigService: TwentyConfigService,
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
@@ -25,20 +26,16 @@ export class DevSeederService {
|
||||
private readonly devSeederMetadataService: DevSeederMetadataService,
|
||||
private readonly devSeederPermissionsService: DevSeederPermissionsService,
|
||||
private readonly devSeederDataService: DevSeederDataService,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
) {}
|
||||
|
||||
public async seedDev(workspaceId: string): Promise<void> {
|
||||
const mainDataSource = this.typeORMService.getMainDataSource();
|
||||
|
||||
if (!mainDataSource) {
|
||||
throw new Error('Could not connect to workspace data source');
|
||||
}
|
||||
|
||||
const isBillingEnabled = this.twentyConfigService.get('IS_BILLING_ENABLED');
|
||||
const appVersion = this.twentyConfigService.get('APP_VERSION');
|
||||
|
||||
await seedCoreSchema({
|
||||
dataSource: mainDataSource,
|
||||
dataSource: this.coreDataSource,
|
||||
workspaceId,
|
||||
seedBilling: isBillingEnabled,
|
||||
appVersion,
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@ import { ViewOpenRecordInType } from 'src/modules/view/standard-objects/view.wor
|
||||
import { convertViewFilterOperandToCoreOperand } from 'src/modules/view/utils/convert-view-filter-operand-to-core-operand.util';
|
||||
|
||||
export const prefillCoreViews = async (
|
||||
dataSource: DataSource,
|
||||
coreDataSource: DataSource,
|
||||
workspaceId: string,
|
||||
objectMetadataItems: ObjectMetadataEntity[],
|
||||
featureFlags?: Record<string, boolean>,
|
||||
@@ -52,7 +52,7 @@ export const prefillCoreViews = async (
|
||||
views.push(dashboardsAllView(objectMetadataItems, true));
|
||||
}
|
||||
|
||||
const queryRunner = dataSource.createQueryRunner();
|
||||
const queryRunner = coreDataSource.createQueryRunner();
|
||||
|
||||
await queryRunner.connect();
|
||||
|
||||
|
||||
+29
-28
@@ -1,6 +1,5 @@
|
||||
import { type DataSource } from 'typeorm';
|
||||
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { type WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource';
|
||||
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
|
||||
import { shouldSeedWorkspaceFavorite } from 'src/engine/utils/should-seed-workspace-favorite';
|
||||
import { prefillCompanies } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-companies';
|
||||
@@ -10,38 +9,40 @@ import { prefillWorkflows } from 'src/engine/workspace-manager/standard-objects-
|
||||
import { prefillWorkspaceFavorites } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workspace-favorites';
|
||||
|
||||
export const standardObjectsPrefillData = async (
|
||||
mainDataSource: DataSource,
|
||||
workspaceDataSource: WorkspaceDataSource,
|
||||
schemaName: string,
|
||||
objectMetadataItems: ObjectMetadataEntity[],
|
||||
featureFlags?: Record<string, boolean>,
|
||||
) => {
|
||||
mainDataSource.transaction(async (entityManager: WorkspaceEntityManager) => {
|
||||
await prefillCompanies(entityManager, schemaName);
|
||||
workspaceDataSource.transaction(
|
||||
async (entityManager: WorkspaceEntityManager) => {
|
||||
await prefillCompanies(entityManager, schemaName);
|
||||
|
||||
await prefillPeople(entityManager, schemaName);
|
||||
await prefillPeople(entityManager, schemaName);
|
||||
|
||||
await prefillWorkflows(entityManager, schemaName, objectMetadataItems);
|
||||
await prefillWorkflows(entityManager, schemaName, objectMetadataItems);
|
||||
|
||||
const viewDefinitionsWithId = await prefillViews(
|
||||
entityManager,
|
||||
schemaName,
|
||||
objectMetadataItems,
|
||||
featureFlags,
|
||||
);
|
||||
const viewDefinitionsWithId = await prefillViews(
|
||||
entityManager,
|
||||
schemaName,
|
||||
objectMetadataItems,
|
||||
featureFlags,
|
||||
);
|
||||
|
||||
await prefillWorkspaceFavorites(
|
||||
viewDefinitionsWithId
|
||||
.filter(
|
||||
(view) =>
|
||||
view.key === 'INDEX' &&
|
||||
shouldSeedWorkspaceFavorite(
|
||||
view.objectMetadataId,
|
||||
objectMetadataItems,
|
||||
),
|
||||
)
|
||||
.map((view) => view.id),
|
||||
entityManager,
|
||||
schemaName,
|
||||
);
|
||||
});
|
||||
await prefillWorkspaceFavorites(
|
||||
viewDefinitionsWithId
|
||||
.filter(
|
||||
(view) =>
|
||||
view.key === 'INDEX' &&
|
||||
shouldSeedWorkspaceFavorite(
|
||||
view.objectMetadataId,
|
||||
objectMetadataItems,
|
||||
),
|
||||
)
|
||||
.map((view) => view.id),
|
||||
entityManager,
|
||||
schemaName,
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
+11
-13
@@ -1,8 +1,9 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
|
||||
import { type ColumnType } from 'typeorm';
|
||||
import { type ColumnMetadata } from 'typeorm/metadata/ColumnMetadata';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { DataSource, type ColumnType } from 'typeorm';
|
||||
import { type ColumnMetadata } from 'typeorm/metadata/ColumnMetadata';
|
||||
|
||||
import {
|
||||
type FieldMetadataDefaultValue,
|
||||
@@ -13,7 +14,6 @@ import {
|
||||
type WorkspaceTableStructureResult,
|
||||
} from 'src/engine/workspace-manager/workspace-health/interfaces/workspace-table-definition.interface';
|
||||
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types';
|
||||
import { type FieldMetadataDefaultValueFunctionNames } from 'src/engine/metadata-modules/field-metadata/dtos/default-value.input';
|
||||
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
@@ -26,14 +26,16 @@ import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-
|
||||
|
||||
@Injectable()
|
||||
export class DatabaseStructureService {
|
||||
constructor(private readonly typeORMService: TypeORMService) {}
|
||||
constructor(
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
) {}
|
||||
|
||||
async getWorkspaceTableColumns(
|
||||
schemaName: string,
|
||||
tableName: string,
|
||||
): Promise<WorkspaceTableStructure[]> {
|
||||
const mainDataSource = this.typeORMService.getMainDataSource();
|
||||
const results = await mainDataSource.query<
|
||||
const results = await this.coreDataSource.query<
|
||||
WorkspaceTableStructureResult[]
|
||||
>(`
|
||||
WITH foreign_keys AS (
|
||||
@@ -150,8 +152,6 @@ export class DatabaseStructureService {
|
||||
}
|
||||
|
||||
getPostgresDataTypes(fieldMetadata: FieldMetadataEntity): string[] {
|
||||
const mainDataSource = this.typeORMService.getMainDataSource();
|
||||
|
||||
const normalizer = (
|
||||
type: FieldMetadataType,
|
||||
isArray: boolean | undefined,
|
||||
@@ -166,7 +166,7 @@ export class DatabaseStructureService {
|
||||
return `${objectName}_${columnName}_enum${isArray ? '[]' : ''}`;
|
||||
}
|
||||
|
||||
return mainDataSource.driver.normalizeType({
|
||||
return this.coreDataSource.driver.normalizeType({
|
||||
type: typeORMType,
|
||||
});
|
||||
};
|
||||
@@ -201,7 +201,6 @@ export class DatabaseStructureService {
|
||||
getFieldMetadataTypeFromPostgresDataType(
|
||||
postgresDataType: string,
|
||||
): FieldMetadataType | null {
|
||||
const mainDataSource = this.typeORMService.getMainDataSource();
|
||||
const types = Object.values(FieldMetadataType).filter((type) => {
|
||||
// We're skipping composite and relation types, as they're not directly mapped to a column type
|
||||
if (isCompositeFieldMetadataType(type)) {
|
||||
@@ -219,7 +218,7 @@ export class DatabaseStructureService {
|
||||
const typeORMType = fieldMetadataTypeToColumnType(
|
||||
FieldMetadataType[type],
|
||||
) as ColumnType;
|
||||
const dataType = mainDataSource.driver.normalizeType({
|
||||
const dataType = this.coreDataSource.driver.normalizeType({
|
||||
type: typeORMType,
|
||||
});
|
||||
|
||||
@@ -248,7 +247,6 @@ export class DatabaseStructureService {
|
||||
| null,
|
||||
) => {
|
||||
const typeORMType = fieldMetadataTypeToColumnType(type) as ColumnType;
|
||||
const mainDataSource = this.typeORMService.getMainDataSource();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let value: any =
|
||||
@@ -282,7 +280,7 @@ export class DatabaseStructureService {
|
||||
value = value.replace(/^'/, '').replace(/'$/, '');
|
||||
}
|
||||
|
||||
return mainDataSource.driver.normalizeDefault({
|
||||
return this.coreDataSource.driver.normalizeDefault({
|
||||
type: typeORMType,
|
||||
default: value,
|
||||
isArray: false,
|
||||
|
||||
+9
-5
@@ -1,4 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
import {
|
||||
type WorkspaceHealthIssue,
|
||||
@@ -7,13 +10,15 @@ import {
|
||||
import { type WorkspaceHealthOptions } from 'src/engine/workspace-manager/workspace-health/interfaces/workspace-health-options.interface';
|
||||
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { validName } from 'src/engine/workspace-manager/workspace-health/utils/valid-name.util';
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
|
||||
import { validName } from 'src/engine/workspace-manager/workspace-health/utils/valid-name.util';
|
||||
|
||||
@Injectable()
|
||||
export class ObjectMetadataHealthService {
|
||||
constructor(private readonly typeORMService: TypeORMService) {}
|
||||
constructor(
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
) {}
|
||||
|
||||
async healthCheck(
|
||||
schemaName: string,
|
||||
@@ -50,11 +55,10 @@ export class ObjectMetadataHealthService {
|
||||
schemaName: string,
|
||||
objectMetadata: ObjectMetadataEntity,
|
||||
): Promise<WorkspaceHealthIssue[]> {
|
||||
const mainDataSource = this.typeORMService.getMainDataSource();
|
||||
const issues: WorkspaceHealthIssue[] = [];
|
||||
|
||||
// Check if the table exist in database
|
||||
const tableExist = await mainDataSource.query(
|
||||
const tableExist = await this.coreDataSource.query(
|
||||
`SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_schema = '${schemaName}'
|
||||
AND table_name = '${computeObjectTargetTable(objectMetadata)}')`,
|
||||
);
|
||||
|
||||
@@ -17,6 +17,7 @@ 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 { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import { prefillCoreViews } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-core-views';
|
||||
import { standardObjectsPrefillData } from 'src/engine/workspace-manager/standard-objects-prefill-data/standard-objects-prefill-data';
|
||||
@@ -47,6 +48,7 @@ export class WorkspaceManagerService {
|
||||
@InjectRepository(RoleTargetsEntity)
|
||||
private readonly roleTargetsRepository: Repository<RoleTargetsEntity>,
|
||||
private readonly agentService: AgentService,
|
||||
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
) {}
|
||||
|
||||
public async init({
|
||||
@@ -123,18 +125,16 @@ export class WorkspaceManagerService {
|
||||
workspaceId: string,
|
||||
featureFlags: Record<string, boolean>,
|
||||
) {
|
||||
const mainDataSource =
|
||||
await this.workspaceDataSourceService.connectToMainDataSource();
|
||||
|
||||
if (!mainDataSource) {
|
||||
throw new Error('Could not connect to main data source');
|
||||
}
|
||||
const workspaceDataSource =
|
||||
await this.twentyORMGlobalManager.getDataSourceForWorkspace({
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const createdObjectMetadata =
|
||||
await this.objectMetadataService.findManyWithinWorkspace(workspaceId);
|
||||
|
||||
await standardObjectsPrefillData(
|
||||
mainDataSource,
|
||||
workspaceDataSource,
|
||||
dataSourceMetadata.schema,
|
||||
createdObjectMetadata,
|
||||
featureFlags,
|
||||
@@ -144,7 +144,7 @@ export class WorkspaceManagerService {
|
||||
this.logger.log(`Prefilling core views for workspace ${workspaceId}`);
|
||||
|
||||
await prefillCoreViews(
|
||||
mainDataSource,
|
||||
workspaceDataSource,
|
||||
workspaceId,
|
||||
createdObjectMetadata,
|
||||
featureFlags,
|
||||
|
||||
+5
-12
@@ -1,8 +1,9 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type QueryRunner, Table, type TableColumn } from 'typeorm';
|
||||
import { DataSource, type QueryRunner, Table, type TableColumn } from 'typeorm';
|
||||
|
||||
import {
|
||||
IndexMetadataException,
|
||||
@@ -21,7 +22,6 @@ import {
|
||||
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
|
||||
import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service';
|
||||
import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import { WorkspaceMigrationColumnService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-column.service';
|
||||
import { type PostgresQueryRunner } from 'src/engine/workspace-manager/workspace-migration-runner/types/postgres-query-runner.type';
|
||||
import { tableDefaultColumns } from 'src/engine/workspace-manager/workspace-migration-runner/utils/table-default-column.util';
|
||||
@@ -33,7 +33,8 @@ export class WorkspaceMigrationRunnerService {
|
||||
private readonly logger = new Logger(WorkspaceMigrationRunnerService.name);
|
||||
|
||||
constructor(
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
@InjectDataSource()
|
||||
private readonly coreDataSource: DataSource,
|
||||
private readonly workspaceMigrationService: WorkspaceMigrationService,
|
||||
private readonly workspaceMigrationColumnService: WorkspaceMigrationColumnService,
|
||||
) {}
|
||||
@@ -88,15 +89,7 @@ export class WorkspaceMigrationRunnerService {
|
||||
public async executeMigrationFromPendingMigrations(
|
||||
workspaceId: string,
|
||||
): Promise<WorkspaceMigrationTableAction[]> {
|
||||
const mainDataSource =
|
||||
await this.workspaceDataSourceService.connectToMainDataSource();
|
||||
|
||||
if (!mainDataSource) {
|
||||
throw new Error('Main data source not found');
|
||||
}
|
||||
|
||||
const queryRunner =
|
||||
mainDataSource.createQueryRunner() as PostgresQueryRunner;
|
||||
const queryRunner = this.coreDataSource.createQueryRunner();
|
||||
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
Reference in New Issue
Block a user