返回 AiToEarn
asset.repository.ts
根目录 / project / aitoearn-backend / libs / mongodb / src / repositories / asset.repository.ts
1 import { InjectModel } from '@nestjs/mongoose'
2 import { Pagination, UserType } from '@yikart/common'
3 import { FilterQuery, Model } from 'mongoose'
4 import { AssetStatus, AssetType } from '../enums'
5 import { Asset } from '../schemas'
6 import { BaseRepository } from './base.repository'
7
8 export interface ListAssetsParams extends Pagination {
9 userId: string
10 userType?: UserType
11 type?: AssetType
12 types?: AssetType[]
13 status?: AssetStatus
14 statuses?: AssetStatus[]
15 }
16
17 export class AssetRepository extends BaseRepository<Asset> {
18 constructor(
19 @InjectModel(Asset.name) assetModel: Model<Asset>,
20 ) {
21 super(assetModel)
22 }
23
24 async getByPath(path: string) {
25 return await this.findOne({
26 path,
27 deletedAt: { $exists: false },
28 })
29 }
30
31 async getByIdAndUserId(id: string, userId: string, userType?: UserType) {
32 return await this.findOne({
33 _id: id,
34 userId,
35 ...(userType ? { userType } : {}),
36 deletedAt: { $exists: false },
37 })
38 }
39
40 async listWithPagination(params: ListAssetsParams) {
41 const { page, pageSize, userId, userType, type, types, status, statuses } = params
42
43 const filter: FilterQuery<Asset> = {
44 userId,
45 ...(userType ? { userType } : {}),
46 deletedAt: { $exists: false },
47 ...(types ? { type: { $in: types } } : type && { type }),
48 ...(statuses ? { status: { $in: statuses } } : status && { status }),
49 }
50
51 const [list, total] = await this.findWithPagination({
52 page,
53 pageSize,
54 filter,
55 options: { sort: { createdAt: -1 } },
56 })
57
58 return { list, total }
59 }
60
61 async updateStatus(id: string, status: AssetStatus, additionalData?: Partial<Asset>) {
62 return await this.updateById(id, {
63 status,
64 ...additionalData,
65 })
66 }
67
68 async softDelete(id: string) {
69 return await this.updateById(id, {
70 deletedAt: new Date(),
71 })
72 }
73
74 async softDeleteByUserId(userId: string, assetIds: string[]) {
75 const result = await this.model.updateMany(
76 {
77 _id: { $in: assetIds },
78 userId,
79 deletedAt: { $exists: false },
80 },
81 {
82 $set: { deletedAt: new Date() },
83 },
84 )
85 return { affectedCount: result.modifiedCount }
86 }
87
88 /**
89 * 查找待确认的 assets(PENDING 状态且创建时间超过指定阈值)
90 * @param olderThanSeconds 创建时间超过多少秒的 asset
91 * @param limit 最大返回数量
92 */
93 async findPendingAssets(olderThanSeconds: number, limit = 100) {
94 const threshold = new Date(Date.now() - olderThanSeconds * 1000)
95 return await this.model.find({
96 status: AssetStatus.Pending,
97 createdAt: { $lt: threshold },
98 deletedAt: { $exists: false },
99 }).limit(limit).lean({ virtuals: true }).exec()
100 }
101
102 /**
103 * 将过期的 PENDING assets 标记为失败
104 * @param olderThanSeconds 创建时间超过多少秒视为过期
105 */
106 async markExpiredPendingAsFailed(olderThanSeconds: number) {
107 const threshold = new Date(Date.now() - olderThanSeconds * 1000)
108 const result = await this.model.updateMany(
109 {
110 status: AssetStatus.Pending,
111 createdAt: { $lt: threshold },
112 deletedAt: { $exists: false },
113 },
114 {
115 $set: { status: AssetStatus.Failed },
116 },
117 )
118 return { affectedCount: result.modifiedCount }
119 }
120
121 /**
122 * 根据状态和创建时间获取资源列表
123 * 只查找创建时间超过 minAgeSeconds 的记录
124 */
125 async listByStatusAndAge(status: AssetStatus, minAgeSeconds: number, limit = 50) {
126 const threshold = new Date(Date.now() - minAgeSeconds * 1000)
127 return await this.model.find({
128 status,
129 createdAt: { $lt: threshold },
130 deletedAt: { $exists: false },
131 }).limit(limit).lean({ virtuals: true }).exec()
132 }
133 }
134
134 lines TYPESCRIPT