DBModule.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. const mysql = require('mysql');
  2. const sys = require('../config/sys_test');
  3. const pool = mysql.createPool({
  4. connectionLimit: 1,
  5. connectTimeout: 60 * 60 * 1000,
  6. host: sys.mysql.host,
  7. user: sys.mysql.user,
  8. password: sys.mysql.pwd,
  9. database: sys.mysql.db
  10. });
  11. class DBModule {
  12. constructor(args = {}) {
  13. Object.keys(args).forEach(key => {
  14. this[key] = args[key];
  15. })
  16. }
  17. /**
  18. * 使用连接池中已有的连接执行sql脚本
  19. * @param {string} sql sql脚本
  20. * @param {array} args sql中的参数
  21. * @return {promise}
  22. */
  23. _query(sql, args = []) {
  24. return new Promise((resolve, reject) => {
  25. pool.getConnection((err, connection) => {
  26. if (err) return reject(err);
  27. if (sys.debug) {
  28. console.log(`run ${sql} \narray ${args.map(item=> `${item} type: ${typeof item}\n`)}`)
  29. }
  30. connection.query(sql, args, (err, result) => {
  31. if (err) {
  32. reject(err);
  33. } else {
  34. resolve(result);
  35. }
  36. connection.release();
  37. });
  38. });
  39. });
  40. }
  41. /**
  42. * 执行对象插入数据库操作
  43. * @return {promise}
  44. */
  45. insert() {
  46. let sql, {attrs, vals, err} = DBModule.getDBModuleArgs(this);
  47. if (err) {
  48. throw `object ${this.constructor.toString()} lack necessary field (table, fields)`;
  49. }
  50. sql = `insert into \`${this.table}\`(${attrs.join(',')}) values(${vals.map(()=>'?')})`;
  51. return this._query(sql, vals);
  52. }
  53. /**
  54. * 执行对象更新映射到数据库操作,对象必须存在有效的主键
  55. * @return {promise}
  56. */
  57. update() {
  58. let sql, setFields, attrs, vals, err;
  59. if (this[this.primary] === undefined || this[this.primary] === null) {
  60. throw `object ${this.constructor.toString()} ${this.primary} is ${this[this.primary]}`;
  61. }
  62. ({attrs, vals, err} = DBModule.getDBModuleArgs(this));
  63. if (err) {
  64. throw `object ${this.constructor.toString()} lack necessary field (table, fields)`;
  65. }
  66. vals.push(this[this.primary]);
  67. setFields = attrs.map(attr=>`${attr}=?`);
  68. sql = `update \`${this.table}\` set ${setFields.join(',')} where ${this.primary}=?`;
  69. return this._query(sql, vals);
  70. }
  71. /**
  72. * 查看某条件的数据是否存在
  73. * @return {promise}
  74. */
  75. exists() {
  76. let fields, {attrs, vals, err} = DBModule.getDBModuleArgs(this);
  77. if (err) {
  78. throw `object ${this.constructor.toString()} lack necessary field (table, fields)`;
  79. }
  80. fields = attrs.map(attr=>` ${attr}=? `);
  81. fields.push(' 1=1 ');
  82. return this._query(`select count(*) as count from \`${this.table}\` where ${fields.join(' and ')}`, vals)
  83. .then(result => {
  84. return result[0].count !== 0
  85. });
  86. }
  87. /**
  88. * 删除数据库中单行操作,对象必须存在有效的主键
  89. * @return {promise}
  90. */
  91. delete() {
  92. let sql, vals;
  93. if (this[this.primary] === undefined || this[this.primary] === null) {
  94. throw `object ${this.constructor.toString()} ${this.primary} is ${this[this.primary]}`;
  95. } else if (DBModule.getDBModuleArgs(this).err) {
  96. throw `object ${this.constructor.toString()} lack necessary field (table, fields)`;
  97. }
  98. vals = [this[this.primary]]
  99. sql = `delete from \`${this.table}\` where ${this.primary}=?`;
  100. return this._query(sql, vals);
  101. }
  102. /**
  103. * 查询该对象表中的数据
  104. * @param connect 多字段要连接字符 如 and or
  105. * @param start 分页时开始位置
  106. * @param limit 分页时要获取的条数
  107. * @param afterAgs 要附加的参数
  108. * @return {promise}
  109. */
  110. query({connect = DBModule.AND, start = 0, limit, sql} = {}, beforeAgs) {
  111. let conneSql = '', fields, {attrs, vals, err} = DBModule.getDBModuleArgs(this);
  112. if (err) {
  113. throw `object ${this.constructor.toString()} lack necessary field (table, fields)`;
  114. } else if (connect !== DBModule.AND && connect !== DBModule.OR) {
  115. throw `query functiton connect args must be DBModule.AND or DBModule.OR`;
  116. }
  117. if (Number.isFinite(Number(this[this.primary]))) {
  118. attrs.push(this.primary);
  119. vals.push(this[this.primary]);
  120. }
  121. if (limit > 0) {
  122. conneSql = ` LIMIT ?,?`;
  123. vals.push(start);
  124. vals.push(limit);
  125. }
  126. fields = attrs.map(attr => ` \`${this.table}\`.${attr}=? `);
  127. fields.push(' 1=1 ');
  128. if (sql) {
  129. sql = `select * from (${sql}) as \`${this.table}\` `;
  130. } else {
  131. sql = `select * from \`${this.table}\` `;
  132. }
  133. sql = `${sql} where ${fields.join(connect)} ${conneSql}`
  134. if (beforeAgs && beforeAgs.length > 0) {
  135. vals = beforeAgs.concat(vals);
  136. }
  137. return this._query(sql, vals);
  138. }
  139. /**
  140. * 分页模式数据统一处理
  141. * @param {*} paging number 是否要开启分页模式
  142. * limit number 每页的条数
  143. * start number 从哪条开始读取
  144. * header string 获取表的表头
  145. * vals array sql的参数
  146. * sql string sql语句表头用{{header}}代替
  147. */
  148. paging({paging = 0, limit = 15, start = 0, sql, headers = 'header', vals = []} = {}) {
  149. let pData, pCount, conneSql = '';
  150. if (!sql) return Promise.resolve(1);
  151. if (limit > 0) {
  152. conneSql = ` LIMIT ?,?`;
  153. vals.push(start);
  154. vals.push(limit);
  155. }
  156. pData = this._query(sql.replace('{{header}}', headers) + conneSql, vals);
  157. if (paging) {
  158. pCount = this._query(sql.replace('{{header}}', 'count(*) as len'), vals);
  159. return Promise.all([pData, pCount])
  160. .then((arrs) => {
  161. return {
  162. total: arrs[1][0].len,
  163. data: arrs[0],
  164. average: limit
  165. }
  166. });
  167. } else {
  168. return pData;
  169. }
  170. }
  171. /**
  172. * 检测对象是否符合DBModule要求并获取对象能执行_query的参数
  173. * @param {object} dbModule要检测的对象
  174. * @return {object} fileds: err attrs vals
  175. * {boolean} err 是否符合DBModule的要求
  176. * {array} attrs 要进行数据库操作的字段
  177. * {array} vals 要进行数据库操作的字段对应的值
  178. */
  179. static getDBModuleArgs(dbModule) {
  180. if(!((dbModule.table && dbModule.table.length > 0) &&
  181. (dbModule.fields && dbModule.fields instanceof Array && dbModule.fields.length > 0)
  182. )) {
  183. return {err: true};
  184. }
  185. let attrs = [], vals = [];
  186. for (let field of dbModule.fields) {
  187. if (dbModule[field] !== undefined) {
  188. attrs.push('`'+field+'`');
  189. vals.push(dbModule[field]);
  190. }
  191. }
  192. return {attrs, vals, err: false};
  193. }
  194. static get AND() {
  195. return 'and';
  196. }
  197. static get OR() {
  198. return 'or';
  199. }
  200. static get HOT() {
  201. return 'hot';
  202. }
  203. static get SOAR() {
  204. return 'soar';
  205. }
  206. }
  207. module.exports = exports = DBModule;