Refactor global datasource part 3 (#16447)
## Context Following https://github.com/twentyhq/twenty/pull/16399 Now using the new global orm manager everywhere and returning a GlobalDatasource/WorkspaceDatasource based on a feature flag. This means we now need to wrap all our ORM calls within executeInWorkspaceContext callback (at least for now) so the global datasource can dynamically hydrate its context via the new store (the global datasource does not store anything related to workspaces as it is now a unique singleton). If feature flag is off it still uses local data stored in the workspace datasource.
This commit is contained in:
+2
@@ -15,6 +15,7 @@ import { EntitySchemaFactory } from 'src/engine/twenty-orm/factories/entity-sche
|
||||
import { GlobalWorkspaceDataSourceService } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.service';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { WorkspaceORMEntityMetadatasCacheService } from 'src/engine/twenty-orm/global-workspace-datasource/workspace-orm-entity-metadatas-cache.service';
|
||||
import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module';
|
||||
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
import { WorkspaceEventEmitterModule } from 'src/engine/workspace-event-emitter/workspace-event-emitter.module';
|
||||
@@ -35,6 +36,7 @@ import { WorkspaceEventEmitterModule } from 'src/engine/workspace-event-emitter/
|
||||
TwentyConfigModule,
|
||||
WorkspaceEventEmitterModule,
|
||||
WorkspaceCacheModule,
|
||||
TwentyORMModule,
|
||||
],
|
||||
providers: [
|
||||
GlobalWorkspaceDataSourceService,
|
||||
|
||||
+8
-17
@@ -15,6 +15,7 @@ import { EntityMetadataNotFoundError } from 'typeorm/error/EntityMetadataNotFoun
|
||||
|
||||
import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
|
||||
import { type FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
|
||||
import { type WorkspaceDataSourceInterface } from 'src/engine/twenty-orm/interfaces/workspace-datasource.interface';
|
||||
|
||||
import {
|
||||
PermissionsException,
|
||||
@@ -31,8 +32,12 @@ type CreateQueryBuilderOptions = {
|
||||
calledByWorkspaceEntityManager?: boolean;
|
||||
};
|
||||
|
||||
export class GlobalWorkspaceDataSource extends DataSource {
|
||||
private eventEmitterService: WorkspaceEventEmitter;
|
||||
export class GlobalWorkspaceDataSource
|
||||
extends DataSource
|
||||
implements WorkspaceDataSourceInterface
|
||||
{
|
||||
readonly isGlobalFlow = true;
|
||||
readonly eventEmitterService: WorkspaceEventEmitter;
|
||||
private _isConstructing = true;
|
||||
dataSourceWithOverridenCreateQueryBuilder: GlobalWorkspaceDataSource;
|
||||
|
||||
@@ -102,21 +107,7 @@ export class GlobalWorkspaceDataSource extends DataSource {
|
||||
return super.createEntityManager(queryRunner) as WorkspaceEntityManager;
|
||||
}
|
||||
|
||||
const context = getWorkspaceContext();
|
||||
|
||||
return new WorkspaceEntityManager(
|
||||
{
|
||||
workspaceId: context.authContext.workspace.id,
|
||||
flatObjectMetadataMaps: context.flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps: context.flatFieldMetadataMaps,
|
||||
flatIndexMaps: context.flatIndexMaps,
|
||||
objectIdByNameSingular: context.objectIdByNameSingular,
|
||||
featureFlagsMap: context.featureFlagsMap,
|
||||
eventEmitterService: this.eventEmitterService,
|
||||
},
|
||||
this,
|
||||
queryRunner,
|
||||
);
|
||||
return new WorkspaceEntityManager(undefined, this, queryRunner);
|
||||
}
|
||||
|
||||
override createQueryRunner(
|
||||
|
||||
+77
-14
@@ -1,17 +1,20 @@
|
||||
import { Injectable, type Type } from '@nestjs/common';
|
||||
|
||||
import { ObjectLiteral } from 'typeorm';
|
||||
import { type ObjectLiteral } from 'typeorm';
|
||||
|
||||
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
|
||||
import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
|
||||
import type { WorkspaceDataSourceInterface } from 'src/engine/twenty-orm/interfaces/workspace-datasource.interface';
|
||||
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { buildObjectIdByNameMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/build-object-id-by-name-maps.util';
|
||||
import { GlobalWorkspaceDataSourceService } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.service';
|
||||
import { type WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||
import type { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||
import {
|
||||
type ORMWorkspaceContext,
|
||||
withWorkspaceContext,
|
||||
} from 'src/engine/twenty-orm/storage/orm-workspace-context.storage';
|
||||
import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import type { RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { convertClassNameToObjectMetadataName } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util';
|
||||
|
||||
@@ -20,8 +23,21 @@ export class GlobalWorkspaceOrmManager {
|
||||
constructor(
|
||||
private readonly globalWorkspaceDataSourceService: GlobalWorkspaceDataSourceService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
) {}
|
||||
|
||||
async isGlobalDataSourceFlow(workspaceId: string): Promise<boolean> {
|
||||
const { featureFlagsMap } = await this.workspaceCacheService.getOrRecompute(
|
||||
workspaceId,
|
||||
['featureFlagsMap'],
|
||||
);
|
||||
|
||||
return (
|
||||
featureFlagsMap[FeatureFlagKey.IS_GLOBAL_WORKSPACE_DATASOURCE_ENABLED] ===
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
async getRepository<T extends ObjectLiteral>(
|
||||
workspaceId: string,
|
||||
workspaceEntity: Type<T>,
|
||||
@@ -39,25 +55,57 @@ export class GlobalWorkspaceOrmManager {
|
||||
workspaceEntityOrObjectMetadataName: Type<T> | string,
|
||||
permissionOptions?: RolePermissionConfig,
|
||||
): Promise<WorkspaceRepository<T>> {
|
||||
let objectMetadataName: string;
|
||||
const isGlobalFlow = await this.isGlobalDataSourceFlow(workspaceId);
|
||||
|
||||
if (typeof workspaceEntityOrObjectMetadataName === 'string') {
|
||||
objectMetadataName = workspaceEntityOrObjectMetadataName;
|
||||
} else {
|
||||
objectMetadataName = convertClassNameToObjectMetadataName(
|
||||
workspaceEntityOrObjectMetadataName.name,
|
||||
if (isGlobalFlow) {
|
||||
let objectMetadataName: string;
|
||||
|
||||
if (typeof workspaceEntityOrObjectMetadataName === 'string') {
|
||||
objectMetadataName = workspaceEntityOrObjectMetadataName;
|
||||
} else {
|
||||
objectMetadataName = convertClassNameToObjectMetadataName(
|
||||
workspaceEntityOrObjectMetadataName.name,
|
||||
);
|
||||
}
|
||||
|
||||
const globalDataSource =
|
||||
this.globalWorkspaceDataSourceService.getGlobalWorkspaceDataSource();
|
||||
|
||||
return globalDataSource.getRepository<T>(
|
||||
objectMetadataName,
|
||||
permissionOptions,
|
||||
);
|
||||
}
|
||||
|
||||
const globalDataSource =
|
||||
this.globalWorkspaceDataSourceService.getGlobalWorkspaceDataSource();
|
||||
if (typeof workspaceEntityOrObjectMetadataName === 'string') {
|
||||
return this.twentyORMGlobalManager.getRepositoryForWorkspace<T>(
|
||||
workspaceId,
|
||||
workspaceEntityOrObjectMetadataName,
|
||||
permissionOptions,
|
||||
);
|
||||
}
|
||||
|
||||
return globalDataSource.getRepository<T>(
|
||||
objectMetadataName,
|
||||
return this.twentyORMGlobalManager.getRepositoryForWorkspace<T>(
|
||||
workspaceId,
|
||||
workspaceEntityOrObjectMetadataName,
|
||||
permissionOptions,
|
||||
);
|
||||
}
|
||||
|
||||
async getDataSourceForWorkspace(
|
||||
workspaceId: string,
|
||||
): Promise<WorkspaceDataSourceInterface> {
|
||||
const isGlobalFlow = await this.isGlobalDataSourceFlow(workspaceId);
|
||||
|
||||
if (isGlobalFlow) {
|
||||
return this.globalWorkspaceDataSourceService.getGlobalWorkspaceDataSource();
|
||||
}
|
||||
|
||||
return this.twentyORMGlobalManager.getDataSourceForWorkspace({
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
async getGlobalWorkspaceDataSource() {
|
||||
return this.globalWorkspaceDataSourceService.getGlobalWorkspaceDataSource();
|
||||
}
|
||||
@@ -71,6 +119,18 @@ export class GlobalWorkspaceOrmManager {
|
||||
return withWorkspaceContext(context, fn);
|
||||
}
|
||||
|
||||
async destroyDataSourceForWorkspace(workspaceId: string): Promise<void> {
|
||||
const isGlobalFlow = await this.isGlobalDataSourceFlow(workspaceId);
|
||||
|
||||
if (isGlobalFlow) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.twentyORMGlobalManager.destroyDataSourceForWorkspace(
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
|
||||
private async loadWorkspaceContext(
|
||||
authContext: WorkspaceAuthContext,
|
||||
): Promise<ORMWorkspaceContext> {
|
||||
@@ -83,6 +143,7 @@ export class GlobalWorkspaceOrmManager {
|
||||
featureFlagsMap,
|
||||
rolesPermissions: permissionsPerRoleId,
|
||||
ORMEntityMetadatas: entityMetadatas,
|
||||
userWorkspaceRoleMap,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
@@ -90,6 +151,7 @@ export class GlobalWorkspaceOrmManager {
|
||||
'featureFlagsMap',
|
||||
'rolesPermissions',
|
||||
'ORMEntityMetadatas',
|
||||
'userWorkspaceRoleMap',
|
||||
]);
|
||||
|
||||
const { idByNameSingular: objectIdByNameSingular } =
|
||||
@@ -104,6 +166,7 @@ export class GlobalWorkspaceOrmManager {
|
||||
featureFlagsMap,
|
||||
permissionsPerRoleId,
|
||||
entityMetadatas,
|
||||
userWorkspaceRoleMap,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user