mysqldb.ts 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /**
  2. * @Author HonorLee (dev@honorlee.me)
  3. * @Version 1.0 (2018-05-04)
  4. * @License MIT
  5. */
  6. import Mysql = require('mysql');
  7. interface DBClient{
  8. getConnection:(callback:(err:Error,connection:any)=>void|null)=>void;
  9. }
  10. //数据对象
  11. export class MysqlDB{
  12. private _pool:DBClient;
  13. constructor(option:DBOption){
  14. this._pool = new MysqlPool().create(option);
  15. }
  16. public query(queryStr:string,callback:(err:Error,ret:any,fields:any)=>void){
  17. this._pool.getConnection((err,con)=>{
  18. if(err) return callback(err,null,null);
  19. con.query(queryStr,(err:Error, ret:any, fields:any)=>{
  20. if(err){
  21. LOGGER.error(`MysqlDB: "${queryStr}" error`);
  22. if(err.stack) LOGGER.error(err.stack);
  23. }
  24. con.release();
  25. if(callback) callback(err,ret,fields);
  26. });
  27. });
  28. }
  29. public querySync(queryStr:string){
  30. return new Promise((resolve)=>{
  31. this._pool.getConnection((err,con)=>{
  32. if(err){
  33. if(err.stack) LOGGER.error(err.stack);
  34. return resolve({err:err,data:[]});
  35. }
  36. con.query(queryStr,(err:Error, ret:any, fields:any)=>{
  37. con.release();
  38. if(err){
  39. LOGGER.error(`MysqlDB: "${queryStr}" error`);
  40. if(err.stack) LOGGER.error(err.stack);
  41. return resolve({err:err,data:[]});
  42. }
  43. resolve({err:null,data:ret});
  44. });
  45. });
  46. })
  47. }
  48. async update(tablename:string,updateObj:any,whereObj:any){
  49. if(!tablename || !updateObj) return;
  50. let whereRule="";
  51. const updateRule = MysqlUtil.objToKVString(updateObj);
  52. if(whereObj){
  53. whereRule = ` where ${MysqlUtil.objToKVString(whereObj,' and ')}`;
  54. }
  55. const sqlStr = `update ${tablename} set ${updateRule} ${whereRule}`;
  56. return await this.querySync(sqlStr);
  57. }
  58. async select(tablename:string,queryField?:Array<string>|null,whereObj?:any){
  59. if(!tablename){
  60. const err = new Error("Missing table name")
  61. if(err.stack) LOGGER.error(err.stack);
  62. return {err:err,data:null};
  63. }
  64. let queryStr = "*",whereStr = "";
  65. if(queryField) queryStr = queryField.join(",");
  66. if(whereObj) whereStr = ` where ${MysqlUtil.objToKVString(whereObj,' and ')}`;
  67. const sql = `select ${queryStr} from ${tablename} ${whereStr}`;
  68. return await this.querySync(sql);
  69. }
  70. async insert(tablename:string,insertData:any){
  71. if(!tablename){
  72. const err = new Error("Missing table name")
  73. if(err.stack) LOGGER.error(err.stack);
  74. return {err:err,data:null};
  75. }
  76. if(!insertData){
  77. const err = new Error("Missing insertData")
  78. if(err.stack) LOGGER.error(err.stack);
  79. return {err:err,data:null};
  80. }
  81. let sql = `insert into ${tablename} `;
  82. if(insertData.constructor == Object){
  83. sql += `set ${MysqlUtil.objToKVString(insertData)}`;
  84. }else if(insertData.constructor == Array && insertData.length>0 && insertData[0].constructor == Object){
  85. const fields = Object.keys(insertData[0]);
  86. const values = [];
  87. for(const data of insertData){
  88. const valueArr = [];
  89. for(const key of fields){
  90. if(data[key] != null || data[key] != undefined){
  91. if(data[key].constructor == String){
  92. data[key] = `"${data[key]}"`;
  93. }else if(data[key].constructor == Number){
  94. data[key] = Number(data[key]);
  95. }
  96. }
  97. valueArr.push(data[key]);
  98. }
  99. values.push(`(${valueArr.join(',')})`);
  100. }
  101. for(const i in fields){
  102. fields[i] = `\`${fields[i]}\``;
  103. }
  104. sql += `(${fields.join(',')}) values ${values.join(',')}`;
  105. }else{
  106. const err = new Error("InsertData type not support")
  107. if(err.stack) LOGGER.error(err.stack);
  108. return {err:err,data:null};
  109. }
  110. return await this.querySync(sql);
  111. }
  112. }
  113. export class MysqlUtil{
  114. /**
  115. * K-V数据转为Sql语句结构
  116. **/
  117. public static objToKVString(obj:any,joinStr?:string,keyPrefix?:string){
  118. const strArr:Array<string> = [];
  119. const keys = Object.keys(obj);
  120. let _extraSql = '',_extraLink = '';
  121. keyPrefix = keyPrefix?`${keyPrefix}.`:'';
  122. if(keys.length>0){
  123. keys.forEach(key =>{
  124. let v = obj[key];
  125. if(key=='_extra'){
  126. if(Array.isArray(v)){
  127. _extraSql = v.join(joinStr);
  128. }else if(v.constructor == Object){
  129. if(v.sql){
  130. _extraSql = v.sql;
  131. _extraLink = v.link||'and';
  132. }
  133. }else{
  134. _extraSql = v;
  135. }
  136. }else{
  137. if(typeof(v)=='string'){
  138. if(v[0]=='='){
  139. v = v.substring(1,-1);
  140. }else{
  141. if(!(v.substr(0,1)=="'" && v.substr(-1,1)=="'") && !(v.substr(0,1)=='"' && v.substr(-1,1)=='"')){
  142. v = `"${v}"`;
  143. }else{
  144. v = v;
  145. }
  146. }
  147. }
  148. keyPrefix = keyPrefix?`${keyPrefix}`:'';
  149. const sqlkey = `${keyPrefix}\`${key}\``;
  150. strArr.push(`${sqlkey}=${v}`);
  151. }
  152. })
  153. const sql = `${strArr.join(joinStr||',')} ${_extraLink} ${_extraSql}`;
  154. return sql;
  155. }else{
  156. return '';
  157. }
  158. }
  159. /**
  160. * 自动处理数据模型与数据,返回处理后符合模型的数据对象,包含数据安全性处理
  161. * @param module 数据模型
  162. * @param data 待处理数据
  163. * @param filter 自动过滤非模型字段数据(可选,默认不过滤)
  164. * @prarm reverse 反向处理,由写入处理变为取出处理,并自动根据模型字段类型进行可视化处理(可选,默认写入状态)
  165. **/
  166. public static analyzeFields(module:any,data:any,filter?:boolean,reverse?:boolean){
  167. const outData:AnyKeyString = {};
  168. Object.keys(data).forEach(key=>{
  169. if(module[key]!=undefined && data[key]!=null){
  170. let value = data[key];
  171. switch(module[key].type){
  172. case String:
  173. value = String(value);
  174. if(!reverse) value = Mysql.escape(value)
  175. break;
  176. case Number:
  177. value = Number(value)||0;
  178. break;
  179. case 'Date_Timestamp':
  180. case 'DateTime_Timestamp':
  181. case 'Time_Timestamp':
  182. value = Number(value)||0;
  183. if(value>0 && reverse){
  184. if(module[key].type=='Date_Timestamp') value = Moment.unix(value).format('YYYY-MM-DD');
  185. if(module[key].type=='DateTime_Timestamp') value = Moment.unix(value).format('YYYY-MM-DD HH:mm:ss');
  186. if(module[key].type=='Time_Timestamp') value = Moment.unix(value).format('HH:mm:ss');
  187. }
  188. break;
  189. }
  190. if(module[key].reverseKey && reverse) key = module[key].reverseKey;
  191. outData[key] = value;
  192. }else{
  193. if(!filter) outData[key] = data[key];
  194. }
  195. })
  196. return outData;
  197. }
  198. public static escape(value:any){
  199. return Mysql.escape(value);
  200. }
  201. public static createPageLimit(page?:number,page_size?:number,orderField?:string){
  202. page = page||0;
  203. page_size = page_size||10;
  204. let sql = ``;
  205. if(orderField) sql += `ORDER BY \`${orderField}\` `;
  206. sql += `LIMIT ${page*page_size},${page_size}`;
  207. return sql;
  208. }
  209. public static createOrderBy(order_filed?:string,order_desc?:boolean){
  210. let orderStr = '';
  211. if(order_filed){
  212. orderStr = `order by \`${order_filed}\``;
  213. if(order_desc) orderStr += ' desc';
  214. }
  215. return orderStr;
  216. }
  217. }
  218. //连接池
  219. class MysqlPool{
  220. private _option:DBOption|null = null;
  221. private _pool:any;
  222. public Client:DBClient|null = null;
  223. create(option:DBOption):DBClient{
  224. this._option = option;
  225. this._pool = Mysql.createPool(option);
  226. this.Client = {
  227. getConnection:(callback)=>{
  228. if(!this._pool) throw new Error("Mysql pool not created!");
  229. if(!callback || typeof(callback)!='function') throw new Error("Mysql pool get connection lost callback!");
  230. this._pool.getConnection((err:any,connection:any)=>{
  231. callback(err,connection);
  232. });
  233. }
  234. }
  235. return this.Client;
  236. }
  237. }