// JSON 对象数据导入数据库的函数库 // 应用配置信息 eval(dfs.read("/script/matrix/utils/ajs/config.js")) function compitable(dta, dtb) { switch (dta) { case "timestamp": switch (dtb) { case "timestamp": return true; default: return false; } case "boolean": switch (dtb) { case "boolean": return true; default: return false; } case "int": case "integer": case "bigint": switch (dtb) { case "int": case "integer": case "bigint": return true; default: return false; } case "number": case "float": case "double": switch (dtb) { case "number": case "float": case "double": case "int": case "integer": case "bigint": return true; default: return false; } case "string": case "varchar": case "text": return true; } return false } // 根据 JSON 对象数据建类或新增字段 // classname 类名 // clsoption 建类选项 // data 数据示例 // fieldmap 字段名映射,参数中指定的字段名均为JSON对象中的属性名,默认将 camelStyle 转换为 snake_style // fields 字段类型 function alterClass(input) { // 返回信息 var output = {}; try { // 参数检查 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.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.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] && !compitable(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 = { 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] && !compitable(clsfields[xk].ftype, xfields[xk])) { throw ("已经存在同名类字段 " + xk + " 信息不一致," + clsfields[xk].ftype + "!=" + xfields[xk] + ",需手动干预"); } } if (addn > 0) { odb.mql(mql); output = { mql: mql }; } } } catch (e) { if (typeof (e) == "object") { output.error = e; } else if (typeof (e) == "string") { output.error = "错误:" + e; } else { output.error = JSON.stringify(e); } } return output } // 根据 JSON 数据生成导入脚本 function generateJsonImporterJS(input) { var output = {}; try { // 参数检查 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; d = new Date(); d.setMinutes(d.getMinutes() - d.getTimezoneOffset()); dtm = d.toJSON().replace(/T/, " ").replace(/Z/,""); 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 (v && typeof (v) == "object") { values += "JSON.stringify("; values += "input." + k + ", \" \", 4)" + fsep; values += JSON.stringify(v, " ", 4).replace(/^/mg, " // ").replace(/ /, " "); } else { values += "input." + k + "?" 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/ajs/JsonImporter.template.js"); importjs = importjs.replace(/___field_map___/mg, JSON.stringify(fieldmap)); 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); } catch (e) { if (typeof (e) == "object") { output.error = e; } else if (typeof (e) == "string") { output.error = "错误:" + e; } else { output.error = JSON.stringify(e); } } 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", cfg.server + "/script/exec/js?filepath=" + calljsfp + "&input=" + reqinput, { "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; }