yoyomysql
Version:
一个链式连接mysql数据库的扩展包
917 lines (916 loc) • 32.7 kB
JavaScript
"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)
}
});
}