mysqli/lib/utils.js

313 lines
7.1 KiB
JavaScript
Raw Normal View History

2017-12-14 16:36:39 +08:00
/**
*
2020-11-24 21:11:45 +08:00
* @author yutent<yutent.io@gmail.com>
* @date 2020/11/24 20:07:37
2017-12-14 16:36:39 +08:00
*/
2020-11-24 21:11:45 +08:00
2017-12-14 16:36:39 +08:00
const { escape } = require('mysql')
2018-05-29 02:42:12 +08:00
function hideProperty(host, name, value) {
Object.defineProperty(host, name, {
2024-07-23 18:54:00 +08:00
value: value
2018-05-29 02:42:12 +08:00
})
}
function getType(val) {
if (val === null) {
return String(val)
}
2024-07-23 18:54:00 +08:00
return Object.prototype.toString.call(val).slice(8, -1).toLowerCase()
}
2024-07-23 18:54:00 +08:00
2018-05-29 02:42:12 +08:00
function parse$or(arr) {
let sql = ''
for (let it of arr) {
sql += '('
if (it.$and) {
sql += parse$and(it.$and)
} else {
sql += parse$opt(it)
}
sql += ') OR '
}
sql = sql.slice(0, -3)
return sql
}
2018-05-29 02:42:12 +08:00
function parse$and(arr) {
let sql = ''
for (let it of arr) {
sql += '('
if (it.$or) {
sql += parse$or(it.$or)
} else {
sql += parse$opt(it)
}
sql += ') AND '
}
sql = sql.slice(0, -4)
return sql
}
2018-05-29 02:42:12 +08:00
function parse$opt(opt) {
let sql = ''
for (let k in opt) {
let tmp = opt[k]
switch (getType(tmp)) {
case 'object':
if (tmp.$like) {
sql += ` ${k} LIKE ${escape(tmp.$like)} `
break
}
if (tmp.$sql) {
2018-03-03 20:10:31 +08:00
sql += ` ${k} ${tmp.$sql} `
break
}
if (tmp.$in) {
2018-05-29 02:42:12 +08:00
let list = tmp.$in.map(it => {
return escape(it)
})
sql += ` ${k} IN (${list.join(',')}) `
break
}
2018-03-03 20:10:31 +08:00
if (tmp.$between) {
if (tmp.$between.length < 2) {
throw new Error(`Array $between's length must be 2.`)
}
2018-05-29 02:42:12 +08:00
let list = tmp.$between.map(it => {
2018-03-03 20:10:31 +08:00
return escape(it)
})
sql += ` ${k} BETWEEN ${list[0]} AND ${list[1]} `
break
}
// 比较
if (tmp.hasOwnProperty('$lt') || tmp.hasOwnProperty('$lte')) {
let oc = tmp.hasOwnProperty('$lt') ? '<' : '<='
let val = tmp.hasOwnProperty('$lt') ? tmp.$lt : tmp.$lte
sql += ` ${k} ${oc} ${escape(val)} `
if (tmp.hasOwnProperty('$gt') || tmp.hasOwnProperty('$gte')) {
oc = tmp.hasOwnProperty('$gt') ? '>' : '>='
val = tmp.hasOwnProperty('$gt') ? tmp.$gt : tmp.$gte
sql += ` AND ${k} ${oc} ${escape(val)} `
2018-03-03 20:10:31 +08:00
}
break
}
if (tmp.hasOwnProperty('$gt') || tmp.hasOwnProperty('$gte')) {
let oc = tmp.hasOwnProperty('$gt') ? '>' : '>='
let val = tmp.hasOwnProperty('$gt') ? tmp.$gt : tmp.$gte
sql += ` ${k} ${oc} ${escape(val)} `
2018-03-03 20:10:31 +08:00
break
}
if (tmp.hasOwnProperty('$eq')) {
sql += ` ${k} = ${escape(tmp.$eq)} `
break
}
if (tmp.hasOwnProperty('$ne')) {
sql += ` ${k} <> ${escape(tmp.$ne)} `
2018-03-03 20:10:31 +08:00
break
}
default:
sql += ` ${k} = ${escape(tmp)}`
}
sql += ' AND '
}
sql = sql.slice(0, -4)
return sql
2017-12-14 16:36:39 +08:00
}
2018-05-29 02:42:12 +08:00
// 格式化表名
function fixtable(name) {
if (/ AS /i.test(name)) {
return name
}
2018-05-29 02:42:12 +08:00
return name
.split('.')
.map(it => {
return '`' + it + '`'
})
.join('.')
}
const parser = {
leftJoin(tables = []) {
2017-12-14 16:36:39 +08:00
let sql = ''
for (let it of tables) {
2018-05-29 02:42:12 +08:00
it.table = fixtable(it.table)
sql += ` LEFT JOIN ${it.table} ON ${it.on} `
2017-12-14 16:36:39 +08:00
}
return sql
},
2018-05-29 02:42:12 +08:00
rightJoin(tables = []) {
2017-12-14 16:36:39 +08:00
let sql = ''
for (let it of tables) {
2018-05-29 02:42:12 +08:00
it.table = fixtable(it.table)
sql += ` RIGHT JOIN ${it.table} ON ${it.on} `
2017-12-14 16:36:39 +08:00
}
return sql
},
2018-05-29 02:42:12 +08:00
join(tables = []) {
2017-12-14 16:36:39 +08:00
let sql = ''
for (let it of tables) {
2018-05-29 02:42:12 +08:00
it.table = fixtable(it.table)
2018-07-17 11:35:42 +08:00
sql += ` JOIN ${it.table} ON ${it.on} `
2017-12-14 16:36:39 +08:00
}
return sql
},
2018-05-29 02:42:12 +08:00
filter(opt) {
let sql = ''
2018-06-21 21:04:48 +08:00
if (!opt) {
return ' '
}
if (typeof opt === 'string') {
sql += opt
}
if (typeof opt === 'function') {
sql += opt()
}
if (typeof opt === 'object') {
if (opt.$and) {
sql += parse$and(opt.$and)
} else if (opt.$or) {
sql += parse$or(opt.$or)
} else {
sql += parse$opt(opt)
}
}
sql = sql.trim()
if (sql) {
return ` WHERE ${sql} `
} else {
return ' '
}
2017-12-14 16:36:39 +08:00
},
2018-05-29 02:42:12 +08:00
select(arr = ['*']) {
2017-12-14 16:36:39 +08:00
return `SELECT ${arr.join(',')} `
},
// 排序 ----------------------------------
2018-05-29 02:42:12 +08:00
sort(obj = {}) {
2017-12-14 16:36:39 +08:00
let sort = ''
for (let i in obj) {
let c = ''
if (obj[i] === -1) {
c = 'DESC'
}
sort += `${i} ${c},`
}
if (sort) {
return ' ORDER BY ' + sort.slice(0, -1)
} else {
return ''
}
},
2018-05-29 02:42:12 +08:00
limit(...args) {
2017-12-14 16:36:39 +08:00
return ` LIMIT ${args.join(',')} `
2018-05-29 02:42:12 +08:00
},
// 解析数据表的配置(新建表时)
field(fields = []) {
let primary = null
let indexes = []
let sql = `(\n`
for (let it of fields) {
it.type = it.type.toUpperCase()
let inc = '' // 自增
let autoUpdate = '' // 自动更新时间戳(仅 DATETIME & TIMESTAMP)
let defaultVal = ''
// 只处理1个主键, 其他的忽略, 且作为主键,必须 NOT NULL
if (!primary && it.primary) {
2019-09-19 15:19:40 +08:00
primary = `PRIMARY KEY (\`${it.name}\`)`
2018-05-29 02:42:12 +08:00
it.notnull = true
if (it.inc) {
inc = 'AUTO_INCREMENT'
}
}
let notnull = it.notnull ? 'NOT NULL' : 'NULL'
2019-09-23 16:07:30 +08:00
if (~it.type.indexOf('CHAR')) {
2018-05-29 02:42:12 +08:00
it.default = it.default ? escape(it.default) : ''
}
// 这几种类型,不允许设置默认值
if (['TEXT', 'BLOB', 'JSON', 'GEOMETRY'].includes(it.type)) {
notnull = 'NULL'
2019-09-23 16:07:30 +08:00
delete it.default
2018-05-29 02:42:12 +08:00
}
// 这2种类型,如果设置了自动更新时间戳, 则默认值自动改为当前时间戳
if (['TIMESTAMP', 'DATETIME'].includes(it.type)) {
if (it.update) {
autoUpdate = 'ON UPDATE CURRENT_TIMESTAMP'
it.default = 'CURRENT_TIMESTAMP'
}
}
// 这3种时间类型,不允许设置默认值为 当前时间戳
if (['TIME', 'DATE', 'YEAR'].includes(it.type)) {
if (it.default.toUpperCase() === 'CURRENT_TIMESTAMP') {
2019-09-23 16:07:30 +08:00
delete it.default
2018-05-29 02:42:12 +08:00
}
}
2019-09-23 16:07:30 +08:00
if (it.default || it.default === 0) {
defaultVal = 'DEFAULT ' + it.default
}
2018-05-29 02:42:12 +08:00
// 非主键下, 设置了unique & index时,都为索引
if (!it.primary) {
if (it.index || it.unique) {
let idx = `INDEX \`${it.name}_idx\` (\`${it.name}\`)`
if (it.unique) {
idx = 'UNIQUE ' + idx
}
indexes.push(idx)
}
}
2021-08-23 16:34:49 +08:00
sql += `\`${it.name}\` ${it.type} ${notnull} ${defaultVal} ${inc} ${autoUpdate},\n`
2018-05-29 02:42:12 +08:00
}
if (!primary) {
throw new Error('Can not create table without primary key.')
}
sql += primary
2019-09-19 15:19:40 +08:00
if (indexes.length) {
2019-09-19 15:49:22 +08:00
sql += ',\n' + indexes.join(', \n') + ')'
2019-09-19 15:19:40 +08:00
} else {
sql += '\n)'
}
2018-05-29 02:42:12 +08:00
return sql
2017-12-14 16:36:39 +08:00
}
}
2018-05-29 02:42:12 +08:00
class SqlErr {
constructor(msg = '', sql = '') {
2021-08-23 16:34:49 +08:00
var line = '-'.repeat(50)
2018-05-29 02:42:12 +08:00
this.message = msg
this.sql = sql
2018-05-29 02:42:12 +08:00
hideProperty(this, 'stack', msg)
2021-06-24 18:13:37 +08:00
console.error(
2021-08-23 16:34:49 +08:00
line +
2024-07-23 18:54:00 +08:00
`\n[${new Date().format(
'Y/m/d_H:i:s'
)}][Last Query SQL]: ${sql}\nQuery ${msg}\n` +
2021-08-23 16:34:49 +08:00
line
2021-06-24 18:13:37 +08:00
)
}
2018-05-29 02:42:12 +08:00
toString() {
return this.message
}
}
2018-05-29 02:42:12 +08:00
exports.SqlErr = SqlErr
exports.parser = parser
exports.escape = escape
exports.fixtable = fixtable