207 lines
6.0 KiB
TypeScript
207 lines
6.0 KiB
TypeScript
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 '../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<T extends BaseModule>(
|
|
this: ReturnModelType<AnyParamConstructor<T>>,
|
|
condition: any,
|
|
data: any,
|
|
) {
|
|
return this.findOneAndUpdate(condition, data, { upsert: true, new: true, setDefaultsOnInsert: true })
|
|
}
|
|
|
|
/**
|
|
* 虚拟删除
|
|
* @param {string[]} ids
|
|
*/
|
|
public static deleteVirtual<T extends BaseModule>(this: ReturnModelType<AnyParamConstructor<T>>, 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<T extends BaseModule>(
|
|
this: ReturnModelType<AnyParamConstructor<T>>,
|
|
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: { $ne: true } }
|
|
// @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 }
|
|
}
|
|
public getTimestampOfID() {
|
|
// Extract the timestamp from the ObjectId
|
|
// @ts-ignore
|
|
return this._id.getTimestamp();
|
|
}
|
|
}
|