UNPKG

yoyomysql

Version:

一个链式连接mysql数据库的扩展包

917 lines (916 loc) 32.7 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const promise_1 = __importDefault(require("mysql2/promise")); const sql_highlight_1 = require("sql-highlight"); function isOperator(value) { const operators = ['=', '<>', '<', '<=', '>', '>=', 'LIKE', 'IN', 'NOT IN', 'IS NULL', 'IS NOT NULL', 'BETWEEN', 'NOT BETWEEN', 'REGEXP', 'NOT REGEXP', 'NOT LIKE']; value = value.toUpperCase(); // 转成大写 return operators.includes(value); } function formatValue(value) { if (typeof value === 'string') { return `'${value}'`; // 如果是字符串,在其前后添加单引号 } else if (typeof value === 'number') { return value; // 如果是数字,直接返回 } throw new Error('The value passed in is of the wrong type and can only be a string or a number'); } /** * 生成指定数量的占位符 * @param arr 数组 * @param str 默认填充值 * @param decollator 分隔符 * @returns */ function fillStr(arr, str = '?', decollator = ',') { return Array(arr.length).fill(str).join(decollator); } /** * 判断类型 * @param {Any} data * @returns {string} 小写 */ function isTypeof(data) { let type = Object.prototype.toString.call(data); return type.replace(/^\[object (.+)\]$/, '$1').toLowerCase(); } function isObject(data) { return typeof data === 'object' && data !== null && !Array.isArray(data); } /** * 判断是否是二维数组 * @param {Array} arr 数组 * @returns {boolean} */ function isTwoArray(arr) { return Array.isArray(arr) && arr.every(Array.isArray); } /** * 判断是否是数组对象 * @param {Array} arr 数组 * @returns {boolean} */ function isArrayObj(arr) { return Array.isArray(arr) && arr.every(item => isObject(item)); } /** * 判断是否是单纯的数组数据 * @param {Array} arr 数组 * @returns {boolean} */ function isArrayData(arr) { return Array.isArray(arr) && arr.every(item => typeof item !== 'object'); } class YoyoMysql { /** * 创建连接池 * @param config mysql.PoolOptions * @returns */ static createPool(config) { if (YoyoMysql._POOL) return YoyoMysql; // 创建连接池,设置连接池的参数 YoyoMysql._POOL = promise_1.default.createPool(config); return YoyoMysql; } /** * 设置表名 * @param table 表名 * @returns */ static table(table) { return new YoyoMysqlClass(this._POOL).table(table); } /** * 开启事务(在(执行结束-提交)或者(报错时-回滚)自动释放连接) * @param callback 回调函数 * @param isError 是否开启错误信息抛出(勾选后错误将直接抛出,需要外围拦截) */ static beginTransaction(callback_1) { return __awaiter(this, arguments, void 0, function* (callback, isError = false) { const conn = yield YoyoMysql._POOL.getConnection(); // 获取一个连接 yield conn.beginTransaction(); // 开始事务 try { yield callback({ table: (table) => new YoyoMysqlClass(conn).table(table), query: (...args) => conn.query(...args), execute: (...args) => conn.execute(...args) }); // 执行回调函数 yield conn.commit(); // 提交事务 } catch (error) { yield conn.rollback(); // 回滚事务 YoyoMysql._POOL.releaseConnection(conn); // 释放连接 if (isError) throw error; // 抛出错误 return false; } YoyoMysql._POOL.releaseConnection(conn); // 释放连接 return true; }); } /** * 获取一条连接(在执行结束或者报错时自动释放连接) * @param callback 回调函数 */ static getOneConnection(callback) { return __awaiter(this, void 0, void 0, function* () { const conn = yield YoyoMysql._POOL.getConnection(); // 获取一个连接 try { const result = yield callback({ table: (table) => new YoyoMysqlClass(conn).table(table), query: (...args) => conn.query(...args), execute: (...args) => conn.execute(...args) }); // 执行回调函数 YoyoMysql._POOL.releaseConnection(conn); // 释放连接 return result; } catch (error) { YoyoMysql._POOL.releaseConnection(conn); // 释放连接 throw error; // 抛出错误 } }); } static query(sql, values) { return __awaiter(this, void 0, void 0, function* () { return yield YoyoMysql._POOL.query(sql, values); }); } static execute(sql, values) { return __awaiter(this, void 0, void 0, function* () { return yield YoyoMysql._POOL.execute(sql, values); }); } /** * 设置额外指定连接池 * @param pool 连接池 */ static setPool(pool) { YoyoMysql._POOL = pool; } } /** 是否显示sql语句 */ YoyoMysql.isShowSql = false; /** * 设置打印sql语句的方法 * @param sql sql语句 * @param highlightSQL 高亮sql方法 */ YoyoMysql.printMethod = (sql, highlightSQL) => { console.log('YoyoMysql:', highlightSQL(sql)); }; exports.default = YoyoMysql; /** * YoyoMysql 连接方式默认采用 mysql2连接池方式处理 */ class YoyoMysqlClass { constructor(link) { this._fields = []; this._clogic = 'AND'; // 当前条件逻辑 this._where = []; this._group = new Set([]); this._having = ''; this._order = []; this._join = []; this._link = link; // 设置指定连接 } /** * 设置表名 * @param table 表名 * @returns */ table(table) { if (/^(\w+)\s+(as\s+)?(\w+)$/i.test(table.trim())) { this._table = table.trim().replace(/^(\w+)\s+(as\s+)?(\w+)$/i, (...args) => `\`${args[1]}\` AS ${args[3]}`); } else { this._table = `\`${table}\``; // 设置表名 } return this; } field(field) { if (Array.isArray(field)) { field.forEach((f) => this._fields.push(f)); return this; } this._fields.push(field); // 添加到字段集合 return this; } order(...args) { var _a; if (args.length === 1) { if (typeof args[0] === 'object') { for (const f in args[0]) { const order = args[0][f]; this._order.push({ field: f, order }); } return this; } } if (args.length === 2) { if (typeof args[0] === 'string') { args[1] = (_a = args[1]) !== null && _a !== void 0 ? _a : 'ASC'; this._order.push({ field: args[0], order: args[1] }); return this; } } throw new Error('The order method can only accept one or two parameters'); } group(args) { if (Array.isArray(args)) { args.forEach((field) => { this._group.add(field); }); return this; } this._group.add(args); // 添加到分组集合 return this; } /** * 过滤由 GROUP BY 产生的结果集中的重复记录 * @param where 条件(字符串自行组合) * @returns */ having(where) { if (this._group.size === 0) throw new Error('The group method must be called before the having method'); this._having = where; return this; } limit(...args) { if (args.length === 1) { this._limit = args[0]; return this; } if (args.length === 2) { this._limit = [args[0], args[1]]; return this; } throw new Error('The limit method can only accept one or two parameters'); } /** * 多表联查[左查询](LEFT JOIN) * @param table 表名 * @param where 条件(字符串自行组合) * @returns */ leftJoin(table, where) { if (/^(\w+)\s+(as\s+)?(\w+)$/i.test(table.trim())) { table = table.trim().replace(/^(\w+)\s+(as\s+)?(\w+)$/i, (...args) => `\`${args[1]}\` AS ${args[3]}`); } else { table = `\`${table}\``; // 设置表名 } this._join.push({ type: 'LEFT', table, where }); return this; } /** * 多表联查[右查询](RIGHT JOIN) * @param table 表名 * @param where 条件(字符串自行组合) * @returns */ rightJoin(table, where) { if (/^(\w+)\s+(as\s+)?(\w+)$/i.test(table.trim())) { table = table.trim().replace(/^(\w+)\s+(as\s+)?(\w+)$/i, (...args) => `\`${args[1]}\` AS ${args[3]}`); } else { table = `\`${table}\``; // 设置表名 } this._join.push({ type: 'RIGHT', table, where }); return this; } /** * 多表联查[等值查询](INNER JOIN) * @param {string} table 表 * @param {string} where 条件 */ join(table, where) { if (/^(\w+)\s+(as\s+)?(\w+)$/i.test(table.trim())) { table = table.trim().replace(/^(\w+)\s+(as\s+)?(\w+)$/i, (...args) => `\`${args[1]}\` AS ${args[3]}`); } else { table = `\`${table}\``; // 设置表名 } this._join.push({ type: 'INNER', table, where }); return this; } /** * 多表联查[一个匹配填充null返回](FULL JOIN) * @param {string} table 表 * @param {string} where 条件 */ fullJoin(table, where) { if (/^(\w+)\s+(as\s+)?(\w+)$/i.test(table.trim())) { table = table.trim().replace(/^(\w+)\s+(as\s+)?(\w+)$/i, (...args) => `\`${args[1]}\` AS ${args[3]}`); } else { table = `\`${table}\``; // 设置表名 } this._join.push({ type: 'FULL', table, where }); return this; } /** * where集合处理方法(包含where的AND和OR) * @param field 字段名 * @param args 参数 * @returns */ _whereComposite(field, ...args) { if (Array.isArray(field)) { // 数组 field.forEach((item) => { this._whereComposite(item[0], item[1], item[2]); }); return this; } else if (typeof field === 'string' && typeof args[0] === 'string' && typeof args[1] !== 'undefined') { args[0] = args[0].toUpperCase(); // 转成大写 if (!isOperator(args[0])) throw new Error('operator error'); if (!/\./.test(field)) field = `\`${field}\``; //如果字段没有点就加上反引号 const _where = { type: this._clogic, // 当前条件逻辑 AND OR data: { subquery: false, //不是子查询 field, // 字段名 operator: args[0], // 操作符 value: args[1], // 值 param: [] //数组参数 } }; if (Array.isArray(args[1])) { // 值是数组 if (args[0] !== 'IN' && args[0] !== 'NOT IN') throw new Error('The operator should be IN or NOT IN when the array is passed.'); _where.data.value = `(${fillStr(args[1])})`; _where.data.param = args[1]; //参数列表 } this._where.push(_where); return this; } else if (typeof field === 'string' && (typeof args[0] === 'string' || typeof args[0] === 'number' || typeof args[0] === 'object') && typeof args[1] === 'undefined') { if (typeof args[0] === 'object') { // 把对象都分解成一一对应的(有很多个) for (const key in args[0]) { const v = args[0][key]; this._whereComposite(key, '=', v); } return this; } return this._whereComposite(field, '=', args[0]); } else if (typeof field === 'string' && typeof args[0] === 'function') { // 这里需要额外处理(因为是sql预处理和参数列表) const result = args[0](); if (!(result instanceof YoyoMysqlClass)) { throw new Error('where callback must return YoyoMysql'); } // 构建sql语句 const resultSql = result.buildSql('select'); if (!/\./.test(field)) field = `\`${field}\``; //如果字段没有点就加上反引号 // 需要将参数列表融合进来 this._where.push({ type: this._clogic, data: { subquery: true, //是子查询 field, operator: '=', value: `${resultSql.sql}`, param: resultSql.params } }); return this; } throw new Error('where params error'); } /** * 添加一条IN条件(子查询) * @param field 字段名 * @param callback 回调函数 * @returns */ whereIn(field, callback) { // 需要额外处理(需要融合sql和参数列表) const result = callback(); if (!(result instanceof YoyoMysqlClass)) { throw new Error('whereIn callback must return YoyoMysql'); } // 构建sql语句 const resultSql = result.buildSql(); if (!/\./.test(field)) field = `\`${field}\``; //如果字段没有点就加上反引号 this._where.push({ type: this._clogic, data: { subquery: true, //是子查询 field, operator: 'IN', value: `${resultSql.sql}`, param: resultSql.params } }); return this; } where(field, ...args) { // 设置当前逻辑为 AND this._clogic = 'AND'; return this._whereComposite(field, ...args); } whereOr(field, ...args) { // 设置当前逻辑为 OR this._clogic = 'OR'; // 调用 where 方法 return this._whereComposite(field, ...args); } // 结尾操作 /** * 查询指定条件的单条数据 */ find() { return __awaiter(this, void 0, void 0, function* () { this._limit = 1; // 设置限制条数 const { sql, params } = this.buildSelect(); // 构建sql语句 const [resData, fields] = yield this._link.query(sql, params); // 执行sql语句 const findData = resData[0] || null; return findData; }); } /** * 查询指定条件的数据 * @returns 返回resultSet对象 */ select() { return __awaiter(this, void 0, void 0, function* () { const { sql, params } = this.buildSelect(); // 构建sql语句 const [resData, fields] = yield this._link.query(sql, params); // 执行sql语句 return { data: resData, count: resData.length, maxCount: resData.length, fields }; }); } /** * 查询指定条件的数据 * @param page 访问的页数 * @param count 每页显示的条数 * @returns 返回resultSet对象 */ pages() { return __awaiter(this, arguments, void 0, function* (page = 1, count = 10) { if (page < 1) page = 1; if (count < 1) count = 1; return yield YoyoMysql.getOneConnection((conn) => __awaiter(this, void 0, void 0, function* () { this._fields.push('COUNT(*) as count'); // 添加count字段到最后 this._limit = 1; // 设置限制条数 const { sql, params } = this.buildSelect(); // 构建sql语句(修改的语句) const [resData, fields] = yield conn.query(sql, params); // 执行sql语句 const countData = resData[0] || { count: 0 }; // 获取总条数 const selectSite = { site: 0, maxPage: Math.ceil(countData.count / count) || 1 //最低1 }; selectSite.site = (page - 1) * count; this._fields = this._fields.slice(0, -1); // 恢复字段 this._limit = [selectSite.site, count]; // 设置limit const newSql = this.buildSelect(); // 构建sql语句 const resl = yield conn.query(newSql.sql, newSql.params); // 执行sql语句 return { data: resl[0], fields: resl[1], count: resl[0].length, maxCount: countData.count, maxPage: selectSite.maxPage, }; })); // 获取一个新的连接 }); } /** * 删除指定条件的数据 * @returns 返回ResultSetHeader对象 */ delete() { return __awaiter(this, void 0, void 0, function* () { const { sql, params } = this.buildDelete(); // 构建sql语句 const [resData] = yield this._link.execute(sql, params); // 执行sql语句 return resData; }); } /** * 插入一条或者多条数据 * @param data 数据 */ insert(data) { return __awaiter(this, void 0, void 0, function* () { const { sql, params } = this.buildInsert(data); // 构建sql语句 const [resData] = yield this._link.execute(sql, params); // 执行sql语句 return resData; }); } /** * 修改指定条件的所有数据 * @param data 数据 */ update(data) { return __awaiter(this, void 0, void 0, function* () { const { sql, params } = this.buildUpdate(data); // 构建sql语句 const [resData] = yield this._link.execute(sql, params); // 执行sql语句 return resData; }); } /** * 构建where条件 * @returns {where: string;params: any[]} */ buildWhere() { const _where = this._where; const whereGroup = []; // where分组 let minGroup = []; // 最小分组 if (_where.length == 0) return null; for (const index in _where) { const eachWhere = _where[index]; const minWhereLast = minGroup.at(-1); if (typeof minWhereLast === 'undefined') { minGroup.push(eachWhere); continue; } // 判断当前条件是否和上一个条件是同一个逻辑(相同就同个组) if (minWhereLast.type === eachWhere.type) { minGroup.push(eachWhere); continue; } // 和上个条件不是相同的需要(清空小分组添加到大分组去) if (Number(index) == _where.length - 1) { // 最后一个条件(不同但是需要添加进前面的分组里面) minGroup.push(eachWhere); } else { whereGroup.push(minGroup); minGroup = [eachWhere]; // 重置小分组(为当前的) } } // 最后一个分组需要添加到大分组去 whereGroup.push(minGroup); // 最终生成where语句 const ultimately = { where: '', params: [], }; // 最终生成的where语句 for (const index in whereGroup) { const eachGroupWhere = whereGroup[index]; const whereMinGroupSqlArr = []; // 最小分组sql语句 const whereMinGroupValArr = []; // 最小分组参数 for (const eachIndex in eachGroupWhere) { const eachWhere = eachGroupWhere[eachIndex]; // 判断是否是in数组 if (eachWhere.data.subquery) { // 子查询 whereMinGroupSqlArr.push(`${eachWhere.data.field} ${eachWhere.data.operator} (${eachWhere.data.value})`); whereMinGroupValArr.push(...eachWhere.data.param); continue; } if (eachWhere.data.param.length > 0) { whereMinGroupSqlArr.push(`${eachWhere.data.field} ${eachWhere.data.operator} (${fillStr(eachWhere.data.param)})`); whereMinGroupValArr.push(...eachWhere.data.param); continue; } whereMinGroupSqlArr.push(`${Number(eachIndex) > 0 ? ` ${eachWhere.type} ` : ''}${eachWhere.data.field} ${eachWhere.data.operator} ?`); whereMinGroupValArr.push(eachWhere.data.value); } if (Number(index) > 0) ultimately.where += ` ${eachGroupWhere[0].type} `; ultimately.where += `(${whereMinGroupSqlArr.join('')})`; ultimately.params = [...ultimately.params, ...whereMinGroupValArr]; } return ultimately; } /** * 构建Select类型的语句 */ buildSelect() { const table = this._table; const field = this._fields; const params = []; // 参数 const sqlArr = ['SELECT']; if (field.length > 0) { sqlArr.push(field.join(',')); } else { sqlArr.push('*'); } sqlArr.push(`FROM ${table}`); // 构建join条件 if (this._join.length > 0) { const joinArr = this._join.map(j => `${j.type} JOIN ${j.table} ON ${j.where}`); sqlArr.push(joinArr.join(' ')); } // 构建where条件 const resultWhere = this.buildWhere(); if (resultWhere) { sqlArr.push('WHERE', resultWhere.where); // 添加where条件 params.push(...resultWhere.params); // 添加参数 } // 构建group条件 if (this._group.size > 0) { sqlArr.push(`GROUP BY ${Array.from(this._group).join(',')}`); } // 构建having条件 if (this._having) { sqlArr.push(`HAVING ${this._having}`); } // 构建order条件 if (this._order.length > 0) { const orderArr = this._order.map(o => { let { field, order } = o; if (/^(\w+)\.(\w+)$$/.test(field)) field = field.replace(/\./g, '`.`'); return `\`${field}\` ${order}`; }); sqlArr.push(`ORDER BY ${orderArr.join(',')}`); } // 构建limit条件 if (typeof this._limit !== 'undefined') { let limitStr = ''; if (Array.isArray(this._limit)) { limitStr = `LIMIT ${this._limit[1]} OFFSET ${this._limit[0]}`; } else { limitStr = `LIMIT ${this._limit}`; } sqlArr.push(limitStr); // 添加limit条件 } /** 打印SQL */ YoyoMysql.isShowSql && logSql(sqlArr.join(' '), params); return { sql: sqlArr.join(' '), params, }; } /** * 构建Delete类型的语句 */ buildDelete() { const table = this._table; const field = this._fields; const params = []; // 参数 const sqlArr = ['DELETE']; sqlArr.push(`FROM ${table}`); // 构建join条件 if (this._join.length > 0) { const joinArr = this._join.map(j => `${j.type} JOIN ${j.table} ON ${j.where}`); sqlArr.push(joinArr.join(' ')); } // 构建where条件 const resultWhere = this.buildWhere(); if (resultWhere) { sqlArr.push('WHERE', resultWhere.where); // 添加where条件 params.push(...resultWhere.params); // 添加参数 } // 构建order条件 if (this._order.length > 0) { const orderArr = this._order.map(o => { let { field, order } = o; if (/^(\w+)\.(\w+)$$/.test(field)) field = field.replace(/\./g, '`.`'); return `\`${field}\` ${order}`; }); sqlArr.push(`ORDER BY ${orderArr.join(',')}`); } // 构建limit条件 if (typeof this._limit !== 'undefined') { let limitStr = ''; if (Array.isArray(this._limit)) { limitStr = `LIMIT ${this._limit[1]} OFFSET ${this._limit[0]}`; } else { limitStr = `LIMIT ${this._limit}`; } sqlArr.push(limitStr); // 添加limit条件 } /** 打印SQL */ YoyoMysql.isShowSql && logSql(sqlArr.join(' '), params); return { sql: sqlArr.join(' '), params, }; } /** * 构建Insert类型的语句 * @param data 数据 * @returns */ buildInsert(data) { const table = this._table; let field = this._fields; const params = []; // 参数(二维数组) const sqlArr = ['INSERT']; sqlArr.push(`INTO ${table}`); /** * 判断并处理数据的函数 * @param data 数据 * @returns */ const processingData = (data) => { if (isObject(data)) { // 单条(会忽略 field 以当前为准) field = Object.keys(data).map(f => `\`${f}\``); params.push([...Object.values(data)]); return; } if (!Array.isArray(data)) throw new Error("The inserted data must be an object or array with a value"); if (data.length <= 0) throw new Error("The data you submit is empty"); if (isTwoArray(data)) { // 二维数组 params.push(...Object.values(data)); return; } if (isArrayObj(data)) { // 对象数组 field = Object.keys(data[0]).map(f => `\`${f}\``); params.push(...data.map(d => Object.values(d))); return; } if (isArrayData(data)) { // 一维数组 params.push(data); return; } throw new Error("The inserted data must be an object or array with a value"); }; processingData(data); if (field.length <= 0) { throw new Error("The data you submit has no fields"); } sqlArr.push(`(${field.join(',')})`); sqlArr.push('VALUES'); sqlArr.push(params.map(p => `(${p.map(v => '?').join(',')})`).join(',')); /** 打印SQL */ YoyoMysql.isShowSql && logSql(sqlArr.join(' '), params); return { sql: sqlArr.join(' '), params: params.flat(), }; } /** * 构建Update类型的语句 */ buildUpdate(data) { const table = this._table; const field = this._fields; const params = []; // 参数 const sqlArr = ['UPDATE']; sqlArr.push(`${table}`); // 构建join条件 if (this._join.length > 0) { const joinArr = this._join.map(j => `${j.type} JOIN ${j.table} ON ${j.where}`); sqlArr.push(joinArr.join(' ')); } sqlArr.push(`SET`); // 构建set条件 const checkSet = () => { if (isObject(data)) { // 对象就是直接设置将指定key设置指定value const arr = []; for (const field in data) { arr.push(`${field} = ?`); params.push(data[field]); } sqlArr.push(arr.join(',')); return; } if (isTwoArray(data)) { // 二维数组 const arr = []; data.forEach(d => { arr.push(`${d[0]} = ${d[1]}`); }); sqlArr.push(arr.join(',')); return; } if (isArrayData(data) && data.length == 3) { // 一维数组 // [field, value] sqlArr.push(`${data[0]} ${data[1]}`); params.push(data[2]); return; } throw new Error("You can only submit data in the form of arrays, two-dimensional arrays, and objects"); }; // 构建set条件 checkSet(); // 构建where条件 const resultWhere = this.buildWhere(); if (resultWhere) { sqlArr.push('WHERE', resultWhere.where); // 添加where条件 params.push(...resultWhere.params); // 添加参数 } // 构建order条件 if (this._order.length > 0) { const orderArr = this._order.map(o => { let { field, order } = o; if (/^(\w+)\.(\w+)$$/.test(field)) field = field.replace(/\./g, '`.`'); return `\`${field}\` ${order}`; }); sqlArr.push(`ORDER BY ${orderArr.join(',')}`); } /** 打印SQL */ YoyoMysql.isShowSql && logSql(sqlArr.join(' '), params); return { sql: sqlArr.join(' '), params, }; } /** * 构建sql语句 * @param type 类型 * @param data 数据(insert数据结构和|update数据结构) * @returns */ buildSql(type = 'select', data) { switch (type) { case 'select': return this.buildSelect(); case 'insert': return this.buildInsert(data); case 'update': return this.buildUpdate(data); case 'delete': return this.buildDelete(); default: throw new Error('Unknown type'); } } } function logSql(sql, bind) { let logSql = sql; if (!Array.isArray(bind)) { bind = [bind]; } else { bind = bind.flat(); } const newBind = bind.concat(); for (let k in newBind) { if (typeof newBind[k] === 'string' || typeof newBind[k] === 'boolean') { newBind[k] = `'${newBind[k]}'`; } // 使用非贪婪匹配防止替换错误(原逻辑可能存在替换顺序问题) logSql = logSql.replace(/([\s=])?\?(\s)?/, `$1${newBind[k]}$2`); } YoyoMysql.printMethod(logSql, highlightSql); } function highlightSql(sql) { return (0, sql_highlight_1.highlight)(sql, { colors: { identifier: '\x1b[36m', // Identifiers (column names, table names, etc.)] keyword: '\x1b[35m', // SQL reserved keywords function: '\x1b[31m', // Functions number: '\x1b[33m', // Numbers string: '\x1b[32m', // Strings special: '\x1b[33m', // Special characters bracket: '\x1b[37m', // Brackets (parentheses) comment: '\x1b[2m\x1b[90m', // Comments clear: '\x1b[0m' // Clear (inserted after each match) } }); }