import { BaseRepository } from "@edr/api-common"; import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { In, Repository } from "typeorm"; import { FileRecord } from "./entities/file.entity"; @Injectable() export class FilesRepository extends BaseRepository { constructor( @InjectRepository(FileRecord) repository: Repository, ) { super(repository); } findByResource(resourceId: string, resource: string): Promise { return this.repository.find({ where: { resourceId, resource } }); } /** * Batch sibling of {@link findByResource} for hydrating a page of resources at * once (a thread of chat messages, say) instead of one query per row. */ async findByResourceIds( resourceIds: string[], resource: string, ): Promise { if (resourceIds.length === 0) return []; return this.repository.find({ where: { resourceId: In(resourceIds), resource }, order: { createdAt: "ASC" }, }); } findByCode( resourceId: string, resource: string, code: string, ): Promise { return this.repository.findOne({ where: { resourceId, resource, code } }); } /** * Retire the live version(s) of a document code. SOFT delete on purpose: the * bytes and the row stay so the original upload can still be read back from * the version history after staff replace it. Every normal read already * filters soft-deleted rows, so callers see only the current version. * * `replacedBy` / `reason` are stamped on the retired row when a newer file is * taking its place (as opposed to a plain removal). */ async deleteByCode( resourceId: string, resource: string, code: string, replacedBy?: { userId?: string | null; reason?: string | null }, ): Promise { if (replacedBy) { await this.repository.update( { resourceId, resource, code }, { replacedByUserId: replacedBy.userId ?? null, replaceReason: replacedBy.reason ?? null, }, ); } await this.repository.softDelete({ resourceId, resource, code }); } /** * Every version of one document code, newest first — superseded versions * included. The only read that deliberately looks past the soft-delete filter. */ findVersionHistory( resourceId: string, resource: string, code: string, ): Promise { return this.repository.find({ where: { resourceId, resource, code }, withDeleted: true, order: { createdAt: "DESC" }, }); } /** * Documents belonging to any of the given resources that a reviewer has asked * the customer to correct. Used by the approval gate, so it takes a list of * resource ids (a company plus each of its company profiles) in one query. */ async findWithOpenChangeRequest( resourceIds: string[], resource: string, ): Promise { if (resourceIds.length === 0) return []; return this.repository.find({ where: { resourceId: In(resourceIds), resource, reviewStatus: "change_requested", }, order: { createdAt: "ASC" }, }); } }