import { FindOrCreate } from '@typegoose/typegoose/lib/defaultClasses' import { checkJson } from '../decorators/nojson' import { plugin, ReturnModelType } from '@typegoose/typegoose' // @ts-ignore import findOrCreate from 'mongoose-findorcreate' import { Connection } from 'mongoose' import { ObjectId } from 'bson' import { isTrue } from 'zutils/utils/string.util' import { AnyParamConstructor } from '@typegoose/typegoose/lib/types' const jsonExcludeKeys = ['updatedAt', '__v'] const saveExcludeKeys = ['createdAt', 'updatedAt', '__v', '_id'] @plugin(findOrCreate) export abstract class BaseModule extends FindOrCreate { static db: Connection public updateFromReq(data: any) { for (let key in data) { if (saveExcludeKeys.indexOf(key) == -1) { this[key] = data[key] } } } /** * 插入或更新 * @param condition * @param data */ public static insertOrUpdate( this: ReturnModelType>, condition: any, data: any, ) { return this.findOneAndUpdate(condition, data, { upsert: true, new: true, setDefaultsOnInsert: true }) } /** * 虚拟删除 * @param {string[]} ids */ public static deleteVirtual(this: ReturnModelType>, ids: string[]) { return this.updateMany( // @ts-ignore { _id: { $in: ids }, }, { $set: { deleted: true, deleteTime: new Date(), }, }, ) } /** * 自定义分页查询 * @param data * @param {boolean} json */ public static async pageQuery( this: ReturnModelType>, data: any, json: boolean = false, ) { let { start, limit, page } = data limit = +limit || 10 start = +start || (+page - 1) * limit || 0 // @ts-ignore let { opt, sort } = this.parseQueryParam(data) let records = await this.find(opt).sort(sort).skip(start).limit(limit) let total = await this.countDocuments(opt) if (json) { records.map((o: T) => o.toJson()) } return { records, total, start, limit } } public toJson() { let result: any = {} // @ts-ignore for (let key in this._doc) { if (checkJson(this, key + '') && jsonExcludeKeys.indexOf(key) == -1) { result[key] = this[key] } } return result } /** * 通用的查询条件拼接方法 * @param {{}} params req.params * @param options * sort: 排序 比如: {createdAt: 1} 默认是 {_id: 1} * opt: 设置一些特殊的过滤条件, 比如{deleted: 0} * timeKey: 如果需要查询创建时间, 而且创建时间不为 createdAt, 可以用此字段设置 * matchKey: 指定关键字查询的匹配字段, 可为string或[string] * * @return {{opt: any, sort: {_id: number}}} */ public static parseQueryParam(params: {}, options?: any) { const opt: any = { deleted: false } // @ts-ignore let obj = this.schema.paths for (let key in params) { if (key !== 'sort' && obj.hasOwnProperty(key)) { switch (obj[key].instance) { case 'String': opt[key] = { $regex: params[key], $options: 'i' } break case 'Number': opt[key] = params[key] break case 'Array': if (Array.isArray(params[key])) { opt[key] = { $in: params[key] } } else { opt[key] = params[key] } break case 'Date': // TODO: break case 'Boolean': opt[key] = isTrue(params[key]) break case 'ObjectID': if (/^[0-9a-fA-F]{24}$/.test(params[key])) { opt[key] = new ObjectId(params[key]) } break } } } if (params.hasOwnProperty('key') && params['key']) { let orArr = [] if (options?.matchKey) { if (Array.isArray(options?.matchKey)) { for (let key in options?.matchKey) { let _tmp = {} _tmp[key] = { $regex: params['key'], $options: 'i' } orArr.push(_tmp) } } else { let _tmp = {} _tmp[options.matchKey] = { $regex: params['key'], $options: 'i' } orArr.push(_tmp) } } else { for (let key in obj) { if (obj[key].instance === 'String') { let _tmp = {} _tmp[key] = { $regex: params['key'], $options: 'i' } orArr.push(_tmp) } } } Object.assign(opt, { $or: orArr }) } let timeKey = options?.timeKey ? options.timeKey : 'createdAt' if (params.hasOwnProperty('timeBegin') && !params.hasOwnProperty('timeEnd')) { let timeBegin = params['timeBegin'] if (!(timeBegin instanceof Date)) { timeBegin = new Date(parseInt(timeBegin)) } opt[timeKey] = { $gte: timeBegin } } else if (params.hasOwnProperty('timeBegin') && params.hasOwnProperty('timeEnd')) { let timeBegin = params['timeBegin'] if (!(timeBegin instanceof Date)) { timeBegin = new Date(parseInt(timeBegin)) } let timeEnd = params['timeEnd'] if (!(timeEnd instanceof Date)) { timeEnd = new Date(parseInt(timeEnd)) } let tmpB = {} tmpB[timeKey] = { $gte: timeBegin } let tmpE = {} tmpE[timeKey] = { $lte: timeEnd } opt['$and'] = [tmpB, tmpE] } else if (!params.hasOwnProperty('timeBegin') && params.hasOwnProperty('timeEnd')) { let timeEnd = params['timeEnd'] if (!(timeEnd instanceof Date)) { timeEnd = new Date(parseInt(timeEnd)) } opt[timeKey] = { $lte: timeEnd } } if (options?.opt) { Object.assign(opt, options.opt) } let sort = { _id: 1 } if (params.hasOwnProperty('sort')) { sort = params['sort'] } return { opt, sort } } }