Spaces:
Runtime error
Runtime error
| import { NotFoundException } from '@nestjs/common'; | |
| import { BaseQueryCoreService } from 'src/core/base-query-core/base-query-core.service'; | |
| import { | |
| BaseQueryCoreDto, | |
| CoreIncludesDto, | |
| } from 'src/core/base-query-core/dto/base-query-core.dto'; | |
| import { safePrismaCall } from 'src/shared/modules/prisma/safe-prisma-call'; | |
| type ErrorMessageType = 'NOT_FOUND' | 'DELETED'; | |
| export type ServiceErrorMessage = { | |
| [key in ErrorMessageType]: string; | |
| }; | |
| export abstract class PrismaBaseRepository< | |
| ModelEntity, | |
| ModelPaginate, | |
| CreateArgs, | |
| UpdateArgs extends { where: Record<string, any> }, | |
| UpdateManyArgs extends { where?: Record<string, any> }, | |
| FindUniqueArgs extends { where: Record<string, any> }, | |
| FindFirstArgs extends { where?: Record<string, any> }, | |
| FindManyArgs extends { | |
| where?: Record<string, any>; | |
| skip?: number; | |
| take?: number; | |
| }, | |
| DeleteArgs extends { where: Record<string, any> }, | |
| DeleteManyArgs extends { where?: Record<string, any> }, | |
| CountArgs extends { where?: Record<string, any> }, | |
| UpsertArgs extends { | |
| where: Record<string, any>; | |
| create: Record<string, any>; | |
| update: Record<string, any>; | |
| }, | |
| > { | |
| constructor( | |
| private readonly repo: any, | |
| public errorMessage: ServiceErrorMessage, | |
| public baseQueryCoreService: any = new BaseQueryCoreService(), | |
| ) {} | |
| async findPaginate( | |
| query: BaseQueryCoreDto, | |
| baseWhere = {}, | |
| ): Promise<ModelPaginate | any> { | |
| const updatedQuery = this.baseQueryCoreService.generatePrismaQuery(query); | |
| const { skip = 0, take = 10, where = {}, ...rest } = updatedQuery; | |
| let list = await safePrismaCall(() => | |
| this.repo.findMany({ | |
| skip, | |
| take: take + 1, | |
| where: { | |
| ...where, | |
| ...baseWhere, | |
| }, | |
| ...rest, | |
| }), | |
| ); | |
| const total = await safePrismaCall(() => | |
| this.repo.count({ | |
| where: { | |
| ...where, | |
| ...baseWhere, | |
| }, | |
| }), | |
| ); | |
| let hasMany = false; | |
| if (list.length > take) { | |
| hasMany = true; | |
| list = list.slice(0, -1); | |
| } | |
| return { | |
| total, | |
| list, | |
| hasMany, | |
| count: list.length, | |
| }; | |
| } | |
| async findPaginateV2( | |
| query: BaseQueryCoreDto, | |
| baseWhere = {}, | |
| ): Promise<ModelPaginate | any> { | |
| const updatedQuery = this.baseQueryCoreService.generatePrismaQuery(query); | |
| const { where = {}, ...rest } = updatedQuery; | |
| const list = await safePrismaCall(() => | |
| this.repo.findMany({ | |
| where: { | |
| ...where, | |
| ...baseWhere, | |
| }, | |
| ...rest, | |
| }), | |
| ); | |
| return { | |
| list, | |
| count: list.length, | |
| }; | |
| } | |
| async checkId(params: { where: any }): Promise<ModelEntity> { | |
| return safePrismaCall(() => | |
| this.repo.findUnique({ where: params.where }), | |
| ).catch(() => { | |
| throw new NotFoundException(this.errorMessage.NOT_FOUND); | |
| }); | |
| } | |
| create(params: CreateArgs): Promise<ModelEntity> { | |
| return safePrismaCall(() => this.repo.create(params)); | |
| } | |
| async getCount(params: CountArgs): Promise<any> { | |
| return safePrismaCall(() => this.repo.count(params)); | |
| } | |
| async update(params: UpdateArgs): Promise<ModelEntity> { | |
| await this.checkId({ where: params.where }); | |
| return safePrismaCall(() => this.repo.update(params)); | |
| } | |
| updateMany(params: UpdateManyArgs): Promise<void> { | |
| return safePrismaCall(() => | |
| this.repo.updateMany(params), | |
| ) as unknown as Promise<void>; | |
| } | |
| async findUnique(params: FindUniqueArgs): Promise<ModelEntity> { | |
| const returnData = await safePrismaCall(() => | |
| this.repo.findUnique(params), | |
| ).catch(() => { | |
| throw new NotFoundException(this.errorMessage.NOT_FOUND); | |
| }); | |
| if (returnData?.isDeleted) { | |
| throw new NotFoundException(this.errorMessage.DELETED); | |
| } | |
| return returnData; | |
| } | |
| findFirst(params: FindFirstArgs): Promise<ModelEntity> { | |
| return safePrismaCall(() => this.repo.findFirst(params)).catch(() => { | |
| throw new NotFoundException(this.errorMessage.NOT_FOUND); | |
| }); | |
| } | |
| findMany(params: FindManyArgs): Promise<ModelEntity[]> { | |
| return safePrismaCall(() => this.repo.findMany(params)); | |
| } | |
| deleteMany(params: DeleteManyArgs): Promise<void> { | |
| return safePrismaCall(() => | |
| this.repo.deleteMany(params), | |
| ) as unknown as Promise<void>; | |
| } | |
| async delete(params: DeleteArgs): Promise<ModelEntity> { | |
| await this.checkId({ where: params.where }); | |
| return safePrismaCall(() => this.repo.delete(params)); | |
| } | |
| async findUniqueIncludes( | |
| params: FindUniqueArgs, | |
| query: CoreIncludesDto, | |
| ): Promise<ModelEntity> { | |
| const updatedQuery = this.baseQueryCoreService.generatePrismaQuery(query); | |
| // Automatically add isDeleted: false filter to related entities | |
| if (updatedQuery.include) { | |
| updatedQuery.include = this.addDeletedFilterToIncludes( | |
| updatedQuery.include, | |
| ); | |
| } | |
| const returnData = await safePrismaCall(() => | |
| this.repo.findUnique({ ...params, ...updatedQuery }), | |
| ).catch(() => { | |
| throw new NotFoundException(this.errorMessage.NOT_FOUND); | |
| }); | |
| if (returnData?.isDeleted) { | |
| throw new NotFoundException(this.errorMessage.DELETED); | |
| } | |
| return returnData; | |
| } | |
| /** | |
| * Helper method to automatically add isDeleted: false filter to related entities | |
| */ | |
| private addDeletedFilterToIncludes(include: any): any { | |
| if (!include) return include; | |
| const result = { ...include }; | |
| // List of relations that have isDeleted field | |
| const relationsWithDeletedField = [ | |
| 'sessions', | |
| 'credentials', | |
| 'user', | |
| 'superAdmin', | |
| ]; | |
| for (const key in result) { | |
| if (result.hasOwnProperty(key)) { | |
| if (relationsWithDeletedField.includes(key)) { | |
| // Add isDeleted: false filter for this relation | |
| if (result[key] === true) { | |
| result[key] = { | |
| where: { | |
| isDeleted: false, | |
| }, | |
| }; | |
| } else if (typeof result[key] === 'object' && result[key] !== null) { | |
| // If it's already an object, merge the where condition | |
| if (!result[key].where) { | |
| result[key].where = {}; | |
| } | |
| result[key].where.isDeleted = false; | |
| // Recursively apply to nested includes | |
| if (result[key].include) { | |
| result[key].include = this.addDeletedFilterToIncludes( | |
| result[key].include, | |
| ); | |
| } | |
| } | |
| } else if (typeof result[key] === 'object' && result[key] !== null) { | |
| // Recursively apply to nested includes | |
| result[key] = this.addDeletedFilterToIncludes(result[key]); | |
| } | |
| } | |
| } | |
| return result; | |
| } | |
| async findFirstIncludes( | |
| params: FindFirstArgs, | |
| query: CoreIncludesDto, | |
| ): Promise<ModelEntity> { | |
| const updatedQuery = this.baseQueryCoreService.generatePrismaQuery(query); | |
| // Automatically add isDeleted: false filter to related entities | |
| if (updatedQuery.include) { | |
| updatedQuery.include = this.addDeletedFilterToIncludes( | |
| updatedQuery.include, | |
| ); | |
| } | |
| const returnData = await safePrismaCall(() => | |
| this.repo.findFirst({ ...params, ...updatedQuery }), | |
| ).catch(() => { | |
| throw new NotFoundException(this.errorMessage.NOT_FOUND); | |
| }); | |
| if (returnData?.isDeleted) { | |
| throw new NotFoundException(this.errorMessage.DELETED); | |
| } | |
| return returnData; | |
| } | |
| async findManyIncludes( | |
| params: FindManyArgs, | |
| query: CoreIncludesDto, | |
| ): Promise<ModelEntity[]> { | |
| const updatedQuery = this.baseQueryCoreService.generatePrismaQuery(query); | |
| return safePrismaCall(() => | |
| this.repo.findMany({ ...params, ...updatedQuery }), | |
| ); | |
| } | |
| async upsert(params: UpsertArgs): Promise<ModelEntity> { | |
| return safePrismaCall(() => this.repo.upsert(params)); | |
| } | |
| } | |