JsonImporterFuncs.js 16 KB

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