JsonImporterFuncs.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. // JSON 对象数据导入数据库的函数库
  2. // 应用配置信息
  3. eval(dfs.read("/script/matrix/utils/ajs/config.js"))
  4. // 根据 JSON 对象数据建类或新增字段
  5. // classname 类名
  6. // clsoption 建类选项
  7. // data 数据示例
  8. // fieldmap 字段名映射,参数中指定的字段名均为JSON对象中的属性名,默认将 camelStyle 转换为 snake_style
  9. // fields 字段类型
  10. function alterClass(input) {
  11. // 返回信息
  12. var output = {};
  13. // 参数检查
  14. if (!input.classname) { // like /cncc/itil/project
  15. throw ("需要指定classname");
  16. }
  17. if (input.classname[0] != "/") { // like /cncc/itil/project
  18. throw ("classname必须以 / 开头");
  19. }
  20. if (!input.data || typeof(input.data)!="object") {
  21. throw ("data必须指定为一个对象");
  22. }
  23. // 检查父类是否存在,不存在就创建
  24. cns = input.classname.split("/");
  25. clsname = "";
  26. for (var cni = 1; cni < cns.length - 1; cni++) {
  27. clsname += "/" + cns[cni];
  28. odb.mql("create class if not exists " + clsname + "()");
  29. }
  30. pclsname = clsname;
  31. clsname += "/" + cns[cns.length - 1];
  32. // 提取现有类的字段信息
  33. clsexist = false;
  34. clsfields = {};
  35. try {
  36. fieldslist = odb.classfields(clsname);
  37. for (var fi = 0; fi < fieldslist.length; fi++) {
  38. fld = fieldslist[fi];
  39. fname = fld.name;
  40. if (/^\w+\:.*/.test(fname)) {
  41. fname = fname.replace(/^\w+\:/, "");
  42. }
  43. if (fname && fld.ftype) {
  44. clsfields[fname] = {
  45. iskey: fld.iskey,
  46. ftype: fld.ftype,
  47. };
  48. }
  49. }
  50. clsexist = true;
  51. } catch(e) {}
  52. if (!clsexist) {
  53. try {
  54. fieldslist = odb.classfields(pclsname);
  55. for (var fi = 0; fi < fieldslist.length; fi++) {
  56. fld = fieldslist[fi];
  57. fname = fld.name;
  58. if (/^\w+\:.*/.test(fname)) {
  59. fname = fname.replace(/^\w+\:/, "");
  60. }
  61. if (fname && fld.ftype) {
  62. clsfields[fname] = {
  63. iskey: fld.iskey,
  64. ftype: fld.ftype,
  65. };
  66. }
  67. }
  68. } catch(e) {}
  69. }
  70. output.clsfields = clsfields;
  71. // 通过参数确定的字段类型信息
  72. fields = input.fields;
  73. if (!fields) {
  74. fields = {};
  75. }
  76. // 字段名映射,参数中指定的字段名均为JSON对象中的属性名,默认将 camelStyle 转换为 snake_style
  77. fieldmap = input.fieldmap;
  78. if (!fieldmap) {
  79. fieldmap = {};
  80. }
  81. // 反向字段名映射,类中的字段名映射为JSON对象中的属性名
  82. xfieldmap = {};
  83. // 类中的字段名列表,用于排序
  84. xfieldslist = [];
  85. // 类字段类型信息
  86. xfields = {};
  87. xpks = [];
  88. for (var jk in input.data) {
  89. xk = fieldmap[jk];
  90. // 通过参数确定的字段类型信息
  91. if (!xk) {
  92. // 默认将 camelStyle 转换为 snake_style
  93. xk = "j_"; // 区别于其它字段,自动创建的字段以 j_ 开头
  94. for (var i = 0; i < jk.length; i++) {
  95. if (jk[i] >= 'A' && jk[i] <= 'Z') {
  96. xk += "_" + jk[i].toLowerCase();
  97. } else {
  98. xk += jk[i];
  99. }
  100. }
  101. fieldmap[jk] = xk;
  102. }
  103. xfieldslist.push(xk);
  104. xfieldmap[xk] = jk;
  105. dt = fields[jk];
  106. if (dt && dt.indexOf(",key") > 0) {
  107. dt = dt.replace(",key", "");
  108. xpks.push(xk);
  109. }
  110. switch (dt) {
  111. case "date":
  112. case "time":
  113. case "datetime":
  114. dt = "timestamp";
  115. break;
  116. case "int":
  117. case "integer":
  118. dt = "bigint";
  119. break;
  120. case "number":
  121. case "float":
  122. dt = "double";
  123. break;
  124. case "text":
  125. dt = "text";
  126. break;
  127. case "string":
  128. dt = "varchar";
  129. break;
  130. case "boolean":
  131. dt = "boolean";
  132. break;
  133. }
  134. if (!dt) {
  135. // 没有明确定义的字段类型
  136. // 根据数据判断类型
  137. dt = "varchar";
  138. d = input.data[jk];
  139. if (d || d == "" || d == 0 || d == false) {
  140. switch (typeof(d)) {
  141. case 'object':
  142. // 转为text
  143. dt = "text";
  144. break;
  145. case 'number':
  146. // 是否为整数
  147. if ((""+d).indexOf(".")<0) {
  148. dt = "bigint";
  149. } else {
  150. dt = "double";
  151. }
  152. break;
  153. case 'boolean':
  154. dt = "boolean";
  155. break;
  156. case 'string':
  157. default:
  158. // 是否为日期时间
  159. if (/_time/.test(xk) || /_date/.test(xk)) {
  160. dt = "timestamp";
  161. } else {
  162. dt = "varchar";
  163. }
  164. break;
  165. }
  166. } else {
  167. if (/_time/.test(xk) || /_date/.test(xk)) {
  168. dt = "timestamp";
  169. } else {
  170. dt = "varchar";
  171. }
  172. }
  173. }
  174. xfields[xk] = dt;
  175. }
  176. output.xfields = xfields;
  177. if (!clsexist) {
  178. // 类不存在,自动创建类
  179. mql = "create class if not exists " + clsname + "(";
  180. indexes = "indexes(";
  181. for (var fi = 0; fi < xfieldslist.length; fi++) {
  182. xk = xfieldslist[fi];
  183. if (xk in {"id":"", "class":"", "name":"", "day":"", "tags":"", "vtime":""}) {
  184. throw("内部使用字段名 " + xk + ",需要映射成其它名称");
  185. }
  186. if (clsfields[xk] && clsfields[xk].ftype != xfields[xk]) {
  187. throw ("类继承字段 "+ xk +" 信息不一致,"+clsfields[xk].ftype + "!=" + xfields[xk]+",需手动干预");
  188. }
  189. mql += fi==0 ? "\n": ",\n";
  190. mql += xk + " " + xfields[xk];
  191. if (fi > 0) {
  192. indexes += ",";
  193. }
  194. indexes += xk;
  195. }
  196. indexes += ")";
  197. mql += ",\n" + indexes;
  198. if (xpks.length > 0) {
  199. mql += ",\n";
  200. mql += "keys(";
  201. for (var pki = 0; pki < xpks.length; pki++) {
  202. if (pki > 0) {
  203. mql += ",";
  204. }
  205. mql += xpks[pki];
  206. }
  207. mql += ")";
  208. }
  209. mql += "\n";
  210. mql += ")";
  211. if (input.clsoption) {
  212. mql += input.clsoption;
  213. }
  214. odb.mql(mql);
  215. output = {mql:mql};
  216. } else {
  217. // 类已存在,检查主键信息是否存在
  218. for (var pki = 0; pki < xpks.length; pki++) {
  219. xk = xpks[pki];
  220. if (!clsfields[xk] || !clsfields[xk].iskey) {
  221. throw ("已经存在同名类主键 "+ xk +" 信息不一致,需手动干预");
  222. }
  223. }
  224. // 追加字段
  225. mql = "alter class " + clsname + " add index column";
  226. addn = 0;
  227. for (var fi = 0; fi < xfieldslist.length; fi++) {
  228. xk = xfieldslist[fi];
  229. if (!clsfields[xk]) {
  230. mql += (addn == 0)?" ":", ";
  231. mql += xk + " " + xfields[xk];
  232. addn++;
  233. } else if (clsfields[xk].ftype != xfields[xk]) {
  234. throw ("已经存在同名类字段 "+ xk +" 信息不一致,需手动干预");
  235. }
  236. }
  237. if (addn > 0) {
  238. odb.mql(mql);
  239. output = {mql:mql};
  240. }
  241. }
  242. return output
  243. }
  244. // 根据 JSON 数据生成导入脚本
  245. function generateJsonImporterJS(input) {
  246. var output = {};
  247. // 参数检查
  248. if (!input.classname) { // like /cncc/itil/project
  249. throw ("需要指定classname");
  250. }
  251. if (input.classname[0] != "/") { // like /cncc/itil/project
  252. throw ("classname必须以 / 开头");
  253. }
  254. sjsfn = input.jsfilename;
  255. if (!sjsfn) {
  256. sjsfn = "/script" + input.classname; // like /script/cncc/itil/project
  257. }
  258. if (sjsfn.substring(0, 8) != "/script/") {
  259. throw ("jsfilename必须以 /script/ 开头");
  260. }
  261. sjsfn = sjsfn.replace(/\.js$/, "");
  262. output.file = sjsfn;
  263. dtm = new Date().toJSON();
  264. mql = "insert into " + input.classname + " (\n";
  265. mql_values = ") values (\n";
  266. mql_end = ")";
  267. values = "";
  268. fieldmap = input.fieldmap;
  269. if (!fieldmap) {
  270. fieldmap = {};
  271. }
  272. xfieldmap = {};
  273. xfields = [];
  274. clsfields = {};
  275. try {
  276. fieldslist = odb.classfields(input.classname);
  277. for (var fi = 0; fi < fieldslist.length; fi++) {
  278. fld = fieldslist[fi];
  279. fname = fld.name;
  280. if (/^\w+\:.*/.test(fname)) {
  281. fname = fname.replace(/^\w+\:/, "");
  282. }
  283. if (fname && fld.ftype) {
  284. clsfields[fname] = {
  285. iskey: fld.iskey,
  286. ftype: fld.ftype,
  287. };
  288. }
  289. }
  290. } catch(e) {}
  291. for (var k in input.data) {
  292. xk = fieldmap[k];
  293. if (!xk) {
  294. xk = "j_"; // 区别于其它字段,自动创建的字段以 j_ 开头
  295. for (var i = 0; i < k.length; i++) {
  296. if (k[i] >= 'A' && k[i] <= 'Z') {
  297. xk += "_" + k[i].toLowerCase();
  298. } else {
  299. xk += k[i];
  300. }
  301. }
  302. fieldmap[k] = xk;
  303. }
  304. xfields.push(xk);
  305. xfieldmap[xk] = k;
  306. }
  307. xfields.sort();
  308. fsep = ",";
  309. for (var i = 0; i < xfields.length; i++) {
  310. if (i == xfields.length - 1) {
  311. fsep = "";
  312. }
  313. xk = xfields[i];
  314. k = xfieldmap[xk];
  315. mql += xk + fsep + "\n";
  316. mql_values += "?" + fsep + "\n";
  317. values += " ";
  318. v = input.data[k];
  319. if (!clsfields[xk]) {
  320. throw("字段不存在", xk)
  321. }
  322. switch (clsfields[xk].ftype) {
  323. case "text":
  324. case "varchar":
  325. if (typeof(v) == "object") {
  326. values += "JSON.stringify(";
  327. values += "input." + k + ", \" \", 4)" + fsep;
  328. values += JSON.stringify(v, " ", 4).replace(/^/mg, " // ").replace(/ /, " ");
  329. } else {
  330. values += "\"\"+";
  331. values += "input." + k + fsep;
  332. values += (""+v).replace(/^/mg, " // ").replace(/ /, " ");
  333. }
  334. break;
  335. default:
  336. values += "input." + k + fsep;
  337. values += (""+v).replace(/^/mg, " // ").replace(/ /, " ");
  338. }
  339. values += "\n ";
  340. }
  341. mql += mql_values + mql_end;
  342. values = "\n " + values;
  343. datainfo = "{";
  344. datacheck = "";
  345. if (input.mustfield) {
  346. ids = input.mustfield.split(",");
  347. for (var i = 0; i < ids.length; i++) {
  348. id = ids[i];
  349. if (i > 0) {
  350. datacheck += "\n ";
  351. }
  352. datacheck += "if (!input." + id + ") {\n ";
  353. datacheck += " throw (\"输入参数必须为对象,且指定属性" + id + "\");\n ";
  354. datacheck += "}";
  355. if (i == 0) {
  356. datainfo += "\n ";
  357. } else {
  358. datainfo += ",\n ";
  359. }
  360. datainfo += " " + id + ": input." + id;
  361. }
  362. }
  363. datainfo += "\n ";
  364. datainfo += "}";
  365. importjs = dfs.read("/script/matrix/utils/ajs/JsonImporter.template.js");
  366. importjs = importjs.replace(/___istesting___/mg, input.istesting);
  367. importjs = importjs.replace(/___classname___/mg, input.classname);
  368. importjs = importjs.replace(/___datetime_now___/mg, dtm);
  369. importjs = importjs.replace(/if\s*\(\s*___datacheck___\s*\)\s*\{.*\}/mg, datacheck);
  370. importjs = importjs.replace(/___mql___/mg, mql);
  371. importjs = importjs.replace(/___values___/mg, values);
  372. importjs = importjs.replace(/___datainfo___/mg, datainfo);
  373. output.content = importjs;
  374. dfs.write(sjsfn + ".js", importjs);
  375. return output
  376. }
  377. // 激活脚本,生成的脚本文件需要激活后才能生效
  378. function activeServerJS(jsfilename) {
  379. result = {};
  380. calljsfp = encodeURIComponent(jsfilename.replace(/\/script/, ""));
  381. http.do("POST",
  382. cfg.server+"/fs/tolocal/script"+calljsfp+"?issys=true",
  383. {"Authorization": "Basic "+cfg.author},
  384. '',
  385. function(response){
  386. // success func
  387. ret = response.data;
  388. if (ret.message) {
  389. result = ret.message;
  390. } else {
  391. result = ret;
  392. }
  393. },
  394. function(response){
  395. // error func
  396. result.error = response.data;
  397. });
  398. return result;
  399. }
  400. // 验证测试执行脚本
  401. function runServerJS(jsfilename, data) {
  402. result = {};
  403. reqinput = encodeURIComponent(base64.encode(JSON.stringify(data)));
  404. calljsfp = encodeURIComponent(jsfilename.replace(/\/script/, ""));
  405. http.do("POST",
  406. cfg.server+"/script/exec/js?filepath="+calljsfp+"&input="+reqinput,
  407. {"Authorization": "Basic "+cfg.author},
  408. '',
  409. function(response){
  410. // success func
  411. ret = response.data;
  412. if (ret.message) {
  413. result = ret.message;
  414. } else {
  415. result = ret;
  416. }
  417. },
  418. function(response){
  419. // error func
  420. result.error = response.data;
  421. });
  422. return result;
  423. }