perf: use cache for role validation (#23383)
## Context Role assignment validation queried PostgreSQL only to check whether a role exists and whether `canBeAssignedToUsers` is enabled. Both values already exist in `flatRoleMaps`. This validation runs when inviting users and assigning a role to a user workspace. ## What changed - Replace the role repository lookup with `flatRoleMaps` - Resolve the role through the existing keyed flat-map helper - Preserve the existing role-not-found and role-not-assignable errors - Replace unused TypeORM module wiring with the flat entity cache module ## Expected impact On a warm workspace cache, role assignment validation uses an O(1) map lookup and avoids a PostgreSQL round trip. Cold caches retain the normal workspace cache recomputation behavior. ## Validation - Typecheck reports no errors in the changed files - Existing validation outcomes and exception codes are preserved <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/23383?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
+3
-9
@@ -1,16 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
|
||||
import { RoleValidationService } from 'src/engine/metadata-modules/role-validation/services/role-validation.service';
|
||||
import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([RoleEntity])],
|
||||
providers: [
|
||||
RoleValidationService,
|
||||
provideWorkspaceScopedRepository(RoleEntity),
|
||||
],
|
||||
imports: [WorkspaceManyOrAllFlatEntityMapsCacheModule],
|
||||
providers: [RoleValidationService],
|
||||
exports: [RoleValidationService],
|
||||
})
|
||||
export class RoleValidationModule {}
|
||||
|
||||
+13
-9
@@ -5,25 +5,29 @@ import {
|
||||
PermissionsExceptionCode,
|
||||
PermissionsExceptionMessage,
|
||||
} from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator';
|
||||
import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
|
||||
@Injectable()
|
||||
export class RoleValidationService {
|
||||
constructor(
|
||||
@InjectWorkspaceScopedRepository(RoleEntity)
|
||||
private readonly roleRepository: WorkspaceScopedRepository<RoleEntity>,
|
||||
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
) {}
|
||||
|
||||
async validateRoleAssignableToUsersOrThrow(
|
||||
roleId: string,
|
||||
workspaceId: string,
|
||||
): Promise<void> {
|
||||
const role = await this.roleRepository.findOne(workspaceId, {
|
||||
where: {
|
||||
id: roleId,
|
||||
},
|
||||
const { flatRoleMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatRoleMaps'],
|
||||
},
|
||||
);
|
||||
const role = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: roleId,
|
||||
flatEntityMaps: flatRoleMaps,
|
||||
});
|
||||
|
||||
if (!role) {
|
||||
|
||||
Reference in New Issue
Block a user