- 9 columns, jobId UNIQUE, ON DELETE CASCADE - Repository: create + findByJobId only (no update/upsert) - 14 unit tests (immutability, security, delete strategy) Co-Authored-By: Claude <noreply@anthropic.com>
47 lines
1.3 KiB
TypeScript
47 lines
1.3 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
||
import { PrismaService } from '../../infrastructure/database/prisma.service';
|
||
|
||
/**
|
||
* M-AI-02-05: 不可变 Job 输入快照 Repository
|
||
*
|
||
* 约束:
|
||
* - 只允许 create + findByJobId
|
||
* - 禁止 update / upsert / 覆盖已有 Snapshot
|
||
* - Snapshot 内容必须在应用层通过安全扫描后方可写入
|
||
*/
|
||
@Injectable()
|
||
export class AiJobSnapshotRepository {
|
||
constructor(private readonly prisma: PrismaService) {}
|
||
|
||
/**
|
||
* 创建快照。每个 Job 最多一个 Snapshot(jobId UNIQUE)。
|
||
* 若已存在则抛出 Prisma 唯一约束错误,调用方应处理。
|
||
*/
|
||
async create(data: {
|
||
jobId: string;
|
||
jobType: string;
|
||
schemaVersion: string;
|
||
redactionVersion?: string;
|
||
content: Record<string, unknown>;
|
||
contentHash?: string;
|
||
expiresAt?: Date;
|
||
}) {
|
||
return this.prisma.aiJobSnapshot.create({ data });
|
||
}
|
||
|
||
/** 按 jobId 查询快照 */
|
||
async findByJobId(jobId: string) {
|
||
return this.prisma.aiJobSnapshot.findUnique({
|
||
where: { jobId },
|
||
});
|
||
}
|
||
|
||
/** 删除过期的快照(由 cleanup service 调用) */
|
||
async deleteExpired(before: Date) {
|
||
const result = await this.prisma.aiJobSnapshot.deleteMany({
|
||
where: { expiresAt: { lt: before } },
|
||
});
|
||
return result.count;
|
||
}
|
||
}
|