Refactor backend folder structure (#4505)

* Refactor backend folder structure

Co-authored-by: Charles Bochet <charles@twenty.com>

* fix tests

* fix

* move yoga hooks

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Weiko
2024-03-15 18:37:09 +01:00
committed by GitHub
parent afb9b3e375
commit 2c09096edd
523 changed files with 1386 additions and 1856 deletions

View File

@ -0,0 +1,78 @@
import { Cache } from '@nestjs/cache-manager';
import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service';
import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum';
const cacheStorageNamespace = CacheStorageNamespace.Messaging;
describe('CacheStorageService', () => {
let cacheStorageService: CacheStorageService;
let cacheManagerMock: Partial<Cache>;
beforeEach(() => {
cacheManagerMock = {
get: jest.fn(),
set: jest.fn(),
};
cacheStorageService = new CacheStorageService(
cacheManagerMock as Cache,
cacheStorageNamespace,
);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('get', () => {
it('should call cacheManager.get with the correct namespaced key', async () => {
const key = 'testKey';
const namespacedKey = `${cacheStorageNamespace}:${key}`;
await cacheStorageService.get(key);
expect(cacheManagerMock.get).toHaveBeenCalledWith(namespacedKey);
});
it('should return the value returned by cacheManager.get', async () => {
const key = 'testKey';
const value = 'testValue';
jest.spyOn(cacheManagerMock, 'get').mockResolvedValue(value);
const result = await cacheStorageService.get(key);
expect(result).toBe(value);
});
});
describe('set', () => {
it('should call cacheManager.set with the correct namespaced key, value, and optional ttl', async () => {
const key = 'testKey';
const value = 'testValue';
const ttl = 60;
const namespacedKey = `${cacheStorageNamespace}:${key}`;
await cacheStorageService.set(key, value, ttl);
expect(cacheManagerMock.set).toHaveBeenCalledWith(
namespacedKey,
value,
ttl,
);
});
it('should not throw if cacheManager.set resolves successfully', async () => {
const key = 'testKey';
const value = 'testValue';
const ttl = 60;
jest.spyOn(cacheManagerMock, 'set').mockResolvedValue(undefined);
await expect(
cacheStorageService.set(key, value, ttl),
).resolves.not.toThrow();
});
});
});

View File

@ -0,0 +1,46 @@
import { CacheModuleOptions } from '@nestjs/common';
import { redisStore } from 'cache-manager-redis-yet';
import { CacheStorageType } from 'src/engine/integrations/cache-storage/types/cache-storage-type.enum';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
export const cacheStorageModuleFactory = (
environmentService: EnvironmentService,
): CacheModuleOptions => {
const cacheStorageType = environmentService.get('CACHE_STORAGE_TYPE');
const cacheStorageTtl = environmentService.get('CACHE_STORAGE_TTL');
const cacheModuleOptions: CacheModuleOptions = {
isGlobal: true,
ttl: cacheStorageTtl * 1000,
};
switch (cacheStorageType) {
case CacheStorageType.Memory: {
return cacheModuleOptions;
}
case CacheStorageType.Redis: {
const host = environmentService.get('REDIS_HOST');
const port = environmentService.get('REDIS_PORT');
if (!(host && port)) {
throw new Error(
`${cacheStorageType} cache storage requires host: ${host} and port: ${port} to be defined, check your .env file`,
);
}
return {
...cacheModuleOptions,
store: redisStore,
socket: {
host,
port,
},
};
}
default:
throw new Error(
`Invalid cache-storage (${cacheStorageType}), check your .env file`,
);
}
};

View File

@ -0,0 +1,31 @@
import { Module, Global } from '@nestjs/common';
import { CacheModule, CACHE_MANAGER, Cache } from '@nestjs/cache-manager';
import { ConfigModule } from '@nestjs/config';
import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { cacheStorageModuleFactory } from 'src/engine/integrations/cache-storage/cache-storage.module-factory';
import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum';
@Global()
@Module({
imports: [
CacheModule.registerAsync({
isGlobal: true,
imports: [ConfigModule],
useFactory: cacheStorageModuleFactory,
inject: [EnvironmentService],
}),
],
providers: [
...Object.values(CacheStorageNamespace).map((cacheStorageNamespace) => ({
provide: cacheStorageNamespace,
useFactory: (cacheManager: Cache) => {
return new CacheStorageService(cacheManager, cacheStorageNamespace);
},
inject: [CACHE_MANAGER],
})),
],
exports: [...Object.values(CacheStorageNamespace)],
})
export class CacheStorageModule {}

View File

@ -0,0 +1,25 @@
import { Inject, Injectable } from '@nestjs/common';
import { CACHE_MANAGER, Cache } from '@nestjs/cache-manager';
import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum';
@Injectable()
export class CacheStorageService {
constructor(
@Inject(CACHE_MANAGER)
private readonly cacheManager: Cache,
private readonly namespace: CacheStorageNamespace,
) {}
async get<T>(key: string): Promise<T | undefined> {
return this.cacheManager.get(`${this.namespace}:${key}`);
}
async set<T>(key: string, value: T, ttl?: number) {
return this.cacheManager.set(`${this.namespace}:${key}`, value, ttl);
}
async del(key: string) {
return this.cacheManager.del(`${this.namespace}:${key}`);
}
}

View File

@ -0,0 +1,4 @@
export enum CacheStorageNamespace {
Messaging = 'messaging',
WorkspaceSchema = 'workspaceSchema',
}

View File

@ -0,0 +1,4 @@
export enum CacheStorageType {
Memory = 'memory',
Redis = 'redis',
}