import type { User } from "@cv/auth"; import { PrismaService } from "@cv/system"; import { Injectable } from "@nestjs/common"; import { EventEmitter2 } from "@nestjs/event-emitter"; import type { DataImportSource } from "./data-import-source.interface"; import { UserFileCreatedEvent } from "./events/user-file-created.event"; import { UserFile } from "./user-file.entity"; import { UserFileMapper } from "./user-file.mapper"; @Injectable() export class ImportService { constructor( private readonly prisma: PrismaService, private readonly userFileMapper: UserFileMapper, private readonly eventEmitter: EventEmitter2, ) {} /** * Find an existing completed UserFile with the same fingerprint for this user. */ async findDuplicateForUser( userId: string, fingerprint: string, ): Promise { const record = await this.prisma.userFile.findFirst({ where: { fingerprint, profile: { userId }, status: "completed", }, orderBy: { createdAt: "desc" }, }); return this.userFileMapper.toDomain(record); } /** * Create a UserFile and emit an event for async processing. */ async createImport( user: User, profileId: string, source: DataImportSource, file: { fileName: string; mimeType: string; sizeBytes: number; fingerprint?: string }, params: Record, ): Promise { const record = await this.prisma.userFile.create({ data: { profile: { connect: { id: profileId } }, fingerprint: file.fingerprint ?? null, fileName: file.fileName, mimeType: file.mimeType, sizeBytes: file.sizeBytes, source: source.name, status: "pending", statusMessage: "Queued for processing", }, }); this.eventEmitter.emit( UserFileCreatedEvent.event, new UserFileCreatedEvent(record.id, user, source, params), ); return this.userFileMapper.toDomain(record) as UserFile; } /** * Delete a UserFile and its cascading ImportJobs. */ async deleteUserFile(id: string): Promise { await this.prisma.userFile.delete({ where: { id } }); } async findUserFileById(id: string): Promise { const record = await this.prisma.userFile.findUnique({ where: { id } }); return this.userFileMapper.toDomain(record); } async findUserFilesForUser(userId: string): Promise { const records = await this.prisma.userFile.findMany({ where: { profile: { userId } }, orderBy: { createdAt: "desc" }, }); return this.userFileMapper.mapToDomain(records); } }