import { Injectable, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, FindManyOptions, FindOptionsWhere, ILike } from 'typeorm'; import { CreateRecurrenceRuleDto } from './dto/create-recurrence-rule.dto'; import { UpdateRecurrenceRuleDto } from './dto/update-recurrence-rule.dto'; import { QueryRecurrenceRuleDto } from './dto/query-recurrence-rule.dto'; import { RecurrenceRule } from '../entity/recurrence-rule.entity'; type QueryConfigItem = { param: keyof Omit< QueryRecurrenceRuleDto, 'page' | 'limit' | 'sortBy' | 'order' >; dbField: keyof RecurrenceRule; operator: 'equals' | 'like'; }; @Injectable() export class RecurrenceRulesService { constructor( @InjectRepository(RecurrenceRule) private readonly recurrenceRuleRepository: Repository, ) {} private readonly searchableFields: (keyof RecurrenceRule)[] = [ 'frequency', 'by_day', ]; create(createRecurrenceRuleDto: CreateRecurrenceRuleDto) { const newRecord = this.recurrenceRuleRepository.create( createRecurrenceRuleDto, ); return this.recurrenceRuleRepository.save(newRecord); } async findAll(queryParams: QueryRecurrenceRuleDto) { const { page = 1, limit = 0, sortBy, order, ...filters } = queryParams; const queryConfig: QueryConfigItem[] = []; const whereClause: { [key: string]: any } = {}; for (const config of queryConfig) { if (filters[config.param] !== undefined) { if (config.operator === 'like') { whereClause[config.dbField] = ILike(`%${filters[config.param]}%`); } else { whereClause[config.dbField] = filters[config.param]; } } } const findOptions: FindManyOptions = { where: whereClause as FindOptionsWhere, }; const paginated = limit > 0; if (paginated) { findOptions.skip = (page - 1) * limit; findOptions.take = limit; } if (sortBy && order) { findOptions.order = { [sortBy]: order }; } const [data, totalItems] = await this.recurrenceRuleRepository.findAndCount(findOptions); if (!paginated) { return { data, total: data.length }; } return { data, meta: { totalItems, itemCount: data.length, itemsPerPage: limit, totalPages: Math.ceil(totalItems / limit), currentPage: page, }, }; } async search(term: string, options: { page: number; limit: number }) { if (this.searchableFields.length === 0) { console.warn('Search is not configured for this entity.'); return { data: [], meta: { totalItems: 0, itemCount: 0, itemsPerPage: options.limit, totalPages: 0, currentPage: options.page, }, }; } const whereConditions = this.searchableFields.map((field) => ({ [field]: ILike(`%${term}%`), })); const [data, totalItems] = await this.recurrenceRuleRepository.findAndCount( { where: whereConditions, skip: (options.page - 1) * options.limit, take: options.limit, }, ); return { data, meta: { totalItems, itemCount: data.length, itemsPerPage: options.limit, totalPages: Math.ceil(totalItems / options.limit), currentPage: options.page, }, }; } async findOne(id: number) { const record = await this.recurrenceRuleRepository.findOneBy({ id: id, }); if (!record) { throw new NotFoundException(`RecurrenceRule with ID ${id} not found`); } return record; } async update(id: number, updateRecurrenceRuleDto: UpdateRecurrenceRuleDto) { const record = await this.findOne(id); Object.assign(record, updateRecurrenceRuleDto); return this.recurrenceRuleRepository.save(record); } async remove(id: number) { const result = await this.recurrenceRuleRepository.delete(id); if (result.affected === 0) { throw new NotFoundException(`RecurrenceRule with ID ${id} not found`); } return { deleted: true, id }; } }