注册
专为达梦数据库写的一个nodejs后端仿sequelize简易ORM框架
培训园地/ 文章详情 /

专为达梦数据库写的一个nodejs后端仿sequelize简易ORM框架

丰云 2025/06/20 172 0 0

由于工作中经常要用到达梦数据库,而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框架目前还很简陋粗糙,但已经能满足现实开发工作中绝大部分数据服务的需求了。这里面还有很多功能有待继续开发,比如外键关联的设定、关联查询等等,后面有时间再添加了。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服