由于工作中经常要用到达梦数据库,而nodejs环境中一时间没有找一个兼容达梦数据库的ORM框架,于是模仿dequelize的工作模式,手写了一个达梦数据库专用的ORM框架。
直接上代码:
首先是封装的框架文件dmService.js:
/*
* 该例程封装了达梦数据库初始化连接、表结构同步、基础数据插入等功能,
* 并且封装了插入数据,批量插入,修改数据,删除数据,数据基本查询、分页查询等基本操作。
*/
var db = require("dmdb");
exports.dmService = (function () {
function DmdbServer() {
//#region 内部变量
var pool= null,
conn= null,
config= null,
tables= null;
//#endregion
//#region 内部方法
// 统一日志记录方法,便于做日志控制
var log= function (title, msg) {
if (this.config.showLog) {
console.log(title, msg || "");
}
};
// 判断是否是数字类型
var isNumber = function(value) {
return Object.prototype.toString.call(value) === '[object Number]';
};
var getConn= async function(cb){
try{
// 数据库连接池
pool = await db.createPool({
connectString: "dm://" + config.account + ":" + config.password + "@" + config.ip + ":" + config.port + "?autoCommit=false&loginEncrypt=false",
poolMax: config.pool.max,
poolMin: 1,
});
conn = await pool.getConnection();
cb && cb();
}catch(ex){
console.log('连接源数据库出错。');
}
};
// 将达梦数据库返回的数据集,转换为json数据集
var getDataList= function (result) {
var re = [];
if (result && result.rows && result.rows.length) {
var m = result.metaData;
result.rows.for((r) => {
var rc = {};
for (var i = 0; i < r.length; i++) {
rc[m[i].name] = r[i];
}
re.push(rc);
});
}
return re;
};
var getColumnSql= function(columns){
var sql = '';
if (columns && columns.length > 0) {
columns.for((column) => {
sql += '"' + column + '",';
});
sql = sql.vtrim(",");
} else {
sql += " * ";
}
return sql;
};
// 拼接where条件的节点
var getWhereNode= function (key, value, type) {
var th = this;
var sql = "";
var tp = type || " AND ";
if (key && value) {
if (key == "or") {
sql += " ( ";
var i = 0;
for (var ky in value) {
sql += th.getWhereNode(ky, value[ky], " OR ");
}
sql = sql.vtrim("OR ") + " ) ";
} else {
if (typeof value == "object") {
if ('like' in value) {
sql += ' "' + key + '" like';
sql += " '%" + value.like + "%'" + tp;
} else if ('in' in value) {
if(value.in.length > 0){
var vs = '';
value.in.for((v)=>{
vs += "'" + v + "',";
});
sql += '"' + key + '" in (' + vs.vtrim(',') + ")" + tp;
}
} else if ('gt' in value) {
sql += '"' + key + '" > ' + value.gt + tp;
} else if ('lt' in value) {
sql += '"' + key + '" < ' + value.lt + tp;
} else if ('gte' in value) {
sql += '"' + key + '" >= ' + value.gte + tp;
} else if ('lte' in value) {
sql += '"' + key + '" <= ' + value.lte + tp;
} else if ('is' in value) {
if(value.is == 'empty'){
sql += '"' + key + '" = \'\' ' + tp;
}
if(value.is == 'null'){
sql += '"' + key + '" is null ' + tp;
}
} else if ('isnot' in value) {
if(value.is == 'empty'){
sql += '"' + key + '" != \'\' ' + tp;
}
if(value.is == 'null'){
sql += '"' + key + '" is not null ' + tp;
}
} else if ('between' in value) {
sql += '"' + key + '" BETWEEN ' + value.between[0] + "AND " + value.between[1] + tp;
} else {
var v = th.isNumber(value.value) ? value.value : "'" + value.value + "'";
sql += '"' + key + '" ' + value.type + " " + v + tp;
}
} else {
var v = th.isNumber(value) ? value : "'" + value + "'";
sql += '"' + key + '" = ' + v + tp;
}
}
}
return sql;
};
// 拼接where条件
var getWhereSql= function (where) {
var th = this;
var sql = "";
if (where) {
if (typeof where == "string") {
sql += " WHERE " + where;
} else {
for (var key in where) {
sql += th.getWhereNode(key, where[key]);
}
if (sql != "") {
sql = " WHERE " + sql.vtrim("AND ");
}
}
}
return sql;
};
var getOrderSql= function(order){
var sql = '';
if (order) {
sql += " ORDER BY ";
for (var i = 0; i < order.length; i++) {
var od = order[i];
sql += '"' + od[0] + '" ' + (od.length > 1 ? od[1].toUpperCase() : "ASC") + ",";
}
sql = sql.vtrim(",");
}
return sql;
};
var getGroupSql= function(group){
var sql = '';
if (group) {
sql += " GROUP BY ";
for (var i = 0; i < group.length; i++) {
var gp = group[i];
sql += '"' + gp[0] + '" ' + ",";
}
sql = sql.vtrim(",");
}
return sql;
};
//#endregion
//#region 外部方法
// 初始化,包括建立数据库连接,同步表结构,插入基础数据等操作
this.init= async function (cfg, cb) {
var th = this;
config = cfg;
tables = config.tables;
await getConn(async ()=>{
if (cfg.asyncTable) {
for (var key in tables) {
if (key && tables[key]) {
var result = await conn.execute(`select COUNT(1) from user_objects where object_type='TABLE' AND OBJECT_NAME='` + key + `';`);
if (result.rows[0][0] == 0) {
console.log('create table ', key);
await th.createTable(
{ tbName: key, table: tables[key].columns },
async () => {
var dt = tables[key].baseData;
if (dt) {
console.log('bcp table basedata', key);
await th.bcp(
{
tbName: key,
list: dt.list,
update: dt.update
},
null
);
}
}
);
}
}
}
}
});
};
// 创建表
this.createTable= async function (cfg, cb) {
this.log( "开始创建表, tbName=" + cfg.tbName + ", struct=" + JSON.stringify(cfg.table));
var sql = 'CREATE TABLE "' + cfg.tbName + '" (';
var unique = {};
var foreignKey = [];
var primaryKey = [];
for (var key in cfg.table) {
var col = cfg.table[key];
sql += '"' + col.field + '" ' + col.type;
// if(col.autoIncrement){
// sql += ' AUTO_INCREMENT'
// }
sql += col.autoIncrement
? " NOT NULL,"
: col.primaryKey
? " NOT NULL,"
: col.allowNull || true
? " NULL,"
: " NOT NULL,";
if (col.primaryKey) {
primaryKey.push(col.field);
}
if (col.unique) {
unique[col.unique] = unique[col.unique] || [];
unique[col.unique].push(col.field);
}
if (col.relation) {
foreignKey.push([
col.field,
col.relation.table,
col.relation.field,
]);
}
}
if (primaryKey.length > 0) {
sql += "PRIMARY KEY (";
primaryKey.forEach((a) => {
sql += '"' + a + '",';
});
sql = sql.vtrim(",") + "),";
}
for (var key in unique) {
sql += "CONSTRAINT " + key + " UNIQUE (";
unique[key].forEach((a) => {
sql += '"' + a + '",';
});
sql = sql.vtrim(",") + "),";
}
foreignKey.for((a) => {
sql += 'FOREIGN KEY ("' + a[0] + '") REFERENCES "' + a[1] + '" ("' + a[2] + '") ON DELETE CASCADE ON UPDATE CASCADE,';
});
sql = sql.vtrim(",") + ");";
try {
await this.conn.execute(sql);
await this.conn.execute("commit;");
this.log("表【" + cfg.tbName + "】, struct:【" + sql + "】, 创建完成!");
cb && cb();
} catch (err) {
this.log("Sql:" + sql + ", 创建表出错:", err.message);
}
};
// 插入数据
this.insert= async function (cfg, res, cb) {
var th = this;
th.log("开始插入数据, tbName=" + cfg.tbName + ", params=" + JSON.stringify(cfg.params));
var sql = 'INSERT INTO "' + cfg.tbName + '" (';
var cols = "";
var vals = "";
for (var key in cfg.params) {
cols += '"' + key + '",';
var v = cfg.params[key];
v = th.isNumber(v) ? v : "'" + v + "'";
vals += v + ",";
}
cols = cols.slice(0, -1); // 移除最后一个逗号
vals = vals.slice(0, -1); // 移除最后一个逗号
sql += cols + ") VALUES(" + vals + ");";
try {
await th.conn.execute(sql, null);
await th.conn.execute("commit;");
this.log("Sql:" + sql + ", 插入数据结束!");
if (cb) {
cb();
} else {
res && res.json({
code: 200,
data: 1,
});
}
} catch (err) {
this.log("Sql:" + sql + ", 插入数据出错:", err.message);
res && res.json({
code: 100,
message: "系统异常,请联系管理员处理。",
});
}
};
//批量插入
this.bcp= async function (cfg, res, cb) {
if(!cfg.tbName || !cfg.list || cfg.list.length < 1){
if (cb) {
cb();
} else {
res && res.json({
code: 100,
message: '没有发现需要批量插入的数据',
});
}
return false;
}
var th = this;
var tb = th.tables[cfg.tbName].columns;
var duplicate = '';
if(cfg.udpate){
duplicate = ' ON DUPLICATE KEY UPDATE '
cfg.update.for(key=>{
duplicate += key + ' = '
});
}
th.log("开始批量插入数据, tbName=" + cfg.tbName + ", list=", cfg.list);
try {
var dt = cfg.list[0];
var sql = 'INSERT INTO "' + cfg.tbName + '" (';
for (var key in dt) {
sql += '"' + key + '",';
}
sql = sql.vtrim(",") + ") VALUES ";
cfg.list.for((a) => {
sql += "(";
for (var key in a) {
var v = a[key];
var c = tb[key];
if (c && (c.type == "int" || c.type == "INT" || c.type == "number" || c.type == "NUMBER")) {//这里还可以追加判断
sql += ((!v && v != 0) ? 'null' : v) + ",";
} else {
sql += "'" + v + "',";
}
}
sql = sql.vtrim(",") + ")";
if(cfg.udpate){
var dstr = '';
cfg.update.for(key=>{
var v = a[key];
var c = tb[key];
if(v){
if (c && (c.type == "int" || c.type == "INT" || c.type == "number" || c.type == "NUMBER")) {//这里还可以追加判断
dstr += key + ' = ' + v + ' AND ';
} else {
dstr += "'" + v + "' AND ";
}
}
});
if(dstr){
sql += ' ON DUPLICATE KEY UPDATE ' + dstr.vtrim(' AND ');
}
}
sql += ',';
});
th.log("批量插入数据, tbName=" + cfg.tbName + ", sql: ", sql);
//th.log("批量插入数据, data:", pms)
await th.conn.execute(sql.vtrim(","));
await th.conn.execute("commit;");
th.log(cfg.tbName + "批量插入数据结束!");
if (cb) {
cb();
} else {
res && res.json({
code: 200,
data: 1,
});
}
} catch (err) {
th.log(cfg.tbName + "批量插入数据出错:", err.message);
res && res.json({
code: 100,
message: "系统异常,请联系管理员处理。",
});
}
};
//修改
this.update= async function (cfg, res, cb) {
var th = this;
th.log("开始修改数据, tbName=" + cfg.tbName + ", params=" + JSON.stringify(cfg.params) + ", where=" + JSON.stringify(cfg.where));
var sql = 'UPDATE "' + cfg.tbName + '" SET ';
var pms = "";
for (var key in cfg.params) {
var v = cfg.params[key];
v = th.isNumber(v) ? v : "'" + v + "'";
pms += '"' + key + '" = ' + v + ",";
}
pms = pms.vtrim(",");
sql += pms + th.getWhereSql(cfg.where);
sql += ";";
try {
await th.conn.execute(sql, pms);
await th.conn.execute("commit;");
th.log("Sql:" + sql + ", 更新数据结束!");
if (cb) {
cb(true);
} else {
res && res.json({
code: 200,
data: 1,
});
}
return true;
} catch (err) {
res && res.json({
code: 100,
message: "系统异常,请联系管理员处理。",
});
th.log("Sql:" + sql + ", 更新数据出错:", err.message);
}
};
//删除
this.delete= async function (cfg, res, cb) {
var th = this;
th.log("开始删除数据, tbName=" + cfg.tbName + ", params=" + JSON.stringify(cfg.params));
var sql = 'DELETE FROM "' + cfg.tbName + '" ';
sql += th.getWhereSql(cfg.where);
sql += ";";
try {
await th.conn.execute(sql);
await th.conn.execute("commit;");
th.log("Sql:" + sql + ", 删除数据结束!");
if (cb) {
cb(true);
} else {
res && res.json({
code: 200,
data: 1,
});
}
return true;
} catch (err) {
res && res.json({
code: 100,
message: "系统异常,请联系管理员处理。",
});
th.log("Sql:" + sql + ", 删除数据出错:", err.message);
}
};
// 获取全表数据
this.getTableData= async function (tableName) {
var th = this;
var sql = "select * from “" + tableName + "”;";
var result = await th.conn.execute(sql);
return th.getDataList(result);
};
//查询数据集
this.excuteSql= async function (sql, params, res, cb) {
var th = this;
try {
var result = await this.conn.execute(sql, params);
//this.log('result:', result);
var re = th.getDataList(result);
//this.log('data:', re);
this.log("Sql:" + sql + ", 查询数据结束!");
if (cb) {
cb(re);
} else {
res && res.json({
code: 200,
data: re,
});
}
return re;
} catch (err) {
res && res.json({
code: 100,
message: "系统异常,请联系管理员处理。",
});
this.log("Sql:" + sql + ", 查询数据出错:", err.message);
return null;
}
};
//查询数据集
this.queryBySql= async function (sql, res, cb) {
this.excuteSql(sql, {}, res, cb);
};
//查询数据集
this.query= async function (cfg, res, cb) {
var th = this;
this.log("query开始查询数据, tbName=" + cfg.tbName + ", columns=" + JSON.stringify(cfg.columns) + ", where=" + JSON.stringify(cfg.where) + ", order=" + JSON.stringify(cfg.order));
var pms = [];
var sql = "SELECT ";
sql += cfg.distinct ? 'DISTINCT ' : '';
sql += th.getColumnSql(cfg.columns);
sql += ' FROM "' + cfg.tbName + '" ';
sql += th.getWhereSql(cfg.where);
sql += th.getGroupSql(cfg.group);
sql += th.getOrderSql(cfg.order);
if(cfg.limit){
sql += ' LIMIT ' + cfg.limit + ';';
}
this.excuteSql(sql, pms, res, cb);
};
//查询分页数据
this.queryPage= async function (cfg, res, cb) {
var th = this;
var pIndex = parseInt(cfg.pageIndex || 1, 10);
var pSize = parseInt(cfg.pageSize || 10, 10);
this.log("queryPage开始查询数据, tbName=" + cfg.tbName + ", columns=" + JSON.stringify(cfg.columns) + ", where=" + JSON.stringify(cfg.where) + ", order=" + JSON.stringify(cfg.order));
var pms = [];
var csql = "SELECT count(1) as total ";
var sql = "SELECT ";
sql += th.getColumnSql(cfg.columns);
csql += ' FROM "' + cfg.tbName + '"';
sql += ' FROM "' + cfg.tbName + '"';
var wsql = th.getWhereSql(cfg.where);
csql += wsql;
sql += wsql;
sql += th.getOrderSql(cfg.order);
sql += " OFFSET " + (pIndex - 1) * pSize + " LIMIT " + pSize;
try {
var total = await th.conn.execute(csql, pms);
var result = await th.conn.execute(sql, pms);
var list = th.getDataList(result);
this.log("csql:" + csql + ", 查询数据结束!");
var re = {
count: total.rows[0][0],
rows: list,
};
if (cb) {
cb(re);
} else {
res && res.json({
code: 200,
data: re,
});
}
return re;
} catch (err) {
res && res.json({
code: 100,
message: "系统异常,请联系管理员处理。",
});
th.log("Sql:" + sql + ", 查询数据出错:", err.message);
}
};
//查询单条数据
this.queryOne= async function (cfg, res, cb) {
var th = this;
th.log("queryOne开始查询数据, tbName=" + cfg.tbName + ", columns=" + JSON.stringify(cfg.columns) + ", where=" + JSON.stringify(cfg.where) + ", order=" + JSON.stringify(cfg.order));
var pms = [];
var sql = "SELECT ";
sql += th.getColumnSql(cfg.columns);
sql += ' FROM "' + cfg.tbName + '"';
sql += th.getWhereSql(cfg.where);
sql += th.getOrderSql(cfg.order);
try {
var result = await th.conn.execute(sql, pms);
var list = th.getDataList(result);
th.log("Sql:" + sql + ", 查询数据结束!");
if (cb) {
cb(list[0]);
} else {
res && res.json({
code: 200,
data: list[0],
});
}
return list[0];
} catch (err) {
res && res.json({
code: 100,
message: "系统异常,请联系管理员处理。",
});
th.log("Sql:" + sql + ", 查询数据出错:", err.message);
}
};
//外部表数据同步
this.asyncData= async function (obj, cfg) {
var th = this;
th.log((new Date()).format('yyyy-MM-dd HH:mm:ss.S') + ": " + cfg.destTbName + "表同步数据开始!");
obj.conn.execute('SELECT * FROM "' + obj.account + '"."' + cfg.srcTbName + '"', null, (err, result)=>{
if(err){
cfg.isErr = 1;
console.log(err);
}else{
var srcDatas = th.getDataList(result);
th.log((new Date()).format('yyyy-MM-dd HH:mm:ss.S') + ": 查找源表" + cfg.srcTbName + "数据共计" + srcDatas.length + "条!");
var lst = [];
th.query({ tbName: cfg.destTbName }, null, (destDatas)=>{
th.log((new Date()).format('yyyy-MM-dd HH:mm:ss.S') + ": 查找目标表" + cfg.destTbName + "数据共计" + destDatas.length + "条!");
srcDatas.for((u)=>{
var filters = destDatas.filter(m =>{
return m[cfg.relation.destKey] == u[cfg.relation.srcKey]
});
if(filters.length > 0){
dt = filters[0];
var params = {};
var isUpdate = false;
var wh = {};
wh[cfg.relation.destKey] = u[cfg.relation.srcKey];
cfg.updateCols.for(col=>{
if(u[col.srcCol] && u[col.srcCol] != 'undefined' && dt[col.destCol] != u[col.srcCol]){
params[col.destCol] = col.defaultValue ? (col.defaultValue == 'UUID' ? obj.tools.getUUID() : col.defaultValue) : u[col.srcCol];
isUpdate = true;
}
});
if(isUpdate){
th.update({
tbName: cfg.destTbName,
params: params,
where: wh
})
}
}else{
dt = {};
cfg.insertCols.for(col=>{
if(u[col.srcCol] && u[col.srcCol] != 'undefined'){
dt[col.destCol] = col.defaultValue ? (col.defaultValue == 'UUID' ? obj.tools.getUUID() : col.defaultValue) : u[col.srcCol];
}
});
lst.push(dt);
}
});
if(lst.length > 0){
th.log((new Date()).format('yyyy-MM-dd HH:mm:ss.S') + ": 目标表" + cfg.destTbName + "不存在,需要新插入的数据共计" + lst.length + "条!");
th.bcp({
tbName: cfg.destTbName,
list: lst
})
}
th.log((new Date()).format('yyyy-MM-dd HH:mm:ss.S') + ': ' + cfg.destTbName + '表同步数据结束!');
});
}
});
};
//#endregion
};
return new DmdbServer();
})();
接下来是项目配置文件中, 关于达梦数据库的一些配置项:
module.exports = {
/*
项目其他配置
*/
// 达梦数据库相关配置
dm8: {
type: "dm8",
ip: "localhost",
port: 5236,
account: "dbAccount",
password: "dbAccountPwd",
pool: {
max: 100,
idle: 30000,
acquire: 60000,
},
showLog: true,
asyncTable: true, // 是否同步建表并插入基础数据
asyncDBConfig:{ // 同步外部数据的配置
type: "dm8",
ip: "192.168.10.8",
port: 5236,
account: "srcDbAccount",
password: "srcDbAccountPwd",
pool: {
max: 100,
idle: 30000,
acquire: 60000,
},
isRun: false,
syncDuration: 30*60, //同步间隔时长,单位:秒
// 需要同步的数据表以及源表和目标表之间的映射关系
tables:[
{
srcTbName: 'users',
destTbName: 'user',
relation: { // 源表和目标表之间的关联字段
srckey: 'account',
destKey: 'account'
},
// 如果该记录在目标表里存在,则需要更新的字段
updateCols: [
{srcCol: 'uname', destCol: 'name', defaultValue: ''},
{srcCol: 'pass', destCol: 'password', defaultValue: ''},
{srcCol: 'e_mail', destCol: 'email', defaultValue: ''},
{srcCol: 'mobile', destCol: 'phone', defaultValue: ''},
{srcCol: 'post_name', destCol: 'duty', defaultValue: ''}
],
// 如果该记录在目标表里不存在,则需要插入的字段
insertCols: [
{srcCol: 'id', destCol: 'id', defaultValue: ''},
{srcCol: 'account', destCol: 'account'},
{srcCol: 'uname', destCol: 'name', defaultValue: ''},
{srcCol: 'pass', destCol: 'password', defaultValue: ''},
{srcCol: 'e_mail', destCol: 'email', defaultValue: ''},
{srcCol: 'mobile', destCol: 'phone', defaultValue: ''},
{srcCol: 'post_name', destCol: 'duty', defaultValue: ''}
]
}
]
},
// 数据库业务表的定义以及必须的基础数据
// 这里还可以进一步拓展外键关系的定义等等
tables: {
// 用户信息
user: {
columns: {
id: {
primaryKey: true,
type: "NVARCHAR(36)",
allowNull: false,
field: "id"
},
type: {
// 管理员、主管、员工...
type: "NVARCHAR(50)",
field: "type"
},
code: {
// 员工编码
type: "NVARCHAR(50)",
field: "code"
},
name: {
type: "NVARCHAR(50)",
field: "name"
},
nickname: {
type: "NVARCHAR(50)",
field: "nickname"
},
signature: { // 签名
type: "NVARCHAR(500)",
field: "signature"
},
gender: {
type: "NVARCHAR(50)",
field: "gender"
},
duty: { // 职务
type: "NVARCHAR(50)",
field: "duty"
},
title: { // 职称
type: "NVARCHAR(50)",
field: "title"
},
phone: {
type: "NVARCHAR(50)",
field: "phone"
},
IDCard: {
type: "NVARCHAR(50)",
field: "IDCard"
},
email: {
type: "NVARCHAR(50)",
field: "email"
},
wechart: {
type: "NVARCHAR(50)",
field: "wechart"
},
address: {
type: "NVARCHAR(500)",
field: "address"
},
avatar: {
//化身、头像,专指网络头像、个人形象
type: "NVARCHAR(500)",
field: "avatar"
},
account: {
type: "NVARCHAR(50)",
field: "account"
},
password: {
type: "NVARCHAR(100)",
field: "password"
},
status: {
//状态: 0:新建,1:正常,2:禁用
type: "INT",
field: "status"
}
},
baseData: { // 基础数据
update: ["id"],
list: [{
id: 1,
code: "P00001",
type: "管理员",
name: "管理员",
account: "admin",
password: "123456",
status: 1
}]
}
},
// 角色信息
role: {
columns: {
id: {
primaryKey: true,
type: "NVARCHAR(36)",
allowNull: false,
field: "id"
},
idx: {
type: "INT",
field: "idx"
},
code: {//admin:管理员, user: 用户, guest: 来宾。。。
type: "NVARCHAR(50)",
field: "code"
},
name: {
type: "NVARCHAR(50)",
field: "name"
},
type: {// base:基础角色,不能删除,不能修改,other:其他角色,可修改,可删除。
type: "NVARCHAR(50)",
field: "type"
},
description: {
type: "NVARCHAR(50)",
field: "description"
}
},
baseData: { // 基础数据
update: ["id"],
list: [
{
id: 1,
idx: 1,
code: 'admin',
name: "管理员",
type: "base",
description: "超级管理员,拥有系统前端和后端的全部权限,请勿随意更改",
},
{
id: 2,
idx: 2,
code: "user",
name: "用户",
type: "base",
description: "系统用户,拥有系统前端大部分功能的增删改查权限",
},
{
id: 3,
idx: 3,
code: "guest",
name: "来宾",
type: "base",
description: "系统外部访问人员,只开放最低级别权限,可以无需登录,即可查看系统前端首页、系统介绍等页面",
},
]
},
},
// 用户信角色映射表
userRoleMap: {
columns: {
roleID: {
type: "NVARCHAR(36)",
field: "roleID"
},
userID: {
type: "NVARCHAR(36)",
field: "userID"
}
}
}
}
}
};
然后就是调用举例了:
// 以下是项目入口初始化的方法
var cfg = require('config');
var dmService = require('dmService').dmService;
dmService.init(cfg.dm8, ()=>{
console.log('dm service init successfully!');
var acfg = cfg.dm8.asyncDBConfig;
if(acfg.isRun){
dmService.getConn(acfg, (conn)=>{
acfg.conn = conn;
setInterval(() => {
conn.excute('select 1;');
acfg.tables.for(tb=>{
if(!tb.isErr){
console.log('async table ' + tb.destTbName + ' start.');
dmService.asyncData(acfg, tb);
}
});
}, acfg.asyncDuration * 1000);
});
}
});
下面是webapi调用的示例
const express = require("express");
const Router = express.Router();
Router.post('/list', (req, res) => {
var pSize = req.body.pageSize || 10;
var pIndex = req.body.pageIndex || 1;
var param = {}
if (!!req.body.name) {
param = {
name: { like: req.body.name }
};
}
if (!!req.body.keywords) {
param = {
or: {
name: { like: req.body.keywords },
dept: { like: req.body.keywords }
},
};
}
req.db.queryPage({
tbName: 'role',
pageIndex: pIndex * 1,
pageSize: pSize * 1,
where: param,
order: [['id']]
}, res, (roles)=>{
var roleIDs = roles.rows.map((r)=>{
return r.id;
});
req.db.query({
tbName: 'userRoleMap',
where: { roleID: { in: roleIDs} }
}, res, (userRoles)=>{
roles.rows.for(role=>{
role.userIDs = [];
userRoles.for(ur=>{
if(ur.roleID == role.id){
role.userIDs.push(ur.userID);
}
});
});
res.json({
code: 200,
data: roles
});
});
});
})
Router.post("/save", async (req, res) => {
var { id, name, description, seq, menuIDs } = req.body;
if (!id) {
id = req.tools.getUUID();
req.db.insert({
tbName: 'role',
params: { id, name, description, seq } // 确保seq被插入
}, res);
} else {
req.db.update({
tbName: 'role',
params: { seq, name, description },
where: { id }
}, res);
}
});
Router.post('/delete', (req, res) => {
req.db.delete({tbName: 'role', where: {id: req.body.id}}, res, ()=>{
req.db.delete({
tbName: 'userRoleMap',
where: {roleID: req.body.id}
}, res);
});
})
module.exports = Router;
这个ORM框架目前还很简陋粗糙,但已经能满足现实开发工作中绝大部分数据服务的需求了。这里面还有很多功能有待继续开发,比如外键关联的设定、关联查询等等,后面有时间再添加了。
文章
阅读量
获赞