UNPKG

gcl

Version:

码农村nodejs类库,完成解决回调陷阱,配置框架,IOC框架,统一多DB访问框架,可扩展日志框架和io/db/net/thread/pool 克隆表达式,加解密算法等等一系列基础类库和算法的实现

1,600 lines (1,584 loc) 164 kB
import V from "../common/tool"; import C from "../io/config"; import { Pool } from "../collection/pool"; import M from "mysql2"; import M2 from "mssql"; import Mem from "memcached"; import Mon from "mongodb"; import N from "../net/tool"; import Q from "querystring"; import Mail from "emailjs"; import es from "@elastic/elasticsearch"; import Redis from "ioredis"; import pg from "pg"; import { createClient } from "soap"; const pri = V.pris(); //import nosql from './nosql'; /** * //依托Middler框架完成对数据类型文件的处理,包括mysql mongodb sqlserver memcache ObjectDB(即自定义function) WebSocket等等数据源类型的操作 //实现对如下格式文件的处理 Ni:{ ajaxtest2:{command:'http://localhost/VESHTest/Module/help/test.tjsonp?_n=recorder',dbtype:'tjson',params:{limit:11},template:'template1'}, ajaxtest1:{command:'http://localhost/KDAPI/Module/GetOrderTrackItems.tjsonp?_n=Order',dbtype:'tjson',params:{},template:'template1'}, 'ajaxtest1.Cache':{command:function(res,params){return res[params.cacheKey];不写即使用默认值},dbtype:'json',params:{},template:'template2'}, 'ajaxtest1.Set':{command:function(res,params){res[params.cacheKey] = params.cacheValue;不写即使用默认值},dbtype:'json',params:{timeout1:{interval:'s',number:50}},template:'template2'}, sqlinsert:{command:'create table if not exists table(name Text,message text,time integer);insert into table values(?,?,?);',dbtype:'json',params:{data:[]},template:'sqltemp'}, sqlselect:{command:'select * from table;',dbtype:'json',params:{data:[]},template:'sqltemp'}, sqlselect2:{command:'select * from table where name=?',dbtype:'json',params:{data:[]},template:'sqltemp'}, Name1:{command:'',params:{},dbtype:'json/tjson',template:'仅在Middler中调用NiMultiTemplateDecorator时启用'}, wstest1: { command: 'abc.json', dbtype: 'json', params: {}, template: 'ws' }, wstest2: { command: 'bcd.json?_n=MT, dbtype: 'json', params: {}, template: 'ws' } } let t = middler.getObjectByAppName('Ni','templatename'); let res = t.execute('aaa.GetProductDetail',{ProductID:111},function(result){ let res = result.last(); }); middler.setObjectByAppName('Ni','templatename',t); //分离NiDataConfig完成Ni格式文件处理 //分离NiDataConfigConvert完成对Ni格式转成Config //用于处理 Ni文件定义 */ export const NiDataConfig = class extends C.Config { constructor() { super(); const that = this; const { _, __ } = pri(that, { mergeValue: (param) => { switch (param.type) { case "Int": case "int": case "int32": case "int16": case "int64": param.value = param.value ? parseInt(param.value) : 0; break; case "DateTime": case "Date": case "datetime": param.value = param.value ? param.value.split ? Date.parse(param.value) : new Date(param.value) : new Date(0); break; case "float": case "single": case "double": param.value = param.value ? parseFloat(param.value) : 0; break; case "string": case "String": param.value = param.value == null ? null : param.value + ""; break; } }, }); } standard(val) { let ret = {}; for (let k in val) { let v = val[k] || { value: val[k], isStandard: true, }; ret[k] = v.isStandard ? v : v.type || (v.out && v.out != "") ? (function () { v.isStandard = true; return v; })() : { value: v, isStandard: true, }; } return ret; } merge(...vals) { const { _, __ } = pri(this); //默认设置最后一个参数为值,其它参数为标准化数据 key:{value:val,type:'',out:false,isStandard:true} vals.forEach((v, i) => (vals[i] = _.standard(v))); vals = V.merge.apply(null, vals); for (let k in vals) __.mergeValue(vals[k]); return vals; } getValue(...args) { const { _, __ } = pri(this); const ret = super.getValue.apply(_, args); //这里借用VJ的方法将ni.js中定义的V.merge方法改为参数标准化方法 if (ret) { ret.merge = ret.merge || function (...args2) { return _.merge.apply(_, args2); }; } return ret; } }; NiDataConfig.instance = new NiDataConfig(); export const NiDataConfigConvert = class extends C.ConfigConvert { constructor() { super(); pri(this); } toConfig(val) { const ret = new NiDataConfig(); if (val) { if (typeof val == "object") { for (let k in val) { let v = val[k]; if (v) ret.data[k.toLowerCase()] = V.merge( { params: {}, }, v, ); } } } return ret; } }; export const NiTemplate = class { constructor(res, cm) { const that = this; this.transaction = false; const { _, __ } = pri(that, { lstCmd: [], KEY: "Ni", result: new NiDataResult(), res, cm, addCommand: (name, params) => { const { _, __ } = pri(that); const cmd = __.cm.getConfigValue(__.KEY, name.toLowerCase().trim()); let command = name; let template = ""; if (cmd) { command = cmd.command || name; params = cmd.merge(cmd.params, V.getValue(params, {})); template = cmd.template; } else params = NiDataConfig.instance.merge({}, params); __.lstCmd.push({ name: command, params: params, oriparams: cmd ? cmd.params : params, //备份 template: template, key: name, jsonp: cmd && cmd.jsonp ? cmd.jsonp : false, dbtype: cmd && cmd.dbtype ? cmd.dbtype : "tjson", }); }, execute: async () => { const { _, __ } = pri(that); let _cms = __.lstCmd; __.lstCmd = []; if (_cms.length > 0) { let conn = await __.res.getDBConnection(); try { if (_cms.length > 1) conn.transaction = true; let cmd = __.res.getDBCommand(); cmd.connection = conn; //执行过程存在严重漏洞 考虑 直接执行与非直接执行的异同 await V.each( _cms, async (v) => { cmd.command = v.name; cmd.params = v.params; cmd.oriparams = v.oriparams; cmd.dbtype = v.dbtype; cmd.jsonp = v.jsonp; //需要知晓connection的执行原理 if (conn.transaction) { cmd.execute(); } else { const data = await cmd.execute(); __.result.add( !data || (V.isArray(data) && data.length == 0) ? false : data, v.key, ); } return false; }, true, ); if (conn.transaction && conn.commit) await conn.commit(); return true; } catch (err) { V.showException("commit ", err); throw err; } finally { __.res.backDBConnection(conn); } } else { V.showException("不能调用空的命令对象!"); } }, excute: async () => await __.execute(), }); } async execute(name, params = {}) { const { _, __ } = pri(this); //__.addCommand(name, V.json(V.toJsonString(params))); //__.addCommand(name, V.merge({},params)); __.addCommand(name, params); if (!_.transaction) { __.result.clear(); await __.execute(); } return __.result; } async excute() { return await this.execute.apply(this, arguments); } async commit() { const { _, __ } = pri(this); __.result.clear(); await __.execute(); return __.result; } dispose() { const { _, __ } = pri(); for (let i in __) { //if (__[i].dispose) try { __[i].dispose() } catch (e) {} delete __[i]; } } getCommand(name = "") { const { __ } = pri(this); return V.merge({}, __.cm.getConfigValue(__.KEY, name.toLowerCase()) || {}); } }; export const NiTemplateManager = class { constructor(middler, appName = "Ni") { pri(this, { middler: middler, KEY: appName, }); } async execute(tempName, name, params, func) { const { _, __ } = pri(this); let temp = __.middler.getObjectByAppName(__.KEY, tempName); if (temp) { let result = await temp.execute(name, params); __.middler.setObjectByAppName(__.KEY, tempName, temp); return result; } else { throw new Error("没有找到Template:" + tempName); } } async excute() { return await this.execute.apply(this, arguments); } dispose() { const { __ } = pri(this); for (let i in __) delete __.i; } getCommand(tempName = "", name = "") { const { _, __ } = pri(this); let temp = __.middler.getObjectByAppName(__.KEY, tempName); if (temp) { let result = temp.getCommand(name); __.middler.setObjectByAppName(__.KEY, tempName, temp); return result; } else { throw new Error("没有找到Template:" + tempName); } } }; function hasData(data) { if (V.isArray(data)) { for (let i = 0; i < data.length; i++) { if (data[i] && hasData(data[i])) return true; } } else { for (let i in data) if (data[i] !== undefined) return true; } return false; } export const NiDataResult = class { constructor() { const { __ } = pri(this, { data: {}, kv: {}, datas: [], hasData: hasData, }); } get(key) { const { _, __ } = pri(this); return __.data[key] || (__.kv[key] ? __.kv[key][1] : null); } add(data, name) { const { _, __ } = pri(this); if (data && !__.kv[name]) { __.data[__.datas.length] = data; __.kv[name] = [__.datas.length, data]; __.datas.push(data); } else if (__.kv[name]) { const id = __.kv[name][0]; __.data[id] = data; __.kv[name] = [__.datas.length, data]; __.datas[id] = data; } } last() { const { _, __ } = pri(this); return _.get(__.datas.length - 1); } /** * 一般用于处理单个对象 */ single(allowNull = false) { const { _, __ } = pri(this); return _.hasData() ? (function () { const data = _.get(__.datas.length - 1); return data[0] && data[0][0] ? data[0][0] : allowNull ? null : {}; })() : null; } each(key, func) { const { _, __ } = pri(this); let val = _.get(key); if (val && V.isArray(val)) { return V.each(val, func); } else throw new Error("遍历对象不存在或者不是数组"); } clear() { const { _, __ } = pri(this); __.data = {}; __.kv = {}; __.datas = []; } hasData(key) { const { _, __ } = pri(this); return __.hasData(key ? get(key) : __.datas); } }; /** * getDBConnection 异步 */ export const NiDataResource = class { constructor(factory, params = {}) { const { _, __ } = pri(this, { fac: factory, params: params, }); } async getDBConnection() { const { _, __ } = pri(this); const conn = __.fac.createDBConnection(); conn.setParams(__.params); //conn.params = V.merge(conn.params, __.params); if (!conn.isOpen) { //open需要转同步 await conn.open(); } return conn; } backDBConnection(conn) { const { _, __ } = pri(this); __.fac.backDBConnection(conn); } getDBCommand() { const { _, __ } = pri(this); return __.fac.createDBCommand(); } }; export const NiInstanceDataResource = class extends NiDataResource { constructor(factory, params = {}) { super(factory, params); } getDBConnection() { return super.getDBConnection(); } backDBConnection(conn) { super.backDBConnection(conn); } getDBCommand() { return super.getDBCommand(); } }; export const NiStaticDataResource = class extends NiDataResource { constructor(factory, params = {}) { super(factory, params); pri(this, { conn: null, }); } async getDBConnection() { const { _, __ } = pri(this); if (!__.conn || !__.conn.isOpen) __.conn = await super.getDBConnection(); return __.conn; } backDBConnection(conn) { const { _, __ } = pri(this); if (conn != __.conn && conn.isOpen) super.backDBConnection(conn); } getDBCommand() { return super.getDBCommand(); } }; export const NiPoolDataResource = class extends NiDataResource { constructor(factory, params = {}, size = 50) { super(factory, params); pri(this, { pool: new Pool(size, async () => { let conn = await super.getDBConnection(); if (!conn.dispose) conn.dispose = conn.close; return conn; }), }); } async getDBConnection() { const { _, __ } = pri(this); return await __.pool.getValue(); } backDBConnection(conn) { const { _, __ } = pri(this); __.pool.setValue(conn); } }; export const NiDataFactory = class { constructor() { pri(this); } createDBConnection() { return new NiDataConnection(); } createDBCommand() { return new NiDataCommand(); } async backDBConnection(conn) { if (conn.isOpen) { await conn.close(); } } }; /** * Connection 全部是callback */ export const NiDataConnection = class { constructor() { pri(this); this.isOpen = false; this.transaction = false; this.params = {}; } setParams(paras) { V.merge(this.params, paras, true); } async open() { const { _, __ } = pri(this); _.isOpen = true; } async close() { const { _, __ } = pri(this); _.isOpen = false; } async invoke(cmd) { return []; } async commit() { return []; } }; /** * DBCommand 命令使用callback命令 */ export const NiDataCommand = class { constructor() { const { _, __ } = pri(this); _.connection = null; _.command = ""; _.params = { dbtype: "json", }; } async execute() { const { _, __ } = pri(this); if (!_.connection || !_.connection.isOpen) { V.showException("数据库未连接"); throw new Error("数据库未连接"); } else { try { //此句关键 return await _.connection.invoke(_); } catch (e) { V.showException("connection invoke success方法", e); throw e; } } } async excute() { return await this.execute.apply(this, arguments); } }; /** * 可以针对每个函数分别设置缓存方式和缓存字段 * @param {*} res * @param {*} cacheres * @param {*} cm * @param {*} params */ export const NiTemplateDecorator = class extends NiTemplate { constructor(res, cacheres, cm, params = {}) { super(res, cm); const that = this; const { _, __ } = pri(that, { KEY: "Ni", lstCmd2: {}, params, cacheres, }); const _addCommand = __.addCommand; const _execute = __.execute; __.addCommand = (name, params) => { const { _, __ } = pri(that); let index = __.lstCmd.length; _addCommand.apply(_, [name, params]); if (__.lstCmd.length != index) { let command = null; let cmd = __.cm.getConfigValue(__.KEY, name.toLowerCase() + ".cache") || __.cm.getConfigValue(__.KEY, name.toLowerCase() + ".clear"); if (cmd) { command = cmd.command; __.lstCmd2[index] = { name: command, key: name, params: cmd.merge( { cacheKey: "" + V.hash( name + ".Set." + V.toJsonString(__.lstCmd[__.lstCmd.length - 1].params), ), }, cmd.params, __.lstCmd[__.lstCmd.length - 1].params, ), oriparams: cmd.params, }; } } }; __.execute = async () => { const { _, __ } = pri(that); let _cms = __.lstCmd; __.lstCmd = []; if (_cms.length > 0) { let conn = await __.res.getDBConnection(); try { if (_cms.length > 1) conn.transaction = true; let cmd = __.res.getDBCommand(); cmd.connection = conn; //执行过程存在严重漏洞 考虑 直接执行与非直接执行的异同 let i = 0; await V.each( _cms, async (v) => { const _nicmd = __.lstCmd2[i++]; if (_nicmd) { const _conn = await __.cacheres.getDBConnection(); try { const _cmd = __.cacheres.getDBCommand(); _cmd.connection = _conn; _cmd.command = _nicmd.name; _cmd.params = V.merge(_nicmd.params, v.params); _cmd.oriparams = _nicmd.oriparams; _cmd.dbtype = v.dbtype; _cmd.jsonp = v.jsonp; let data = await _cmd.execute(); if (hasData(data)) { __.result.add( !data || (V.isArray(data) && data.length == 0) ? false : V.json( data[0].cacheValue || (data[0][0] && data[0][0].cacheValue), ), v.key, ); return false; } } finally { __.cacheres.backDBConnection(_conn); } } cmd.command = v.name; cmd.params = v.params; cmd.oriparams = v.oriparams; cmd.dbtype = v.dbtype; cmd.jsonp = v.jsonp; //需要知晓connection的执行原理 if (conn.transaction) { cmd.execute(); } else { let data = await cmd.execute(); __.result.add( !data || (V.isArray(data) && data.length == 0) ? false : data, v.key, ); if ( data && data.length > 0 && !(data.length == 1 && data[0].length == 0) ) { //新增缓存 let _nicmd = __.cm.getConfigValue( __.KEY, v.key.toLowerCase() + ".set", ); if (_nicmd) { const _conn = await __.cacheres.getDBConnection(); try { const _cmd = __.cacheres.getDBCommand(); _cmd.connection = _conn; _cmd.command = _nicmd.command; _cmd.params = _nicmd.merge( { cacheKey: "" + V.hash( v.key + ".Set." + V.toJsonString(cmd.params), ), cacheValue: V.toJsonString(data), }, _nicmd.params, cmd.params, ); _cmd.oriparams = _nicmd.oriparams; _cmd.dbtype = v.dbtype; _cmd.jsonp = v.jsonp; const _data = await _cmd.execute(); } finally { __.cacheres.backDBConnection(_conn); } } } } return false; }, true, ); if (conn.transaction && conn.commit) await conn.commit(); return __.result; } catch (err) { V.showException("commit ", err); } finally { __.res.backDBConnection(conn); } } else { V.showException("不能调用空的命令对象!"); } }; __.excute = async () => await __.execute(); } }; /** * 可以非常简单的设置缓存方式 但是存储命令只有cacheKey,cacheValue两种 * @param {*} res * @param {*} cacheres * @param {*} cm * @param {*} params * @param {*} cachecommand //缓存命令 * @param {*} setcommand //缓存设置命令 */ export const NiTemplateCacheDecorator = class extends NiTemplate { constructor( res, cacheres, cm, params = {}, cachecommand = "", setcommand = "", ) { super(res, cm); const that = this; const { _, __ } = pri(that, { KEY: "Ni", lstCmd2: {}, params, cacheres, cachecommand: cachecommand.toLowerCase(), setcommand: setcommand.toLowerCase(), }); const _addCommand = __.addCommand; const _execute = __.execute; __.addCommand = (name, params) => { const { _, __ } = pri(that); let index = __.lstCmd.length; _addCommand.apply(_, [name, params]); if (__.lstCmd.length != index) { let command = null; let cmd = __.cm.getConfigValue(__.KEY, __.cachecommand); if (cmd) { command = cmd.command; __.lstCmd2[index] = { name: command, key: name, params: cmd.merge( { cacheKey: "" + V.hash( name + ".Set." + V.toJsonString(__.lstCmd[__.lstCmd.length - 1].params), ), }, cmd.params, __.lstCmd[__.lstCmd.length - 1].params, ), }; } } }; __.execute = async () => { const { _, __ } = pri(that); let _cms = __.lstCmd; __.lstCmd = []; if (_cms.length > 0) { let conn = await __.res.getDBConnection(); try { if (_cms.length > 1) conn.transaction = true; let cmd = __.res.getDBCommand(); cmd.connection = conn; //执行过程存在严重漏洞 考虑 直接执行与非直接执行的异同 let i = 0; await V.each( _cms, async (v) => { const _nicmd = __.lstCmd2[i++]; if (_nicmd) { const _conn = await __.cacheres.getDBConnection(); try { const _cmd = __.cacheres.getDBCommand(); _cmd.connection = _conn; _cmd.command = _nicmd.name; _cmd.params = V.merge(_nicmd.params, v.params); _cmd.dbtype = v.dbtype; _cmd.jsonp = v.jsonp; let data = await _cmd.execute(); if (hasData(data)) { __.result.add( !data || (V.isArray(data) && data.length == 0) ? false : V.json( data[0].cacheValue || (data[0][0] && data[0][0].cacheValue), ), v.key, ); return false; } } finally { __.cacheres.backDBConnection(_conn); } } cmd.command = v.name; cmd.params = v.params; cmd.dbtype = v.dbtype; cmd.jsonp = v.jsonp; //需要知晓connection的执行原理 if (conn.transaction) { cmd.execute(); } else { let data = await cmd.execute(); __.result.add( !data || (V.isArray(data) && data.length == 0) ? false : data, v.key, ); if ( data && data.length > 0 && !(data.length == 1 && data[0].length == 0) ) { //新增缓存 let _nicmd = __.cm.getConfigValue(__.KEY, __.setcommand); if (_nicmd) { const _conn = await __.cacheres.getDBConnection(); try { const _cmd = __.cacheres.getDBCommand(); _cmd.connection = _conn; _cmd.command = _nicmd.command; _cmd.params = _nicmd.merge( { cacheKey: "" + V.hash( v.key + ".Set." + V.toJsonString(cmd.params), ), cacheValue: V.toJsonString(data), }, _nicmd.params, cmd.params, ); cmd.dbtype = v.dbtype; cmd.jsonp = v.jsonp; const _data = await _cmd.execute(); } finally { __.cacheres.backDBConnection(_conn); } } } } return false; }, true, ); if (conn.transaction && conn.commit) await conn.commit(); return __.result; } catch (err) { V.showException("commit ", err); } finally { __.res.backDBConnection(conn); } } else { V.showException("不能调用空的命令对象!"); } }; __.excute = async () => await __.execute(); } }; export const NiMultiTemplateDecorator = class extends NiTemplate { constructor(res, cm, relcm, appName = "Ni") { super(res, cm); const that = this; const { _, __ } = pri(that, { KEY: appName, ni: new NiTemplateManager(relcm, appName), lstCmd2: {}, }); const _addCommand = __.addCommand; const _execute = __.execute; //todo 可能可以实现覆盖! __.addCommand = (name, params) => { const { _, __ } = pri(that); let index = __.lstCmd.length; _addCommand.apply(_, [name, params]); let cmd = __.lstCmd[__.lstCmd.length - 1]; if (cmd.template) { //调用templdate优先 复用其次 __.lstCmd2[__.lstCmd.length - 1] = true; } }; __.execute = async () => { const { _, __ } = pri(that); let _cms = __.lstCmd, _cm2 = __.lstCmd2; ((__.lstCmd = []), (__.lstCmd2 = {})); if (_.transaction) throw new Error("NiMultiTemplateDecorator不支持事务,容易发生内容错位"); if (_cms.length > 0) { let i = 0; await V.each( _cms, async (v) => { let _nicmd = _cm2[i++]; if (_nicmd) { const result = await __.ni.execute(v.template, v.key, v.params); __.result.add( result && result.get(v.key) ? result.get(v.key) : [], v.key, ); } else { const conn = await __.res.getDBConnection(); try { let cmd = __.res.getDBCommand(); cmd.connection = conn; cmd.command = v.name; cmd.params = v.params; cmd.oriparams = v.oriparams; cmd.dbtype = v.dbtype; cmd.jsonp = v.jsonp; const data = await cmd.execute(); __.result.add( typeof data == "undefined" || (V.isArray(data) && data.length == 0) ? false : data, v.key, ); } finally { __.res.backDBConnection(conn); } } return false; }, true, ); } else { V.showException("不能调用空的命令对象!"); } return __.result; }; __.excute = async () => await __.execute(); } dispose() { const { __ } = pri(this); __.ni.dispose(); super.dispose(); } }; /** * MySQL 池连接方式工厂 */ export const NiMySQLDataFactory = class extends NiDataFactory { constructor() { super(); const that = this; that.idic = {}; const { _, __ } = pri(that, { MySQLConnection: class extends NiDataConnection { constructor() { super(); const that = this; const { _, __ } = pri(this, { cmds: [], conn: null, getValue: (p) => p.value, toList: (vals) => { const { _, __ } = pri(that); if (vals[0]) { let ret = []; for (let i = 0; i < vals.length; i++) ret.push(__.toList(vals[i])); return ret; } else return (function () { const ret = {}; for (let k in vals) { switch (V.getType(vals[k]).toLowerCase()) { case "date": case "number": case "boolean": case "string": case "null": ret[k] = vals[k]; break; case "uint8array": // ret[k] = parseInt(Buffer.from(vals[k])[0]); ret[k] = Buffer.from(vals[k]).toString(); break; } } return ret; })(); }, invoke: async (command, params) => { try { const { _, __ } = pri(that); let result = await V.callback( __.conn.query, __.conn, _.prepare(command, params), ); let data = []; if (!result[0]) result = [[]]; //过滤mysql自定义的更新结果JSON result = result.filter((v) => v.serverStatus == undefined); //过滤mysql上复制:= result = result.filter((v) => { switch (V.getType(v)) { case "object": case "Object": for (var k in v) { if (k.indexOf(":=") >= 0) return false; } break; case "Array": const _v = v.filter((r) => { for (var k2 in r) { if (k2.indexOf(":=") >= 0) return false; } return true; }); return _v.length > 0 || v.length == 0; } return true; }); if (!result[0]) result = [[]]; if (V.getType(result[0]).toLowerCase() != "array") result = [result]; //自动补充mysql在单sql下不是2个嵌套数据的问题 if (result && result.length > 0) for (let i = 0; i < result.length; i++) { if (typeof result[i] != "undefined" && result[i].length > 0) data.push(__.toList(result[i])); else if ( typeof result[i] != "undefined" && !V.isArray(result[i]) ) { //if (typeof(result[i].affectedRows) == 'undefined') { data.push(__.toList([result[i]])); } else { data.push([]); } } else data.push([]); return data; } catch (e) { console.log(command, params); console.log(e.message); throw e; } }, }); _.params = { multipleStatements: true, connectionLimit: 10, }; } prepare(cmd, paras) { const { _, __ } = pri(this); //需要将{}转成[] 处理 if (cmd && paras) { let vals = []; cmd = cmd .replace(/\{[a-zA-Z0-9_]+\}/g, (data) => { try { data = data.substr(1, data.length - 2); return __.getValue(paras[data]); } catch (e) { throw data + "未找到参数定义"; } }) .replace(/\?[a-zA-Z0-9_]+/g, (data) => { try { vals.push(__.getValue(paras[data.trim("?")])); return "?"; } catch (e) { throw data.trim("?") + "未找到参数定义"; } }); return { sql: cmd, values: vals, timeout: _.params.timeout || 60000, //1分钟 }; } else throw new Error("prepare方法要求写入command参数与paras参数"); } async invoke(cmd) { //需要处理单条与多条s const { _, __ } = pri(this); if (_.transaction) { __.cmds.push({ command: cmd.command, params: cmd.params, }); } else { /*if (cmd.command.split(';').filter(e => e.length) > 1) { //事务性处理 __.cmds.push({ command: cmd.command, params: cmd.params }); return await _.commit()[0]; } else*/ return await __.invoke(cmd.command, cmd.params); } } async commit() { const { _, __ } = pri(this); if (_.transaction) { //事务性处理 try { await V.callback(__.conn.beginTransaction, __.conn); let data = []; let cmds = __.cmds; __.cmds = []; await V.each( cmds, async (v) => { //console.log(v.cmd.params); data.push(await __.invoke(v.command, v.params)); return false; }, true, ); await V.callback(__.conn.commit, __.conn); return data; } catch (e) { await V.callback(__.conn.rollback, __.conn); throw e; } } else throw new Error("非事务条件下不可调用此方法"); } async open() { const { _, __ } = pri(this); const key = V.hash2(V.toJsonString(_.params)); that.idic[key] = that.idic[key] || M.createPool(_.params); var getonconn = async function () { var conn = await V.callback( that.idic[key].getConnection, that.idic[key], ); conn._key = key; if (!!!conn._ison) { conn._ison = true; conn.on("error", async function (err) { if ( err.code == "PROTOCOL_CONNECTION_LOST" || err.code == "PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR" ) { try { //conn.close(); that.idic[key] && that.idic[key].releaseConnection(conn); } catch (e) {} __.conn = await getonconn(); } }); } return conn; }; __.conn = await getonconn(); await super.open(); } async close() { const { _, __ } = pri(this); try { if (__.conn && __.conn._key && that.idic[__.conn._key]) that.idic[__.conn._key].releaseConnection(__.conn); else if (__.conn && __.conn.end) __.conn.end(); else if (__.conn && __.conn.dispose) __.conn.dispose(); } catch (e) {} __.cmds = []; __.conn = null; await super.close(); } }, }); } createDBConnection() { const { _, __ } = pri(this); return new __.MySQLConnection(); } dispose() { for (let i in this.idic) { if (this.idic[i] && this.idic[i].dispose) { const v = this.idic[i]; V.tryC(() => { v.dispose(); }); } } } }; /* 默认类型转换 String -> sql.NVarChar Number -> sql.Int Boolean -> sql.Bit Date -> sql.DateTime Buffer -> sql.VarBinary sql.Table -> sql.TVP 特别定义 param length 和 scale属性 分别对应 长度和精度(仅限Decimal和Numberic) */ export const NiMsSQLDataFactory = class extends NiDataFactory { constructor() { super(); const that = this; that.idic = {}; const { _, __ } = pri(that, { MsSQLConnection: class extends NiDataConnection { constructor() { super(); const that = this; const { _, __ } = pri(this, { cmds: [], conn: null, getValue: (p) => p.value, invoke: async (source, command, params) => { try { const { _, __ } = pri(that); const request = new M2.Request(source); request.multiple = true; command = command.replace(/\{[a-zA-Z0-9_]+\}/g, (data) => { try { data = data.substr(1, data.length - 2); return __.getValue(params[data]); } catch (e) { throw data + "未找到参数定义"; } }); for (let i in params) { //ni params 应该有 name:{type:'',value:''} or name:string ni定义未必支持 const type = M2[V.getValue(params[i].type, "NVarChar")] || M2.NVarChar; if (params[i].out) request.output( i, (params[i].length || 0) > 0 ? type(params[i].length) : type, params[i].value, ); else switch ((params[i].type + "").toLowerCase()) { case "decimal": case "numeric": request.input( i, type(params[i].length || 10, params[i].scale || 2), params[i].value, ); break; default: request.input( i, (params[i].length || 0) > 0 ? type(params[i].length) : type, params[i].value, ); break; } } let [result, affected] = [null, 0]; //await V.callback(request.prepare, request, command); [result, affected] = await V.callback((call) => { if (command.indexOf(" ") >= 0) request.query(command, (err, result) => call(err, [result, err ? 0 : result.rowsAffected]), ); else request.execute(command, (err, result) => call(err, [result, err ? 0 : result.rowsAffected]), ); }); //await V.callback(request.unprepare, request); let data = []; //特别注意单行的处理,可能会导致单行无数据 if (result.recordsets && result.recordsets.length > 0) for (let i = 0; i < result.recordsets.length; i++) { if (result.recordsets[i] && result.recordsets[i].length > 0) data.push(result.recordsets[i]); else data.push( affected[i] ? [ { affected: affected[i], }, ] : [], ); } else data.push( affected && affected[0] ? [ { affected: affected[0], }, ] : [], ); return data; } catch (e) { console.log(command, params); console.log(e.message); throw e; } }, }); _.params = { connectionLimit: 10, timeout: 60000, }; } async invoke(cmd) { const { _, __ } = pri(this); if (_.transaction) { __.cmds.push({ command: cmd.command, params: cmd.params, }); } else { /*if (cmd.command.split(';').filter(e => e.length) > 1) { //事务性处理 __.cmds.push({ command: cmd.command, params: cmd.params }; return await _.commit()[0]; } else*/ return await __.invoke(__.conn, cmd.command, cmd.params); } } async commit() { const { _, __ } = pri(this); if (_.transaction) { //事务性处理 let trans = new M2.Transaction(__.conn); try { await V.callback(trans.begin, trans); let data = []; let cmds = __.cmds; __.cmds = []; await V.each( cmds, async (v) => { data.push(await __.invoke(trans, v.command, v.params)); return false; }, true, ); await V.callback(trans.commit, trans); return data; } catch (e) { await V.callback(trans.rollback, trans); throw e; } } else throw new Error("非事务条件下不可调用此方法"); } async open() { const { _, __ } = pri(this); const key = V.hash2(V.toJsonString(_.params)); const func = function () { const conn = new M2.ConnectionPool(_.params); conn.on("error", function (err) { console.log("GCL mssql error:" + err.stack); __.conn = func(); }); return conn; }; __.conn = func(); await V.callback(__.conn.connect, __.conn); await super.open(); } async close() { const { _, __ } = pri(this); try { if (__.conn && __.conn.close) __.conn.close(); else if (__.conn && __.conn.end) __.conn.end(); else if (__.conn && __.conn.dispose) __.conn.dispose(); } catch (e) { } finally { //const key = V.hash2(V.toJsonString(_.params)); //delete that.idic[key]; } __.cmds = []; __.conn = null; await super.close(); } }, }); } createDBConnection() { const { _, __ } = pri(this); return new __.MsSQLConnection(); } dispose() { for (let i in this.idic) { if (this.idic[i] && this.idic[i].close) { const v = this.idic[i]; V.tryC(() => { v.close(); }); delete this.idic[i]; } } } }; /** * 分离NiDBFactory产生NiDBConnection(Invoke) mysql,sqlserver,memcache,mongo websocket ObjectDB等各种资源 */ export const NiObjectDataFactory = class extends NiDataFactory { constructor(middler = null) { super(); if (!V.isValid(middler)) throw new Error("参数的定义必须要输入middler参数"); const that = this; const { _, __ } = pri(that, { middler: middler, ObjectConnection: class extends NiDataConnection { constructor() { super(); const { _, __ } = pri(this, { cmds: [], prepare: (oriparams, params) => { //按照oriparams过滤 var ret = []; for (var k in oriparams) ret.push(params[k] ? params[k].value : undefined); return ret; }, invoke: async (command, params) => { try { command = command.trim(); if (typeof __.obj[command] == "function") { return ( (await V.callback2(__.obj[command], __.obj, ...params)) || true ); } else throw new Error(command + "方法没有在对象源上找到"); } catch (e) { console.log(command, params); console.log(e.message); throw e; } }, }); _.params = { app: "Ni", name: "", }; } async open() { const { _, __ } = pri(this); if (V.isValid(_.params.name)) { //证明可用 __.obj = middler.getObjectByAppName(_.params.app, _.params.name); if (!__.obj) throw new Error( `N.NiObjectDataFactory 无法创建<${_.params.app}/${_.params.name}>对象`, ); } else throw new Error( `N.NiObjectDataFactory 无法找到<'${_.params.app}/${_.params.name}>对象`, ); await super.open(); } async close() { const { _, __ } = pri(this); if (__.obj) { middler.setObjectByAppName(_.params.app, _.params.name, __.obj); delete __.obj; } await super.close(); } async invoke(cmd) { const { _, __ } = pri(this); if (_.transaction) { __.cmds.push({ command: cmd.command, params: __.prepare(cmd.oriparams, cmd.params), }); } else return await __.invoke( cmd.command, __.prepare(cmd.oriparams, cmd.params), ); } async commit() { const { _, __ } = pri(this); if (_.transaction) { //事务性处理 let data = []; let cmds = __.cmds; __.cmds = []; await V.each( cmds, async (v) => { data.push(await __.invoke(v.command, v.params)); return false; }, true, ); return data; } else throw new Error("非事务条件下不可调用此方法"); } }, }); } createDBConnection() { const { _, __ } = pri(this); return new __.ObjectConnection(); } }; /** * MemCached * @param {*} parser */ export const NiMemSQLDataFactory = class extends NiDataFactory { constructor(parser) { super(); let that = this; const { _, __ } = pri(that, { MemSQLConnection: class extends NiDataConnection { constructor() { super(); const _this = this; const { _, __ } = pri(this, { cmds: [], conn: null, invoke: async (command, params) => { try { const { _, __ } = pri(_this); let queryList = that.parser.parse(command, params); let data = []; await V.each( queryList, async (v, call) => { let cacheKey = _this.getKey(v); switch (v.Method.toLowerCase().trim()) { case "select": { data.push([ await V.callback((call) => __.conn.get(cacheKey, call), ), ]); } break; case "insert": case "update": { const datetime = V.getValue( V.toJsonString(v.DateTimeParam).length > 2 ? (() => { for (let k in v.DateTimeParam) return v.DateTimeParam[k]; })() : _.params.datetime, ); const values = {}; for (let k in v.MethodParam) { let v2 = v.MethodParam[k]; v2 = typeof v2.value === "undefined" ? v2 : v2.value; values[k] = v2; if (typeof v2 === "undefined" || v2.type) throw new Error(`参数${k}不能为undefined`); } await V.callback( __.conn.set, __.conn, cacheKey, values, datetime, ); data.push([ { value: 1, }, ]); } break; case "delete": { let res = await V.callback( __.conn.del, __.conn, cacheKey, ); data.push([ { value: res, }, ]); } break; case "touch": { let dt = V.toJsonString(v.DateTimeParam).length > 2 ? (() => {