gcl
Version:
码农村nodejs类库,完成解决回调陷阱,配置框架,IOC框架,统一多DB访问框架,可扩展日志框架和io/db/net/thread/pool 克隆表达式,加解密算法等等一系列基础类库和算法的实现
1,601 lines (1,585 loc) • 158 kB
JavaScript
import V from "../common/tool";
import C from "../io/config";
import { Pool } from "../collection/pool";
import M from "mysql";
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 { 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() {
const { _, __ } = pri(this);
return _.hasData()
? (function () {
const data = _.get(__.datas.length - 1);
return data[0] && data[0][0] ? data[0][0] : {};
})()
: 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
? (() => {
for (let k in v.DateTimeParam)
return v.DateTimeParam[k];