import { LoggerService } from '@/modules/logger/pino/logger.service'; import { Cache } from '@nestjs/cache-manager'; import { Paginated, PaginateQuery } from 'nestjs-paginate'; import { CacheConfiguration, InvalidationStrategy } from '../domain/interfaces/cache-configuration.interface'; import { IBaseService } from './base.interface'; import { CachedService } from './cached.service'; /** * Base CRUD service with caching capabilities. */ export class CachedBaseService< Entity, CreateMessage, UpdateMessage extends { id: number | string }, Message, > extends CachedService implements IBaseService { /** * Creates an instance of CachedBaseService. * * @param {LoggerService} logger - The logger service. * @param {IBaseService} service - The service to add the caching layer to. * @param {Cache} cacheManager - The NestJS cache manager. * @param {CacheConfiguration} cacheConfig - The cache configuration. */ constructor( protected readonly logger: LoggerService, protected readonly service: IBaseService, protected readonly cacheManager: Cache, protected readonly cacheConfig: CacheConfiguration, ) { super(logger, cacheManager, cacheConfig); } /** * Finds a single entity by its ID with caching. * * @param {number | string} id - The ID of the entity to find. * @returns {Promise} A promise that resolves to the mapped message. */ async findOne(id: number | string): Promise { const cacheKey = this.generateCacheKey('findOne', { id }); return await this.getOrSetCache(cacheKey, async () => await this.service.findOne(id)); } /** * Retrieves all entities with caching. * * @returns {Promise<{ data: Message[] }>} A promise that resolves to an object containing an array of mapped messages. */ async findAll(): Promise<{ data: Message[] }> { const cacheKey = this.generateCacheKey('findAll'); return await this.getOrSetCache(cacheKey, async () => await this.service.findAll()); } /** * Retrieves paginated entities based on the provided query with caching. * The cache key includes filters to ensure correct results for different queries. * * @param {PaginateQuery} query - Pagination and filter criteria. * @returns {Promise>} A promise that resolves to the paginated result. */ async getMany(query?: PaginateQuery): Promise> { const cacheKey = this.generateCacheKey('getMany', query); return await this.getOrSetCache(cacheKey, async () => await this.service.getMany(query)); } /** * Creates a new entity and invalidates cache. * * @param {CreateMessage} createDTO - The data transfer object for creating an entity. * @returns {Promise} A promise that resolves to the mapped message of the created entity. */ async create(createDTO: CreateMessage): Promise { const result = await this.service.create(createDTO); if (this.cacheConfig.invalidationStrategy === InvalidationStrategy.OnChange) { await this.invalidateCache(); } return result; } /** * Updates an existing entity and invalidates cache. * * @param {UpdateMessage} updateDTO - The data transfer object for updating an entity. * @returns {Promise} A promise that resolves to the mapped message of the updated entity. */ async update(updateDTO: UpdateMessage): Promise { const result = await this.service.update(updateDTO); if (this.cacheConfig.invalidationStrategy === InvalidationStrategy.OnChange) { await this.invalidateCache(); } return result; } /** * Deletes an entity by its ID and invalidates cache. * * @param {number | string} id - The ID of the entity to delete. * @returns {Promise} A promise that resolves when the entity is deleted. */ async remove(id: number | string): Promise { await this.service.remove(id); if (this.cacheConfig.invalidationStrategy === InvalidationStrategy.OnChange) { await this.invalidateCache(); } } /** * Counts all entities with caching. * * @param {any} options - Optional query options for counting entities. * @returns {Promise<{ count: number }>} A promise that resolves to an object containing the count. */ async count(options?: any): Promise<{ count: number }> { const cacheKey = this.generateCacheKey('count', options); return await this.getOrSetCache(cacheKey, async () => await this.service.count(options)); } }