egg-orm-ts
Version:
Simple orm with Typeorm, for egg plugin.
364 lines • 25.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseService = void 0;
const egg_1 = require("egg");
const typeorm_1 = require("typeorm");
const error_1 = require("../../lib/error");
const object_1 = require("../../lib/object");
const string_1 = require("../../lib/string");
/**
* Service基类:
* - 提供通用的基本业务处理方法
*/
class BaseService extends egg_1.Service {
constructor(_ctx) {
super(_ctx);
this.modelName = this.constructor.name.substring(0, this.constructor.name.length - 7);
// this.entity = require('../entity/' + this.modelName);
// this.entityClass = this.entity[this.modelName];
this.model = this.ctx.repo[this.modelName];
// TODO: 提示
this.repo = this.ctx.repo;
this.HTTP_CODE = error_1.HTTP_CODE;
this.BIZ_CODE = error_1.BIZ_CODE;
this.BizError = (message, code) => {
if (process.env.NODE_ENV === 'development') {
message = `${this.constructor.name} error:` + message;
}
throw new error_1.BizError(message, code);
};
// @see https://typeorm.biunav.com/zh/find-options.html#进阶选项
this.OPR = {
'!=': typeorm_1.Not,
'<': typeorm_1.LessThan,
'<=': typeorm_1.LessThanOrEqual,
'>': typeorm_1.MoreThan,
'>=': typeorm_1.MoreThanOrEqual,
'=': typeorm_1.Equal,
'<>': typeorm_1.Between,
'not in': (val) => typeorm_1.Not(typeorm_1.In(val)),
'!<>': (val, val2) => typeorm_1.Not(typeorm_1.Between(val, val2)),
'not between': (val, val2) => typeorm_1.Not(typeorm_1.Between(val, val2)),
not: typeorm_1.Not,
lessThan: typeorm_1.LessThan,
lessThanOrEqual: typeorm_1.LessThanOrEqual,
moreThan: typeorm_1.MoreThan,
moreThanOrEqual: typeorm_1.MoreThanOrEqual,
equal: typeorm_1.Equal,
between: typeorm_1.Between,
in: typeorm_1.In,
any: typeorm_1.Any,
isNull: typeorm_1.IsNull,
iLike: typeorm_1.ILike,
like: typeorm_1.Like,
raw: typeorm_1.Raw,
};
this.FIND_OPTIONS_KEYS = [
'select',
'where',
'relations',
'join',
'order',
'cache',
'lock',
'withDeleted',
'loadRelationIds',
'loadEagerRelations',
'transaction',
'take',
'skip',
// AntD 参数,需转换成 order
'sort',
];
}
/**
* Utils API
*/
/**
* 唯一性校验
* - 必须使用 await 调用
* - 支持排除当前 id
* - 至少一个属性不为空才判断重复
* @param params 校验参数对象
* @param message 提示信息(不传则使用默认值)
*/
async checkUnique(params, message) {
const id = this.getAndDelete(params, 'id');
// 判断查询条件
if (!object_1.isEmptyObject(params)) {
// 查询重复数据
const existedOne = await this.getOne(params);
if (!!existedOne && id !== existedOne.id) {
throw this.BizError((!message ? '请确认存在相同的数据.' : message));
}
}
}
/**
* Executes raw SQL query and returns raw database results
* - !!禁止直接在 SQL 中拼接用户传入的参数,以避免 SQL 注入
* @param sql script
* @param params params
* @param runner params
*/
async query(sql, params, runner) {
// return this.ctx.connection.manager.query(sql, params);
return await this.ctx.connection.query(sql, params, runner);
}
/**
* Base API
* - Default api, should overwrite if need.
* - Others use repo, model or manager to implement.
*
* FindOperatorType
* @see https://typeorm.biunav.com/zh/find-options.html#进阶选项
*/
async save(entity, options) {
// save<T extends DeepPartial<Entity>>(entity: T, options?: SaveOptions): Promise<T & Entity>;
const data = await this.model.save(entity, options);
return {
data,
success: !!data && string_1.isValid(data.id),
};
}
async get(id, options) {
// 避免获取不可预知的数据
if (!string_1.isValid(id)) {
return null;
}
return await this.model.findOne(id, options);
}
async getOne(params, options) {
if (!!options) {
// findOne(conditions?: FindConditions<Entity>, options?: FindOneOptions<Entity>): Promise<Entity | undefined>;
return await this.model.findOne(this.getWhere(params), options);
}
// findOne(options?: FindOneOptions<Entity>): Promise<Entity | undefined>;
return await this.model.findOne(Object.assign({
// 转换条件
where: this.getWhere(params),
// 转换排序
order: this.getOrders(params) }, this.getOptions(params)));
}
async getListByIds(ids, options) {
return await this.model.findByIds(ids, options);
}
/**
* Find with pagination and condition.
* - cant use findAndCount for both params
* - use createQueryBuilder
* @param params 参数
* @param params.current 页码
* @param params.pageSize 页面条数
* @param params.sort 排序
* @param dataFunc 数据处理函数
*/
async getPage(params, dataFunc) {
const current = this.getAndDelete(params, 'current', 1);
const pageSize = this.getAndDelete(params, 'pageSize', 10);
// 查询分页
// findAndCount(options?: FindManyOptions<Entity>): Promise<[Entity[], number]>;
const [data, total] = await this.model.findAndCount(Object.assign({
// 页面分页参数
take: pageSize, skip: (current - 1) * pageSize,
// 转换条件
where: this.getWhere(params),
// 转换排序
order: this.getOrders(params) }, this.getOptions(params)));
// 数据处理
if (dataFunc) {
await dataFunc(data);
}
return {
// Optional
totalPage: Math.ceil(total / pageSize),
current,
pageSize,
// Required
total,
data,
// AntD table required
success: true,
};
}
/**
* Update with id only (not use criteria).
* @param params param
* @param params.id primary key
* @param params.partialEntity new data
*/
async updateMix(params) {
const id = this.getAndDelete(params, 'id');
return await this.update(id, params);
}
async update(criteria, partialEntity) {
return this.addSuccessFlag(await this.model.update(criteria, partialEntity));
}
async delete(criteria) {
return this.addSuccessFlag(await this.model.delete(criteria));
}
async saveList(entities, options) {
const data = await this.model.save(entities, options);
return {
data,
success: !!data && data.length > 0,
};
}
/**
* 查询列表
* @param params 参数
* @param dataFunc 数据处理函数
* @returns
*/
async getList(params, dataFunc) {
const listRes = await this.model.find(Object.assign({
// 转换条件
where: this.getWhere(params),
// 转换排序
order: this.getOrders(params) }, this.getOptions(params)));
// 数据处理
if (dataFunc) {
await dataFunc(listRes);
}
return listRes;
}
/**
* Update with ids only (not use criteria).
* @param params param
* @param params.id primary key
* @param params.partialEntity new data
*/
async updateListMix(params) {
const ids = this.getAndDelete(params, 'ids');
return await this.updateList(ids, params);
}
async updateList(criteria, partialEntity) {
return this.addSuccessFlag(await this.model.update(criteria, partialEntity));
}
async deleteList(criteria) {
return this.addSuccessFlag(await this.model.delete(criteria));
}
/**
* Utils function.
*/
/**
* 转换 Find*Options
* @param params 查询条件
* @returns
*/
getOptions(params) {
const options = {};
!!params && Object.keys(params).forEach(k => {
if (this.FIND_OPTIONS_KEYS.indexOf(k.trim()) !== -1 && ['where', 'order', 'sort'].indexOf(k.trim()) === -1) {
options[k] = params[k];
}
});
return options;
}
/**
* 转换条件
* @param params 查询条件
* @returns
*/
getWhere(params) {
let where = this.getAndDelete(params, 'where');
let otherCondition = params;
// 合并 where 条件
where = this.combineParams(where, otherCondition);
// 处理 where 条件
const newWhere = {};
!!where && Object.keys(where).forEach(k => {
// 排除 findOptions 的关键字
if (this.FIND_OPTIONS_KEYS.indexOf(k.trim()) === -1) {
const type = Object.prototype.toString.call(where[k]);
if (!string_1.isValid(where[k])) {
// 剔除空属性
delete where[k];
}
else if (type === '[object Array]') {
newWhere[k] = typeorm_1.In(where[k]);
}
else if (type === '[object Object]' && !!where[k].opr) {
const opr = where[k].opr.trim();
const val = where[k].val;
if ((opr.indexOf('<>') !== -1 || opr.indexOf('between') !== -1) && val.length >= 2) {
newWhere[k] = this.OPR[opr](val[0], val[1]);
}
else if (opr === 'like' || opr === 'iLike') {
newWhere[k] = this.OPR[opr]((val.indexOf('%') === -1 ? `%${val}%` : val));
}
else if (opr.startsWith('not')) {
newWhere[k] = typeorm_1.Not(this.OPR[opr.replace('not', '').trim()](val));
}
else {
newWhere[k] = this.OPR[opr](val);
}
}
else {
newWhere[k] = where[k];
}
}
});
return newWhere;
}
/**
* 转换排序条件
* - 合并 order 和 sort(AntD 默认)参数
* @param params
* @returns
*/
getOrders(params) {
let order = this.getAndDelete(params, 'order');
const sort = this.getAndDelete(params, 'sort');
// 合并排序参数
order = this.combineParams(order, sort);
// 处理排序参数
const newOrder = {};
!!order && Object.keys(order).forEach(k => {
// 转换(直接支持 ant design table 排序参数)
if (!!order[k]) {
newOrder[k.trim()] = order[k].trim().toUpperCase().replace('ASCEND', 'ASC').replace('DESCEND', 'DESC');
}
});
return newOrder;
}
// 合并参数
combineParams(first, second) {
if (!second) {
return first;
}
if (!first) {
return second;
}
else {
return Object.assign(Object.assign({}, first), second);
}
}
/**
* deal mix params
* @param params 参数
*/
getAndDelete(params, label, defaultValue) {
if (!params || !string_1.isValid(params[label])) {
return defaultValue;
}
const value = params[label];
delete params[label];
return value;
}
/**
* 增加额外标志
* - 默认只判断 update or delete
* @param res 响应
* @returns
*/
addSuccessFlag(res) {
// affected: undefined, null, 0
let success = true;
if (!res || !res.affected) {
success = false;
}
return Object.assign(Object.assign({}, res), { success });
}
}
exports.BaseService = BaseService;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImJhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkJBQXVDO0FBQ3ZDLHFDQXlCaUI7QUFDakIsMkNBQWdFO0FBQ2hFLDZDQUFpRDtBQUNqRCw2Q0FBMkM7QUF1QjNDOzs7R0FHRztBQUNILE1BQU0sV0FBMEMsU0FBUSxhQUFPO0lBdUI3RCxZQUFZLElBQWE7UUFDdkIsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ1osSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztRQUN0Rix3REFBd0Q7UUFDeEQsa0RBQWtEO1FBQ2xELElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzNDLFdBQVc7UUFDWCxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO1FBQzFCLElBQUksQ0FBQyxTQUFTLEdBQUcsaUJBQVMsQ0FBQztRQUMzQixJQUFJLENBQUMsUUFBUSxHQUFHLGdCQUFRLENBQUM7UUFDekIsSUFBSSxDQUFDLFFBQVEsR0FBRyxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsRUFBRTtZQUNoQyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLGFBQWEsRUFBRTtnQkFDMUMsT0FBTyxHQUFHLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLFNBQVMsR0FBRyxPQUFPLENBQUM7YUFDdkQ7WUFDRCxNQUFNLElBQUksZ0JBQVEsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDcEMsQ0FBQyxDQUFDO1FBQ0YsNERBQTREO1FBQzVELElBQUksQ0FBQyxH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