返回 AiToEarn
base.repository.ts
根目录 / project / aitoearn-backend / libs / mongodb / src / repositories / base.repository.ts
1 import { Pagination } from '@yikart/common'
2 import { DeleteOptions } from 'mongodb'
3 import {
4 FilterQuery,
5 FlattenMaps,
6 Model,
7 MongooseBaseQueryOptions,
8 ProjectionType,
9 QueryOptions,
10 Require_id,
11 UpdateQuery,
12 } from 'mongoose'
13
14 export type LeanDoc<T> = FlattenMaps<Require_id<T>>
15
16 export interface PaginationParams<TDocument> extends Pagination {
17 filter?: FilterQuery<TDocument>
18 projection?: ProjectionType<TDocument> | null | undefined
19 options?: QueryOptions<TDocument>
20 }
21
22 export type CreateDocumentType<TDocument> = Partial<TDocument>
23
24 export type UpdateDocumentType<TDocument> = UpdateQuery<TDocument>
25
26 export class BaseRepository<TDocument> {
27 constructor(
28 protected readonly model: Model<TDocument>,
29 ) { }
30
31 /**
32 * 根据ID获取单个文档
33 */
34 async getById(id: string, options?: QueryOptions<TDocument>): Promise<LeanDoc<TDocument> | null> {
35 return await this.model.findById(id, undefined, options).lean({ virtuals: true }).exec() as LeanDoc<TDocument> | null
36 }
37
38 /**
39 * 创建新文档
40 */
41 async create(data: CreateDocumentType<TDocument>): Promise<LeanDoc<TDocument>> {
42 const created = new this.model(data)
43 const saved = await created.save()
44 return saved.toObject() as LeanDoc<TDocument>
45 }
46
47 /**
48 * 批量创建文档
49 */
50 async createMany(data: CreateDocumentType<TDocument>[]): Promise<LeanDoc<TDocument>[]> {
51 const docs = await this.model.insertMany(data, { lean: true })
52 return docs.map(doc => ({ ...doc, id: String(doc._id) })) as unknown as LeanDoc<TDocument>[]
53 }
54
55 /**
56 * 根据ID更新文档
57 */
58 async updateById(
59 id: string,
60 update: UpdateDocumentType<TDocument>,
61 options?: QueryOptions<TDocument>,
62 ): Promise<LeanDoc<TDocument> | null> {
63 return await this.model.findByIdAndUpdate(id, update, { new: true, ...options }).lean({ virtuals: true }).exec() as LeanDoc<TDocument> | null
64 }
65
66 /**
67 * 更新单个文档
68 */
69 protected async updateOne(
70 filter: FilterQuery<TDocument>,
71 update: UpdateDocumentType<TDocument>,
72 options?: QueryOptions<TDocument>,
73 ): Promise<LeanDoc<TDocument> | null> {
74 return await this.model.findOneAndUpdate(filter, update, { new: true, ...options }).lean({ virtuals: true }).exec() as LeanDoc<TDocument> | null
75 }
76
77 /**
78 * 根据ID删除文档
79 */
80 async deleteById(id: string, options?: QueryOptions<TDocument>): Promise<LeanDoc<TDocument> | null> {
81 return await this.model.findByIdAndDelete(id, options).lean({ virtuals: true }).exec() as LeanDoc<TDocument> | null
82 }
83
84 /**
85 * 删除单个文档
86 */
87 protected async deleteOne(filter: FilterQuery<TDocument>, options?: (DeleteOptions & MongooseBaseQueryOptions<TDocument>)) {
88 return await this.model.deleteOne(filter, options).exec()
89 }
90
91 /**
92 * 批量删除文档
93 */
94 protected async deleteMany(filter: FilterQuery<TDocument>): Promise<void> {
95 await this.model.deleteMany(filter).exec()
96 }
97
98 /**
99 * 分页查询
100 */
101 protected async findWithPagination(params: PaginationParams<TDocument>): Promise<readonly [LeanDoc<TDocument>[], number]> {
102 const { page, pageSize, filter = {}, options = {}, projection } = params
103 const skip = (page - 1) * pageSize
104
105 const findOptions = { ...options, skip, limit: pageSize }
106
107 const [items, total] = await Promise.all([
108 this.model.find(filter, projection, findOptions).lean({ virtuals: true }).exec() as Promise<LeanDoc<TDocument>[]>,
109 this.model.countDocuments(filter).exec(),
110 ])
111
112 return [items, total] as const
113 }
114
115 /**
116 * 查找单个文档
117 */
118 protected async findOne(filter: FilterQuery<TDocument>, options?: QueryOptions<TDocument>): Promise<LeanDoc<TDocument> | null> {
119 return await this.model.findOne(filter, undefined, options).lean({ virtuals: true }).exec() as LeanDoc<TDocument> | null
120 }
121
122 /**
123 * 查找多个文档
124 */
125 protected async find(filter: FilterQuery<TDocument> = {}, options?: QueryOptions<TDocument>): Promise<LeanDoc<TDocument>[]> {
126 return await this.model.find(filter, undefined, options).lean({ virtuals: true }).exec() as LeanDoc<TDocument>[]
127 }
128
129 /**
130 * 统计文档数量
131 */
132 protected async count(filter: FilterQuery<TDocument> = {}): Promise<number> {
133 return await this.model.countDocuments(filter).exec()
134 }
135
136 /**
137 * 检查文档是否存在
138 */
139 protected async exists(filter: FilterQuery<TDocument>): Promise<boolean> {
140 const result = await this.model.exists(filter).exec()
141 return result !== null
142 }
143 }
144
144 lines TYPESCRIPT