mm_os
Version:
MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。
1,259 lines (1,186 loc) • 33.6 kB
JavaScript
const Item = require('mm_machine').Drive;
const Excel = require('mm_excel');
/**
* Sql操作驱动类
* @augments {Item}
* @class
*/
class Drive extends Item {
static config = {
'main': '',
// 表名 {0} 代表可前端传参自定义查询的表
'table': '{0}',
// 主键 用于水平连表查询时 例如:id
'key': '',
// 排序 {0} 代表可前台传参自定义排序规则 格式: `name` asc, `id` desc
'orderby': '{0}',
// 默认排序 `id` desc
'orderby_default': '',
// 显示的字段 {0} 代表可前台传参自定义查询的字段, 例如: `id`,`username`,`name`,`email`
'field': '{0}',
// 默认显示字段 例如: `id`,`username`,`name`
'field_default': '*',
// 隐藏字段 有些字段即使前端请求也不能返回,这是通过隐藏字段将其过滤掉, 例如:password *表示包含匹配
'field_hide': ['*password*', '*token*', 'salt'],
// 分页大小,默认一页显示条数
'page_size': 30,
/* 过滤参数 */
'filter': {
/**
* 表名
*/
'table': 'table',
/**
* 查询的页码
*/
'page': 'page',
/**
* 查询每页条数
*/
'size': 'size',
/**
* 操作方式: 传入参数method=add, 支持参数 add增、del删、set改、get查,为空则为get
*/
'method': 'method',
/**
* 排序
*/
'orderby': 'orderby',
/**
* 查询显示的字段
*/
'field': 'field',
/**
* 统计结果: 统计符合条件的结果数,只有当page等于1或0时才会统计
*/
'count_ret': 'count_ret'
},
// 分隔符 用于查询时的多条件处理
'separator': '|',
// 支持的方法 add增、del删、set改、get查, 只填get表示只支持查询 // import export del_repeat",
'method': 'add del set get get_obj import export del_repeat avg sum count update',
// sql查询语句
'query': {},
// 默认查询, 当查询条件中不包含该项时,默认添加该项。 例如: { "age": "`age` < 20" } , 当查询参含有age,不调用该项,不存在时,sql会增加该项
'query_default': {},
// sql更改语句
'update': {},
// 默认添加条件,当不包含该项时,默认添加该项。 例如: { "age": "`age` += 1" } , 当查询参含有age,不调用该项,不存在时,sql会增加该项
'body_default': {},
// 参数 []
'params': null,
// 格式
'format': [
/* {
// 表名,当选择转换方式 表转换时需填写
"table": "mm_web_region",
// 查询条件,用于加速转换
"query": {
"group": "市"
},
// 表标题名
"title": "所属省份",
// 转换ID
"id": "province_id",
// 转换主键
"key": "province",
// 取名
"name": "name",
// 列表
"list": [{
"province_id": 1,
"name": "广东省"
},
{
"province_id": 2,
"name": "广西省"
},
{
"province_id": 3,
"name": "湖南省"
}
]
},
{
"title": "是否可见",
"key": "show",
"list": ["否", "是"]
} */
],
/* 去重 */
'del_repeat': {
// 判断重复的字段,例如字段名 number
'groupBy': '',
// 排序方式 例如: `diJia` ASC
'orderBy': ''
},
/* 逻辑符 */
'logic': {},
// 输出sql语句
'log': false
};
/**
* 构造函数
* @param {object} config 配置参数
* @param {object} parent 父对象
* @class
*/
constructor(config, parent) {
super({ ...Drive.config, ...config }, parent);
// 默认启用热更新
this.mode = 3;
}
}
/**
* 获取模板目录
* @returns {string} 模板目录
*/
Drive.prototype._getTplDir = function () {
return __dirname;
};
/**
* 预设
*/
Drive.prototype._preset = function () {
// 保存文件目录
this.save_dir = './static/file/';
// 读取文件目录
this.url_path = '/file/';
/* 通用项 */
this.params = null;
};
/**
* 执行前, 可用于过滤参数
* @param {object} params 参数对象 (object) 包含query和body 如{ query, body }
* @param {object} db 数据库管理器
* @returns {object} 过滤后的参数
*/
Drive.prototype.before = async function (params, db) {
return params;
};
/**
* 验证, 用于判断是否执行
* @param {object} params 参数对象 (object) 包含query和body
* @param {object} db 数据管理器
* @returns {boolean} 验证通过返回true, 失败返回false
*/
Drive.prototype.check = async function (params, db) {
return true;
};
/**
* 执行后, 可用于附加执行
* @param {object} params 参数对象 (object) 包含query和body
* @param {object} db 数据管理器
* @returns {object} 最终执行结果
*/
Drive.prototype.after = async function (params, db) {
return db.ret;
};
/**
* 更新缓存
* @param {string} table 表名
* @param {object} sql 缓存sql语句
*/
Drive.prototype.updateCache = async function (table, sql) {
};
/**
* @ 执行修改
* @param {object} query 查询url参数
* @param {object} body 修改时置入body的参数
* @param {object} db 数据库管理器
* @returns {object} 返回执行结果
*/
Drive.prototype.run = async function (query, body, db) {
var params = {
query,
body
};
params = await this.before(params, db);
if (this.check(params, db)) {
var ret = await this.main(params, db);
if (!ret.error) {
db.ret = ret;
return await this.after(params, db);
} else {
return ret;
}
}
return null;
};
/**
* SQL操作准备
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回准备参数
*/
Drive.prototype.ready = function (db, query, body) {
var cg = this.config;
var qy = { ...query };
$.push(db.config.filter, cg.filter, true);
db.filter(qy);
return {
cg,
qy
};
};
/**
* 转为查询条件字符串
* @param {object} db 数据库管理器
* @param {object} query 查寻条件
* @param {object} method 方法
* @returns {string} 返回查询条件
*/
Drive.prototype.toWhere = function (db, query, method) {
var { cg, qy: originalQy } = this.ready(db, query, {});
// 创建 qy 对象的副本,避免修改原始参数
var qy = { ...originalQy };
this._setDbConfig(db, cg, query);
qy = this._setQueryField(db, query, cg, method, qy);
qy = this._setOrderBy(db, query, cg, qy);
return this._buildQueryString(db, qy, cg);
};
/**
* 设置数据库配置
* @param {object} db 数据库管理器
* @param {object} cg 配置
* @param {object} query 查询条件
* @private
*/
Drive.prototype._setDbConfig = function (db, cg, query) {
db.config.separator = cg.separator;
if (!query.size && cg.page_size) {
db.size = cg.page_size + 0;
}
if (db.size > 0 && db.page === 0) {
db.page = 1;
}
};
/**
* 设置查询字段
* @param {object} db 数据库管理器
* @param {object} query 查询条件
* @param {object} cg 配置
* @param {object} method 方法
* @param {object} qy 查询条件对象
* @returns {object} 更新后的查询条件对象
* @private
*/
Drive.prototype._setQueryField = function (db, query, cg, method, qy) {
var f = db.config.filter;
var field = query[f.field];
if (cg.field.has('*{0}*')) {
if (field) {
db.field = cg.field.replace('{0}', field);
} else if (method === 'get_obj' && cg.field_obj) {
db.field = cg.field_obj + '';
} else if (cg.field_default) {
db.field = cg.field_default + '';
}
} else {
db.field = cg.field + '';
if (field) {
return { ...qy, [f.field]: field };
}
}
return qy;
};
/**
* 设置排序方式
* @param {object} db 数据库管理器
* @param {object} query 查询条件
* @param {object} cg 配置
* @param {object} qy 查询条件对象
* @returns {object} 更新后的查询条件对象
* @private
*/
Drive.prototype._setOrderBy = function (db, query, cg, qy) {
var f = db.config.filter;
var orderby = query[f.orderby];
if (cg.orderby.has('*{0}*')) {
if (orderby) {
db.orderby = cg.orderby.replace('{0}', orderby);
} else if (cg.orderby_default) {
db.orderby = cg.orderby_default + '';
}
} else {
db.orderby = cg.orderby + '';
if (orderby) {
return { ...qy, [f.orderby]: orderby };
}
}
return qy;
};
/**
* 构建查询字符串
* @param {object} db 数据库管理器
* @param {object} qy 查询条件对象
* @param {object} cg 配置
* @returns {string} 查询字符串
* @private
*/
Drive.prototype._buildQueryString = function (db, qy, cg) {
var query_str = db.tplQuery(qy, cg.query);
var qt = cg.query_default;
if (Object.keys(qt).length > 0) {
var id = $.dict.user_id;
var id_key = '{' + id + '}';
var user_id = '0';
var user = db.user;
if (user && user[id]) {
user_id = user[id];
}
for (var k in qt) {
if (!qy[k]) {
query_str += ' && ' + qt[k].replaceAll(id_key, user_id);
}
}
if (query_str.startsWith(' && ')) {
query_str = query_str.replace(' && ', '');
}
}
return query_str;
};
/**
* 查询(主要)
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} method 方法
* @returns {object} 返回查询结果
*/
Drive.prototype.getMain = async function (db, query, method) {
var ret;
if (this.config.field.has('*{0}*')) {
var field = query[db.config.filter.field];
if (field && this.config.field_hide.getMatch(field)) {
return $.ret.error(70003, '不合法的查询参数');
}
}
var query_str = this.toWhere(db, query, method);
// 查询
if (db.count_ret === 'true') {
ret = $.ret.body(await db.getCountSql(query_str, db.orderby, db.field));
} else {
ret = $.ret.list(await db.getSql(query_str, db.orderby, db.field));
}
return ret;
};
/**
* 查询
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回查询结果
*/
Drive.prototype.get = async function (db, query, body) {
return await this.getMain(db, query);
};
/**
* 查询单条数据
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回查询结果
*/
Drive.prototype.getObj = async function (db, query, body) {
var qy = { ...query };
qy.page = 1;
qy.size = 1;
var ret = await this.getMain(db, qy, 'get_obj');
if (ret.result) {
var list = ret.result.list;
if (list.length > 0) {
return $.ret.obj(list[0]);
} else {
return $.ret.obj(null);
}
}
return ret;
};
/**
* 修改(主要)
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回修改结果
*/
Drive.prototype.setMain = async function (db, query, body) {
var ret;
var {
cg,
qy
} = this.ready(db, query, body);
var key = cg.key;
if (body[key]) {
qy[key] = body[key];
}
var query_str = db.tplQuery(qy, cg.query);
var qt = cg.query_default;
if (Object.keys(qt).length > 0) {
var id = $.dict.user_id;
var id_key = '{' + id + '}';
var user_id = '0';
var user = db.user;
if (user && user[id]) {
user_id = user[id];
}
for (var k in qt) {
if (!qy[k]) {
query_str += ' && ' + qt[k].replace(id_key, user_id);
}
}
if (query_str.startsWith(' && ')) {
query_str = query_str.replace(' && ', '');
}
}
var n = await db.setSql(query_str, db.tplBody(body, cg.update));
if (n < 1) {
ret = $.ret.error(500, '修改失败!\n' + db.error.message);
} else {
ret = $.ret.bl(true, '修改成功!');
}
return ret;
};
/**
* 修改
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回查询结果
*/
Drive.prototype.set = async function (db, query, body) {
return await this.setMain(db, query, body);
};
/**
* 添加(主要)
* @param {object} db 数据库操作类
* @param {object} body 添加项
* @returns {object} 返回查询结果
*/
Drive.prototype.addMain = async function (db, body) {
var ret;
var cg = this.config;
if (Object.keys(body).length > 0) {
var bt = cg.body_default;
if (Object.keys(bt).length > 0) {
var id = $.dict.user_id;
var id_key = '{' + id + '}';
var user_id = '0';
var user = db.user;
if (user && user[id]) {
user_id = user[id];
}
for (var k in bt) {
if (!body[k]) {
var str = bt[k].replace(id_key, user_id);
var key = str.left('=').trim('`');
body[key] = str.right('=').trim("'");
}
}
}
var n = await db.add(body);
if (n < 1) {
ret = $.ret.error(500, '添加失败!\n' + db.error.message);
} else {
ret = $.ret.bl(true, '添加成功!');
}
} else {
ret = $.ret.error(30001, '参数不能为空');
}
if (cg.log) {
this.log('debug', '添加SQL语句', db.sql);
}
return ret;
};
/**
* 添加
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回添加结果
*/
Drive.prototype.add = async function (db, query, body) {
return await this.addMain(db, body);
};
/**
* 删除(主要)
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @returns {object} 返回查询结果
*/
Drive.prototype.delMain = async function (db, query) {
var ret;
var {
cg,
qy
} = this.ready(db, query, {});
var query_str = db.tplQuery(qy, cg.query);
var bl = await db.delSql(query_str);
if (bl < 1) {
ret = $.ret.error(500, '删除失败!\n' + db.error.message);
} else {
ret = $.ret.bl(true, '删除成功!');
}
if (cg.log) {
this.log('debug', '删除SQL语句', db.sql);
}
return ret;
};
/**
* 删除
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回删除结果
*/
Drive.prototype.del = async function (db, query, body = {}) {
return await this.delMain(db, { ...query, ...body });
};
/**
* 添加或修改(主要)
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回修改结果
*/
Drive.prototype.addorsetMain = async function (db, query, body) {
var ret;
var {
cg,
qy
} = this.ready(db, query, body);
if (Object.keys(body).length > 0 && Object.keys(qy).length > 0) {
var n = await db.addOrSet(qy, body);
if (n < 1) {
ret = $.ret.error(500, '操作失败!\n' + db.error.message);
} else {
ret = $.ret.bl(true, '操作成功!');
}
} else {
ret = $.ret.error(30001, '参数不能为空');
}
if (cg.log) {
this.log('debug', '添加或修改SQL语句', db.sql);
}
return ret;
};
/**
* 添加或修改
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回查询结果
*/
Drive.prototype.addOrSet = async function (db, query, body) {
return await this.addOrSetMain(db, query, body);
};
/**
* 获取数据类型
* @param {string} data_type 数据类型
* @returns {string} 返回数据类型
*/
Drive.prototype.getType = function (data_type) {
if (data_type.indexOf('int') !== -1) {
return 'number';
} else {
return 'string';
}
};
/**
* 获取数据
* @param {object} db 数据库操作类
* @param {string} field 要获取的字段
* @returns {Array} 返回参数信息列表
*/
Drive.prototype.getParam = async function (db, field) {
var cg = this.config;
if (cg.params) {
return cg.params;
}
if (this.params) {
return this.params;
}
var lt = await this._getFieldsFromCache(cg);
if (!lt.length) {
lt = await this._getFieldsFromDb(db, cg);
}
return this._filterFields(lt, field, cg);
};
/**
* 从缓存获取字段列表
* @param {object} cg 配置
* @returns {Array} 字段列表
* @private
*/
Drive.prototype._getFieldsFromCache = function (cg) {
var lt = [];
if ($.pool.db) {
var pool = $.pool.db['sys'];
if (pool) {
var dt = pool.get(cg.table);
if (dt && dt.config) {
var list = dt.config.fields;
for (var i = 0; i < list.length; i++) {
var name = list[i].replace(/`/g, '');
lt.push({ name, title: name });
}
}
}
}
return lt;
};
/**
* 从数据库获取字段列表
* @param {object} db 数据库操作类
* @param {object} cg 配置
* @returns {Array} 字段列表
* @private
*/
Drive.prototype._getFieldsFromDb = async function (db, cg) {
var lt = [];
db.table = cg.table;
var list = await db.fields();
for (var i = 0; i < list.length; i++) {
var o = list[i];
var name = o.name;
var note = o.note ? o.note.replace(':', ':') : name;
lt.push({
name,
title: note.left(':', true),
type: this.getType(o.type)
});
}
return lt;
};
/**
* 过滤字段
* @param {Array} lt 字段列表
* @param {string} field 字段筛选
* @param {object} cg 配置
* @returns {Array} 过滤后的字段列表
* @private
*/
Drive.prototype._filterFields = function (lt, field, cg) {
var fields = field || cg.field_default;
if (fields && fields !== '*') {
var arr = fields.replace(/`/g, '').split(',');
return arr.map(name => lt.getObj({ name })).filter(obj => obj);
}
return lt;
};
/**
* 获取导入导出格式
* @param {object} db 数据库操作类
* @returns {Array} 格式列表
*/
Drive.prototype.getFormat = async function (db) {
var dbs = { ...db };
dbs.size = 0;
var fmt = this.config.format;
for (var i = 0; i < fmt.length; i++) {
var o = fmt[i];
if (o.table) {
if (!o.list || o.list.length == 0) {
dbs.table = o.table;
if (!o.id) {
o.id = o.key;
}
o.list = await dbs.getSql(o.where, null, o.id + ',' + o.name);
if (o.id !== o.key) {
for (var j = 0; j < o.list.length; j++) {
var m = o.list[j];
m[o.key] = m[o.name];
}
}
}
}
}
return fmt;
};
/**
* 导入数据(主要)
* @param {object} db 数据库操作类
* @param {string} filename 文件名
* @returns {object} 返回导入结果
*/
Drive.prototype.importMain = async function (db, filename) {
var params = await this.getParam(db);
var format = await this.getFormat(db);
var file = this._processFilePath(filename);
if (!file.hasFile()) {
return $.ret.error(30001, file + '文件不存在!');
}
var jarr = await this._loadImport(file, params, format);
if (!jarr || !jarr.length) {
return $.ret.error(10000, '要导入的数据不能为空!');
}
var result = await this._importToDb(db, jarr);
return this._buildImport(result);
};
/**
* 处理文件路径
* @param {string} filename 文件名
* @returns {string} 处理后的文件路径
* @private
*/
Drive.prototype._processFilePath = function (filename) {
var file = filename;
if (file.indexOf($.run_path) !== 0) {
file = file.replace(this.url_path, this.save_dir);
var path = this._getPath();
file = file.fullname(path);
}
return file;
};
/**
* 加载导入数据
* @param {string} file 文件路径
* @param {Array} params 参数列表
* @param {Array} format 格式列表
* @returns {Array} 数据数组
* @private
*/
Drive.prototype._loadImport = async function (file, params, format) {
if (file.ends('.json')) {
return file.loadJson();
} else if (file.ends('.xml')) {
return file.loadXml();
} else {
var excel = new Excel({ file, params, format });
try {
return await excel.load();
} catch (e) {
this.log('error', '导入文件', e);
} finally {
excel.clear();
excel = null;
}
}
return [];
};
/**
* 导入数据到数据库
* @param {object} db 数据库操作类
* @param {Array} jarr 数据数组
* @returns {object} 导入结果
* @private
*/
Drive.prototype._importToDb = async function (db, jarr) {
var list = [];
var errors = [];
var list_error = [];
db.table = db.table || this.config.table;
var key = this.config.key;
if (jarr[0][key]) {
for (var i = 0; i < jarr.length; i++) {
var o = jarr[i];
var qy = {};
qy[key] = o[key];
var n = await db.addOrSet(qy, o);
if (n < 1) {
errors.push(db.error);
list_error.push(o);
} else {
list.push(o);
}
}
} else {
for (var i = 0; i < jarr.length; i++) {
var o = jarr[i];
var n = await db.add(o);
if (n < 1) {
errors.push(db.error);
list_error.push(o);
} else {
list.push(o);
}
}
}
return { list, errors, list_error, total: jarr.length };
};
/**
* 构建导入结果
* @param {object} result 导入结果数据
* @returns {object} 返回结果对象
* @private
*/
Drive.prototype._buildImport = function (result) {
var bl = result.list.length === result.total;
var body = $.ret.bl(bl, bl ? '导入成功!' : '导入失败!');
body.result.list = result.list;
if (result.errors.length) {
body.result.list_error = result.list_error;
body.result.errors = result.errors;
}
return body;
};
/**
* 导入数据
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 导入设置
* @returns {object} 返回执行结果
*/
Drive.prototype.import = async function (db, query, body) {
var params = { ...query, ...body };
if (!params.file) {
return $.ret.error(60000, '文件名(file)参数不能为空');
}
return await this.importMain(db, params.file);
};
/**
* 导出数据(主要)
* @param {object} db 数据库操作类
* @param {object} query 查询参数
* @param {object} body 正文参数(导出设置)
* @property {string} body.fields 需要导出的字段 例如: `username`,`gm`,`vip`
* @property {string} body.file 文件名 例如: 用户名.xlsx 、用户信息.csv 、用户账户.xls
* @property {string} body.path 文件路径 例如: /static/download, 可不填写
* @returns {object} 返回执行结果
*/
Drive.prototype.exportMain = async function (db, query, body) {
var by = await this.getMain(db, query);
if (db.error) {
return $.ret.error(10000, db.error.message);
}
var config = this._prepareExportConfig(query, body);
var params = await this.getParam(db, config.fields);
var format = await this.getFormat(db);
var file = await this._saveExportFile(config.file, params, format, by.result.list);
return this._buildExport(file, config.name);
};
/**
* 准备导出配置
* @param {object} query 查询参数
* @param {object} body 正文参数
* @returns {object} 导出配置
* @private
*/
Drive.prototype._prepareExportConfig = function (query, body) {
var path = body.path;
var file = body.file;
var fields = body.fields;
var table = $.dict.table || this.config.table;
if (!path) {
path = this._getPath();
}
if (!file) {
var date = new Date();
file = this.save_dir + table + '_' + date.stamp() + '.xlsx';
}
if (!fields) {
fields = query.field || (this.config.field_default !== '*' ? this.config.field_default : '');
}
return { path, file, fields, name: file.split('/').pop() };
};
/**
* 获取路径
* @returns {string} 导出路径
* @private
*/
Drive.prototype._getPath = function () {
return $.config.get('user_path') || $.config.get('static_path') || './static/';
};
/**
* 保存导出文件
* @param {string} file 文件路径
* @param {Array} params 参数列表
* @param {Array} format 格式列表
* @param {Array} list 数据列表
* @returns {string} 保存后的文件路径
* @private
*/
Drive.prototype._saveExportFile = async function (file, params, format, list) {
var export_path = this._getPath();
var save_file = file.fullname(export_path);
save_file.addDir();
var excel = new Excel({ file: save_file, params, format });
try {
return await excel.save(list);
} catch (e) {
this.log('error', '导出保存文件失败!', e);
} finally {
excel.clear();
excel = null;
}
return '';
};
/**
* 构建导出结果
* @param {string} file 文件路径
* @param {string} name 文件名
* @returns {object} 导出结果
* @private
*/
Drive.prototype._buildExport = function (file, name) {
var body = $.ret.bl(!!file, file ? '导出成功!' : '导出失败!');
body.result.file = file;
body.result.url = this.url_path + name;
return body;
};
/**
* 导出数据
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回执行结果
*/
Drive.prototype.export = async function (db, query, body) {
return await this.exportMain(db, query, body);
};
/**
* 删除重复项(主要)
* @param {object} db 数据库管理器
* @param {object} params 查询参数
* @returns {object} 返回执行结果
*/
Drive.prototype.delRepeatMain = async function (db, params) {
var pm = { ...params };
var msg = '';
var cg = this.config.del_repeat;
var order_by = pm.orderby || cg.orderBy;
delete pm.orderby;
var group_by = pm.groupby || cg.groupBy;
delete pm.groupby;
var f = db.config.filter;
// 设置查询字段
var field = pm[f.field] || group_by;
delete pm[f.field];
db.field = field;
var sql = db.toGetSql(pm).replace(' * ', ' `' + field + '`, count(*) as len ');
sql += ` GROUP BY ${group_by}`;
sql = 'SELECT * FROM (' + sql + ') a WHERE len > 1';
var list = await db.run(sql);
if (list.length) {
db.page = 1;
db.size = 1;
var key = this.config.key;
for (var i = 0; i < list.length; i++) {
var o = list[i];
var len = o.len - 1;
delete o.len;
for (var n = 0; n < len; n++) {
var obj = await db.getObj(o, order_by, key);
if (obj) {
await db.del(obj);
}
}
}
} else {
msg = '没有重复项。';
}
return $.ret.bl(!msg, msg ? '去重失败!原因:' + msg : '去重成功!');
};
/**
* 删除重复项
* @param {object} db 数据库管理器
* @param {object} query 查询条件
* @param {object} body 正文参数
* @returns {object} 返回执行结果
*/
Drive.prototype.delRepeat = async function (db, query, body) {
var pm = { ...query, ...body };
return await this.delRepeatMain(db, pm);
};
/**
* 执行模板操作
* @param {object} params 参数对象 (object) 包含query和body
* @param {object} db 数据管理器
* @returns {object} 返回执行结果
*/
Drive.prototype.main = async function (params, db) {
var {
query,
body
} = params;
var cg = this.config;
var method = query.method;
if (!method) {
method = 'get';
}
if (!cg.method.has('*' + method + '*')) {
return $.ret.error(50001, '不支持的操作方式');
}
method = this._getMethodName(method);
var qy = { ...query };
delete qy.method;
if (this[method]) {
db.method = method;
// 过滤查询参数
var f = cg.filter;
var table = query[f.table];
// 设置操作的数据表
if (cg.table.has('*{0}*')) {
if (table) {
db.table = cg.table.replace('{0}', table);
} else {
return $.ret.error(30001, '表名不能为空');
}
} else {
db.table = cg.table + '';
}
return await this[method](db, qy, { ...body });
} else {
return $.ret.error(50001, '不支持的操作方式');
}
};
/**
* 获取方法名
* @param {string} method 方法名
* @returns {string} 方法名
* @private
*/
Drive.prototype._getMethodName = function (method) {
if (!method) {
return '';
}
if (method.indexOf('_') == -1) {
return method;
}
// 将小写蛇形改为小驼峰
let arr = method.split('_');
let new_name = arr[0].toLowerCase();
for (let i = 1; i < arr.length; i++) {
let name = arr[i];
new_name += name.charAt(0).toUpperCase() + name.substring(1);
}
return new_name;
};
/**
* 总计
* @param {object} db 数据库管理器
* @param {object} param 查询条件
* @returns {object} 返回执行结果
*/
Drive.prototype.sumMain = async function (db, param) {
var pm = { ...param };
var ret;
var orderby = pm.orderby || '';
delete pm.orderby;
var groupby = pm.groupby;
delete pm.groupby;
var f = db.config.filter;
var field = pm[f.field];
delete pm[f.field];
var query_str = this.toWhere(db, pm, 'get_list');
if (!groupby || !field) {
ret = $.ret.error(30000, '参数groupby、field是必须的,且值不能为空!');
} else {
var list = await db.groupSumSql(query_str, groupby, field, orderby);
if (!list.length && db.error) {
ret = $.ret.body(db.error);
} else {
ret = $.ret.list(list);
}
}
return ret;
};
/**
* 总计
* @param {object} db 数据库管理器
* @param {object} query 查询条件
* @param {object} body 正文参数
* @returns {object} 返回执行结果
*/
Drive.prototype.sum = async function (db, query, body) {
var pm = { ...query, ...body };
return await this.sumMain(db, pm);
};
/**
* 平均值
* @param {object} db 数据库管理器
* @param {object} param 查询条件
* @returns {object} 返回执行结果
*/
Drive.prototype.avgMain = async function (db, param) {
var pm = { ...param };
var ret;
var orderby = pm.orderby || '';
delete pm.orderby;
var groupby = pm.groupby;
delete pm.groupby;
var f = db.config.filter;
var field = pm[f.field];
delete pm[f.field];
var query_str = this.toWhere(db, pm, 'get_list');
if (!groupby || !field) {
ret = $.ret.error(30000, '参数groupby、field是必须的,且值不能为空!');
} else {
var list = await db.groupAvgSql(query_str, groupby, field, orderby);
if (!list.length && db.error) {
ret = $.ret.body(db.error);
} else {
ret = $.ret.list(list);
}
}
return ret;
};
/**
* 平均值
* @param {object} db 数据库管理器
* @param {object} query 查询条件
* @param {object} body 正文参数
* @returns {object} 返回执行结果
*/
Drive.prototype.avg = async function (db, query, body) {
var pm = { ...query, ...body };
return await this.avgMain(db, pm);
};
/**
* 总计
* @param {object} db 数据库管理器
* @param {object} param 查询条件
* @returns {object} 返回执行结果
*/
Drive.prototype.countMain = async function (db, param) {
var pm = { ...param };
var ret;
var orderby = pm.orderby || '';
delete pm.orderby;
var groupby = pm.groupby;
delete pm.groupby;
var f = db.config.filter;
var field = pm[f.field];
delete pm[f.field];
var query_str = this.toWhere(db, pm, 'get_list');
if (!groupby || !field) {
ret = $.ret.error(30000, '参数groupby、field是必须的,且值不能为空!');
} else {
var list = await db.groupCountSql(query_str, groupby, field, orderby);
if (!list.length && db.error) {
ret = $.ret.body(db.error);
} else {
ret = $.ret.list(list);
}
}
return ret;
};
/**
* 总计
* @param {object} db 数据库管理器
* @param {object} query 查询条件
* @param {object} body 正文参数
* @returns {object} 返回执行结果
*/
Drive.prototype.count = async function (db, query, body) {
var pm = { ...query, ...body };
return await this.countMain(db, pm);
};
/**
* 获取模型
* @param {string} type 模型类型
* @returns {object} 返回获取到的模型
*/
Drive.prototype.getModel = function (type) {
let model = { ...this.config };
let dir = this.getDir();
let l = $.slash;
let app_name = dir.between('app' + l, l);
let plugin_name = dir.between('plugin' + l, l);
let name = dir.basename();
model.app = app_name;
model.plugin = plugin_name;
model.name = model.name || app_name + '_' + name;
return model;
};
module.exports = Drive;