import PocketBase, { CommonOptions, RecordFullListOptions, RecordListOptions, RecordModel, RecordOptions, } from "pocketbase" import { Logger } from "winston" /** * 用于扩展记录模型的接口,添加展开字段功能 * @template T 基础对象类型 */ export interface WithExpand { expand: T } /** * PocketBase 数据操作基础类 * 提供通用的 CRUD 操作方法,自动处理错误和日志 * * @template T 继承自 RecordModel 的类型,表示数据库记录模型 */ class PbToolBase { /** PocketBase 集合名称 */ protected dbName: string /** PocketBase 客户端实例 */ protected pbClient: PocketBase /** 日志记录器实例 */ protected logger: Logger /** * 创建 PbToolBase 实例 * * @param dbName - PocketBase 集合名称 * @param pbClient - PocketBase 客户端实例 * @param logger - 日志记录器实例 */ constructor(dbName: string, pbClient: PocketBase, logger: Logger) { this.dbName = dbName this.pbClient = pbClient this.logger = logger } /** * 错误处理包装函数,捕获并记录 PocketBase 操作中的错误 * * @template R - 返回结果类型 * @param fn - 需要执行的异步函数 * @param operation - 操作名称,用于日志记录 * @returns 成功时返回执行结果,失败时返回 null 并记录错误 */ protected managePbError = async ( fn: () => Promise, operation: string ) => { try { const result = await fn() this.logger.debug(`PocketBase ${operation} 成功`, { collection: this.dbName, operation, }) return result } catch (err: any) { this.logger.error(`PocketBase ${operation} 失败`, { collection: this.dbName, operation, error: err.message, }) return null } } /** * 创建新记录 * * @param data - 要创建的记录数据 * @returns 成功时返回创建的记录,失败时返回 null * * @example * ```typescript * const record = await pbTool.create({ name: "示例", value: 100 }); * ``` */ public create = async (data: Partial) => { this.logger.info(`创建记录`, { collection: this.dbName, data }) return this.managePbError( () => this.pbClient.collection(this.dbName).create(data), "create" ) } /** * 获取指定 ID 的记录 * * @template R - 返回记录的类型,默认为 T * @param id - 记录 ID * @param options - 获取记录的选项参数 * @returns 成功时返回查询到的记录,失败时返回 null * * @example * ```typescript * const record = await pbTool.get("record123", { expand: "relation_field" }); * ``` */ public get = async (id: string, options?: RecordOptions) => { this.logger.info(`获取记录`, { collection: this.dbName, id, options }) return this.managePbError( () => this.pbClient.collection(this.dbName).getOne(id, options), "get" ) } /** * 更新指定 ID 的记录 * * @template R - 返回记录的类型,默认为 T * @param id - 记录 ID * @param data - 更新的数据 * @param options - 更新记录的选项参数 * @returns 成功时返回更新后的记录,失败时返回 null * * @example * ```typescript * const updatedRecord = await pbTool.update("record123", { name: "新名称" }); * ``` */ public update = async ( id: string, data: Partial, options?: RecordOptions ) => { this.logger.info(`更新记录`, { collection: this.dbName, id, data, options }) return this.managePbError( () => this.pbClient.collection(this.dbName).update(id, data, options), "update" ) } /** * 删除指定 ID 的记录 * * @param id - 要删除的记录 ID * @param options - 删除记录的选项参数 * @returns 成功时返回 true,失败时返回 null * * @example * ```typescript * const result = await pbTool.delete("record123"); * ``` */ public delete = async (id: string, options?: CommonOptions) => { this.logger.info(`删除记录`, { collection: this.dbName, id, options }) return this.managePbError( () => this.pbClient.collection(this.dbName).delete(id, options), "delete" ) } /** * 获取记录列表 * * @template R - 返回记录的类型,默认为 T * @param options - 列表查询选项,可包含排序、过滤和扩展等参数 * @returns 成功时返回记录数组,失败时返回 null * * @example * ```typescript * const records = await pbTool.list({ * sort: "-created", * filter: "active=true" * }); * ``` */ public list = async (options?: RecordFullListOptions) => { this.logger.info(`获取记录列表`, { collection: this.dbName, filter: options?.filter, sort: options?.sort, options, }) return this.managePbError( () => this.pbClient.collection(this.dbName).getFullList(options), "list" ) } /** * 获取符合过滤条件的第一条记录 * * @template R - 返回记录的类型,默认为 T * @param filter - 过滤条件 * @param options - 查询选项 * @returns 成功时返回第一条匹配记录,失败时返回 null * * @example * ```typescript * const user = await pbTool.getFirstOne("email='test@example.com'"); * ``` */ public getFirstOne = async ( filter: string, options?: RecordListOptions ) => { this.logger.info(`获取第一条匹配记录`, { collection: this.dbName, filter, options, }) return this.managePbError( () => this.pbClient.collection(this.dbName).getFirstListItem(filter, options), "getFirstOne" ) } } export default PbToolBase