|
@@ -0,0 +1,436 @@
|
|
|
+// JSON 对象数据导入数据库的函数库
|
|
|
+
|
|
|
+// 应用配置信息
|
|
|
+eval(dfs.read("/script/matrix/utils/config.js"))
|
|
|
+
|
|
|
+// 根据 JSON 对象数据建类或新增字段
|
|
|
+// classname 类名
|
|
|
+// clsoption 建类选项
|
|
|
+// data 数据示例
|
|
|
+// fieldmap 字段名映射,参数中指定的字段名均为JSON对象中的属性名,默认将 camelStyle 转换为 snake_style
|
|
|
+// fields 字段类型
|
|
|
+function alterClass(input) {
|
|
|
+ // 返回信息
|
|
|
+ output = {}
|
|
|
+ // 参数检查
|
|
|
+ if (!input.classname) { // like /cncc/itil/project
|
|
|
+ throw ("需要指定classname");
|
|
|
+ }
|
|
|
+ if (input.classname[0] != "/") { // like /cncc/itil/project
|
|
|
+ throw ("classname必须以 / 开头");
|
|
|
+ }
|
|
|
+ if (!input.data || typeof(input.data)!="object") {
|
|
|
+ throw ("data必须指定为一个对象");
|
|
|
+ }
|
|
|
+ // 检查父类是否存在,不存在就创建
|
|
|
+ cns = input.classname.split("/");
|
|
|
+ clsname = "";
|
|
|
+ for (var cni = 1; cni < cns.length - 1; cni++) {
|
|
|
+ clsname += "/" + cns[cni];
|
|
|
+ odb.mql("create class if not exists " + clsname + "()");
|
|
|
+ }
|
|
|
+ pclsname = clsname;
|
|
|
+ clsname += "/" + cns[cns.length - 1];
|
|
|
+
|
|
|
+ // 提取现有类的字段信息
|
|
|
+ clsexist = false;
|
|
|
+ clsfields = {};
|
|
|
+ try {
|
|
|
+ fieldslist = odb.classfields(clsname);
|
|
|
+ for (var fi = 0; fi < fieldslist.length; fi++) {
|
|
|
+ fld = fieldslist[fi];
|
|
|
+ fname = fld.name;
|
|
|
+ if (/^\w+\:.*/.test(fname)) {
|
|
|
+ fname = fname.replace(/^\w+\:/, "");
|
|
|
+ }
|
|
|
+ if (fname && fld.ftype) {
|
|
|
+ clsfields[fname] = {
|
|
|
+ iskey: fld.iskey,
|
|
|
+ ftype: fld.ftype,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ clsexist = true;
|
|
|
+ } catch(e) {}
|
|
|
+ if (!clsexist) {
|
|
|
+ try {
|
|
|
+ fieldslist = odb.classfields(pclsname);
|
|
|
+ for (var fi = 0; fi < fieldslist.length; fi++) {
|
|
|
+ fld = fieldslist[fi];
|
|
|
+ fname = fld.name;
|
|
|
+ if (/^\w+\:.*/.test(fname)) {
|
|
|
+ fname = fname.replace(/^\w+\:/, "");
|
|
|
+ }
|
|
|
+ if (fname && fld.ftype) {
|
|
|
+ clsfields[fname] = {
|
|
|
+ iskey: fld.iskey,
|
|
|
+ ftype: fld.ftype,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch(e) {}
|
|
|
+ }
|
|
|
+ output.info.clsfields = clsfields;
|
|
|
+
|
|
|
+ // 通过参数确定的字段类型信息
|
|
|
+ fields = input.fields;
|
|
|
+ if (!fields) {
|
|
|
+ fields = {};
|
|
|
+ }
|
|
|
+ // 字段名映射,参数中指定的字段名均为JSON对象中的属性名,默认将 camelStyle 转换为 snake_style
|
|
|
+ fieldmap = input.fieldmap;
|
|
|
+ if (!fieldmap) {
|
|
|
+ fieldmap = {};
|
|
|
+ }
|
|
|
+ // 反向字段名映射,类中的字段名映射为JSON对象中的属性名
|
|
|
+ xfieldmap = {};
|
|
|
+ // 类中的字段名列表,用于排序
|
|
|
+ xfieldslist = [];
|
|
|
+ // 类字段类型信息
|
|
|
+ xfields = {};
|
|
|
+ xpks = [];
|
|
|
+ for (var jk in input.data) {
|
|
|
+ xk = fieldmap[jk];
|
|
|
+ // 通过参数确定的字段类型信息
|
|
|
+ if (!xk) {
|
|
|
+ // 默认将 camelStyle 转换为 snake_style
|
|
|
+ xk = "j_"; // 区别于其它字段,自动创建的字段以 j_ 开头
|
|
|
+ for (var i = 0; i < jk.length; i++) {
|
|
|
+ if (jk[i] >= 'A' && jk[i] <= 'Z') {
|
|
|
+ xk += "_" + jk[i].toLowerCase();
|
|
|
+ } else {
|
|
|
+ xk += jk[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fieldmap[jk] = xk;
|
|
|
+ }
|
|
|
+ xfieldslist.push(xk);
|
|
|
+ xfieldmap[xk] = jk;
|
|
|
+ dt = fields[jk];
|
|
|
+ if (dt && dt.indexOf(",key") > 0) {
|
|
|
+ dt = dt.replace(",key", "");
|
|
|
+ xpks.push(xk);
|
|
|
+ }
|
|
|
+ switch (dt) {
|
|
|
+ case "date":
|
|
|
+ case "time":
|
|
|
+ case "datetime":
|
|
|
+ dt = "timestamp";
|
|
|
+ break;
|
|
|
+ case "int":
|
|
|
+ case "integer":
|
|
|
+ dt = "bigint";
|
|
|
+ break;
|
|
|
+ case "number":
|
|
|
+ case "float":
|
|
|
+ dt = "double";
|
|
|
+ break;
|
|
|
+ case "text":
|
|
|
+ dt = "text";
|
|
|
+ break;
|
|
|
+ case "string":
|
|
|
+ dt = "varchar";
|
|
|
+ break;
|
|
|
+ case "boolean":
|
|
|
+ dt = "boolean";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (!dt) {
|
|
|
+ // 没有明确定义的字段类型
|
|
|
+ // 根据数据判断类型
|
|
|
+ dt = "varchar";
|
|
|
+ d = input.data[jk];
|
|
|
+ if (d || d == "" || d == 0 || d == false) {
|
|
|
+ switch (typeof(d)) {
|
|
|
+ case 'object':
|
|
|
+ // 转为text
|
|
|
+ dt = "text";
|
|
|
+ break;
|
|
|
+ case 'number':
|
|
|
+ // 是否为整数
|
|
|
+ if ((""+d).indexOf(".")<0) {
|
|
|
+ dt = "bigint";
|
|
|
+ } else {
|
|
|
+ dt = "double";
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'boolean':
|
|
|
+ dt = "boolean";
|
|
|
+ break;
|
|
|
+ case 'string':
|
|
|
+ default:
|
|
|
+ // 是否为日期时间
|
|
|
+ if (/_time/.test(xk) || /_date/.test(xk)) {
|
|
|
+ dt = "timestamp";
|
|
|
+ } else {
|
|
|
+ dt = "varchar";
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (/_time/.test(xk) || /_date/.test(xk)) {
|
|
|
+ dt = "timestamp";
|
|
|
+ } else {
|
|
|
+ dt = "varchar";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ xfields[xk] = dt;
|
|
|
+ }
|
|
|
+ output.info.xfields = xfields;
|
|
|
+
|
|
|
+ if (!clsexist) {
|
|
|
+ // 类不存在,自动创建类
|
|
|
+ mql = "create class if not exists " + clsname + "(";
|
|
|
+ indexes = "indexes(";
|
|
|
+ for (var fi = 0; fi < xfieldslist.length; fi++) {
|
|
|
+ xk = xfieldslist[fi];
|
|
|
+ if (xk in {"id":"", "class":"", "name":"", "day":"", "tags":"", "vtime":""}) {
|
|
|
+ throw("内部使用字段名 " + xk + ",需要映射成其它名称");
|
|
|
+ }
|
|
|
+ if (clsfields[xk] && clsfields[xk].ftype != xfields[xk]) {
|
|
|
+ throw ("类继承字段 "+ xk +" 信息不一致,"+clsfields[xk].ftype + "!=" + xfields[xk]+",需手动干预");
|
|
|
+ }
|
|
|
+ mql += fi==0 ? "\n": ",\n";
|
|
|
+ mql += xk + " " + xfields[xk];
|
|
|
+ if (fi > 0) {
|
|
|
+ indexes += ",";
|
|
|
+ }
|
|
|
+ indexes += xk;
|
|
|
+ }
|
|
|
+ indexes += ")";
|
|
|
+ mql += ",\n" + indexes;
|
|
|
+ if (xpks.length > 0) {
|
|
|
+ mql += ",\n";
|
|
|
+ mql += "keys(";
|
|
|
+ for (var pki = 0; pki < xpks.length; pki++) {
|
|
|
+ if (pki > 0) {
|
|
|
+ mql += ",";
|
|
|
+ }
|
|
|
+ mql += xpks[pki];
|
|
|
+ }
|
|
|
+ mql += ")";
|
|
|
+ }
|
|
|
+ mql += "\n";
|
|
|
+ mql += ")";
|
|
|
+ if (input.clsoption) {
|
|
|
+ mql += input.clsoption;
|
|
|
+ }
|
|
|
+ odb.mql(mql);
|
|
|
+ output.info = {mql:mql};
|
|
|
+ } else {
|
|
|
+ // 类已存在,检查主键信息是否存在
|
|
|
+ for (var pki = 0; pki < xpks.length; pki++) {
|
|
|
+ xk = xpks[pki];
|
|
|
+ if (!clsfields[xk] || !clsfields[xk].iskey) {
|
|
|
+ throw ("已经存在同名类主键 "+ xk +" 信息不一致,需手动干预");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 追加字段
|
|
|
+ mql = "alter class " + clsname + " add index column";
|
|
|
+ addn = 0;
|
|
|
+ for (var fi = 0; fi < xfieldslist.length; fi++) {
|
|
|
+ xk = xfieldslist[fi];
|
|
|
+ if (!clsfields[xk]) {
|
|
|
+ mql += (addn == 0)?" ":", ";
|
|
|
+ mql += xk + " " + xfields[xk];
|
|
|
+ addn++;
|
|
|
+ } else if (clsfields[xk].ftype != xfields[xk]) {
|
|
|
+ throw ("已经存在同名类字段 "+ xk +" 信息不一致,需手动干预");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (addn > 0) {
|
|
|
+ odb.mql(mql);
|
|
|
+ output.info = {mql:mql};
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return output
|
|
|
+}
|
|
|
+
|
|
|
+// 根据 JSON 数据生成导入脚本
|
|
|
+function generateJsonImporterJS(input) {
|
|
|
+ output = {}
|
|
|
+ // 参数检查
|
|
|
+ if (!input.classname) { // like /cncc/itil/project
|
|
|
+ throw ("需要指定classname");
|
|
|
+ }
|
|
|
+ if (input.classname[0] != "/") { // like /cncc/itil/project
|
|
|
+ throw ("classname必须以 / 开头");
|
|
|
+ }
|
|
|
+ sjsfn = input.jsfilename;
|
|
|
+ if (!sjsfn) {
|
|
|
+ sjsfn = "/script" + input.classname; // like /script/cncc/itil/project
|
|
|
+ }
|
|
|
+ if (sjsfn.substring(0, 8) != "/script/") {
|
|
|
+ throw ("jsfilename必须以 /script/ 开头");
|
|
|
+ }
|
|
|
+ sjsfn = sjsfn.replace(/\.js$/, "");
|
|
|
+ output.file = sjsfn;
|
|
|
+
|
|
|
+ dtm = new Date().toJSON();
|
|
|
+ mql = "insert into " + input.classname + " (\n";
|
|
|
+ mql_values = ") values (\n";
|
|
|
+ mql_end = ")";
|
|
|
+ values = "";
|
|
|
+ fieldmap = input.fieldmap;
|
|
|
+ if (!fieldmap) {
|
|
|
+ fieldmap = {};
|
|
|
+ }
|
|
|
+ xfieldmap = {};
|
|
|
+ xfields = [];
|
|
|
+ clsfields = {};
|
|
|
+ try {
|
|
|
+ fieldslist = odb.classfields(input.classname);
|
|
|
+ for (var fi = 0; fi < fieldslist.length; fi++) {
|
|
|
+ fld = fieldslist[fi];
|
|
|
+ fname = fld.name;
|
|
|
+ if (/^\w+\:.*/.test(fname)) {
|
|
|
+ fname = fname.replace(/^\w+\:/, "");
|
|
|
+ }
|
|
|
+ if (fname && fld.ftype) {
|
|
|
+ clsfields[fname] = {
|
|
|
+ iskey: fld.iskey,
|
|
|
+ ftype: fld.ftype,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch(e) {}
|
|
|
+ for (var k in input.data) {
|
|
|
+ xk = fieldmap[k];
|
|
|
+ if (!xk) {
|
|
|
+ xk = "j_"; // 区别于其它字段,自动创建的字段以 j_ 开头
|
|
|
+ for (var i = 0; i < k.length; i++) {
|
|
|
+ if (k[i] >= 'A' && k[i] <= 'Z') {
|
|
|
+ xk += "_" + k[i].toLowerCase();
|
|
|
+ } else {
|
|
|
+ xk += k[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fieldmap[k] = xk;
|
|
|
+ }
|
|
|
+ xfields.push(xk);
|
|
|
+ xfieldmap[xk] = k;
|
|
|
+ }
|
|
|
+ xfields.sort();
|
|
|
+ fsep = ",";
|
|
|
+ for (var i = 0; i < xfields.length; i++) {
|
|
|
+ if (i == xfields.length - 1) {
|
|
|
+ fsep = "";
|
|
|
+ }
|
|
|
+ xk = xfields[i];
|
|
|
+ k = xfieldmap[xk];
|
|
|
+ mql += xk + fsep + "\n";
|
|
|
+ mql_values += "?" + fsep + "\n";
|
|
|
+ values += " ";
|
|
|
+ v = input.data[k];
|
|
|
+ if (!clsfields[xk]) {
|
|
|
+ throw("字段不存在", xk)
|
|
|
+ }
|
|
|
+ switch (clsfields[xk].ftype) {
|
|
|
+ case "text":
|
|
|
+ case "varchar":
|
|
|
+ if (typeof(v) == "object") {
|
|
|
+ values += "JSON.stringify(";
|
|
|
+ values += "input." + k + ", \" \", 4)" + fsep;
|
|
|
+ values += JSON.stringify(v, " ", 4).replace(/^/mg, " // ").replace(/ /, " ");
|
|
|
+ } else {
|
|
|
+ values += "\"\"+";
|
|
|
+ values += "input." + k + fsep;
|
|
|
+ values += (""+v).replace(/^/mg, " // ").replace(/ /, " ");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ values += "input." + k + fsep;
|
|
|
+ values += (""+v).replace(/^/mg, " // ").replace(/ /, " ");
|
|
|
+ }
|
|
|
+ values += "\n ";
|
|
|
+ }
|
|
|
+ mql += mql_values + mql_end;
|
|
|
+ values = "\n " + values;
|
|
|
+
|
|
|
+ datainfo = "{";
|
|
|
+ datacheck = "";
|
|
|
+ if (input.mustfield) {
|
|
|
+ ids = input.mustfield.split(",");
|
|
|
+ for (var i = 0; i < ids.length; i++) {
|
|
|
+ id = ids[i];
|
|
|
+ if (i > 0) {
|
|
|
+ datacheck += "\n ";
|
|
|
+ }
|
|
|
+ datacheck += "if (!input." + id + ") {\n ";
|
|
|
+ datacheck += " throw (\"输入参数必须为对象,且指定属性" + id + "\");\n ";
|
|
|
+ datacheck += "}";
|
|
|
+ if (i == 0) {
|
|
|
+ datainfo += "\n ";
|
|
|
+ } else {
|
|
|
+ datainfo += ",\n ";
|
|
|
+ }
|
|
|
+ datainfo += " " + id + ": input." + id;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ datainfo += "\n ";
|
|
|
+ datainfo += "}";
|
|
|
+
|
|
|
+ importjs = dfs.read("/script/matrix/utils/JsonImporter.template.js");
|
|
|
+ importjs = importjs.replace(/___istesting___/mg, input.istesting);
|
|
|
+ importjs = importjs.replace(/___classname___/mg, input.classname);
|
|
|
+ importjs = importjs.replace(/___datetime_now___/mg, dtm);
|
|
|
+ importjs = importjs.replace(/if\s*\(\s*___datacheck___\s*\)\s*\{.*\}/mg, datacheck);
|
|
|
+ importjs = importjs.replace(/___mql___/mg, mql);
|
|
|
+ importjs = importjs.replace(/___values___/mg, values);
|
|
|
+ importjs = importjs.replace(/___datainfo___/mg, datainfo);
|
|
|
+
|
|
|
+ output.content = importjs;
|
|
|
+
|
|
|
+ dfs.write(sjsfn + ".js", importjs);
|
|
|
+ return output
|
|
|
+}
|
|
|
+
|
|
|
+// 激活脚本,生成的脚本文件需要激活后才能生效
|
|
|
+function activeServerJS(jsfilename) {
|
|
|
+ result = {}
|
|
|
+ calljsfp = encodeURIComponent(jsfilename.replace(/\/script/, ""));
|
|
|
+ http.do("POST",
|
|
|
+ cfg.server+"/fs/tolocal/script"+calljsfp+"?issys=true",
|
|
|
+ {"Authorization": "Basic "+cfg.author},
|
|
|
+ '',
|
|
|
+ function(response){
|
|
|
+ // success func
|
|
|
+ ret = response.data;
|
|
|
+ if (ret.message) {
|
|
|
+ result = ret.message;
|
|
|
+ } else {
|
|
|
+ result = ret;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ function(response){
|
|
|
+ // error func
|
|
|
+ result.error = response.data;
|
|
|
+ });
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+// 验证测试执行脚本
|
|
|
+function runServerJS(jsfilename, data) {
|
|
|
+ result = {}
|
|
|
+ reqinput = encodeURIComponent(base64.encode(JSON.stringify(data)));
|
|
|
+ calljsfp = encodeURIComponent(jsfilename.replace(/\/script/, ""));
|
|
|
+ http.do("POST",
|
|
|
+ server+"/script/exec/js?filepath="+calljsfp+"&input="+reqinput,
|
|
|
+ {"Authorization": "Basic "+author},
|
|
|
+ '',
|
|
|
+ function(response){
|
|
|
+ // success func
|
|
|
+ ret = response.data;
|
|
|
+ if (ret.message) {
|
|
|
+ result = ret.message;
|
|
|
+ } else {
|
|
|
+ result = ret;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ function(response){
|
|
|
+ // error func
|
|
|
+ result.error = response.data;
|
|
|
+ });
|
|
|
+ return result;
|
|
|
+}
|