import { HttpError } from "@lib/error-handling/http-error"; import { AnyKeys, Document, FilterQuery, Model } from "mongoose"; export const CrudService = ( model: Model ) => { return class CrudServiceClass { protected model: Model = model; async create(data: AnyKeys): Promise { return this.model.create(data); } async updateOne( filter: FilterQuery, data: AnyKeys ): Promise { await this.existsOrThrow(filter); await this.model.updateOne(filter, data); return this.findOneOrFail(filter); } async updateMany( filter: FilterQuery, data: AnyKeys ): Promise { await this.existsOrThrow(filter); await this.model.updateMany(filter, data); return this.model.find(filter); } async deleteOne(filter: FilterQuery): Promise { await this.existsOrThrow(filter); return this.model.findOneAndDelete(filter); } async list( filter: FilterQuery, paginationOptions: { limit?: number; skip?: number; } = { limit: 10, skip: 1, }, options?: { populateArray: any }, ): Promise<{ docs: ModelDoc[]; paginationData: { total: number; page: number; perPage: number; }; }> { const queryInstruction = this.model .find(filter) .limit(paginationOptions.limit) .skip(paginationOptions.skip); if (options?.populateArray) queryInstruction.populate(options.populateArray); const docs = await queryInstruction; const total = await this.model.countDocuments(filter); const paginationData = { total: total, page: paginationOptions.skip, perPage: paginationOptions.limit, }; return { docs, paginationData }; } async search( filter: FilterQuery, paginationOptions: { limit?: number; skip?: number; } = { limit: 10, skip: 1, }, options?: { populateArray: any }, ): Promise<{ docs: ModelDoc[]; paginationData: { total: number; page: number; perPage: number; }; }> { const queryInstruction = this.model .find(filter) .limit(paginationOptions.limit) .skip(paginationOptions.skip); if (options?.populateArray) queryInstruction.populate(options.populateArray); const docs = await queryInstruction; const total = await this.model.countDocuments(filter); const paginationData = { total: total, page: paginationOptions.skip, perPage: paginationOptions.limit, }; return { docs, paginationData }; } async findOne( filter: FilterQuery, options?: { populateArray: any }): Promise { const queryInstruction = this.model.findOne(filter); if (options?.populateArray) queryInstruction.populate(options.populateArray); const document = await queryInstruction return document; } async findOneOrFail( filter: FilterQuery, options?: { populateArray: any } ): Promise { await this.existsOrThrow(filter); const queryInstruction = this.model.findOne(filter); if (options?.populateArray) queryInstruction.populate(options.populateArray); const document = await queryInstruction; return document; } private async existsOrThrow(filter: FilterQuery) { if (!(await this.model.exists(filter))) { throw new HttpError(404, "No Matching Result Found."); } } }; };