2022-06-09 18:20:28 +08:00
|
|
|
|
// import { GenericSQL, SqlParserVisitor } from 'dt-sql-parser'
|
2022-01-25 19:47:08 +08:00
|
|
|
|
import Meta, { connection, condition, columnType, cloneMeta } from '@/components/advancedSearch/meta/meta'
|
2022-02-13 23:20:24 +08:00
|
|
|
|
import { riskLevelMapping } from '@/utils/constants'
|
2022-01-25 17:16:56 +08:00
|
|
|
|
import _ from 'lodash'
|
|
|
|
|
|
// 补全语句,用于解析
|
|
|
|
|
|
const sqlPrev = 'select a from b where '
|
2022-06-09 18:20:28 +08:00
|
|
|
|
export default class SqlParser/* extends SqlParserVisitor*/ {
|
2022-01-25 17:16:56 +08:00
|
|
|
|
constructor (init, columnList) {
|
2022-06-09 18:20:28 +08:00
|
|
|
|
// super()
|
2022-01-25 17:16:56 +08:00
|
|
|
|
this.tempMeta = null
|
|
|
|
|
|
this.originalSql = ''
|
|
|
|
|
|
this.metaList = []
|
|
|
|
|
|
this.columnList = columnList
|
|
|
|
|
|
// 原始数据
|
|
|
|
|
|
if (_.isArray(init)) {
|
|
|
|
|
|
this.metaList = init
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.originalSql = init
|
|
|
|
|
|
}
|
|
|
|
|
|
// 工具类实例
|
|
|
|
|
|
this.dtSqlParser = new GenericSQL()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 返回的数组是错误信息,为空即校验通过
|
|
|
|
|
|
validate () {
|
|
|
|
|
|
return this.dtSqlParser.validate(sqlPrev + this.originalSql)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 规范化原始语句
|
|
|
|
|
|
formatSql () {
|
|
|
|
|
|
// 先使用originalSql走一遍parse,获取metaList,再将metaList转为sql
|
|
|
|
|
|
const tree = this.dtSqlParser.parse(sqlPrev + this.originalSql)
|
|
|
|
|
|
this.visit(tree)
|
|
|
|
|
|
if (this.metaList.length === 0 && this.tempMeta.column.name) {
|
|
|
|
|
|
this.tempMeta.column.type = columnType.fullText
|
|
|
|
|
|
this.tempMeta.column.label = this.tempMeta.column.name
|
2022-01-25 19:47:08 +08:00
|
|
|
|
this.metaList.push(cloneMeta(this.tempMeta))
|
2022-01-25 17:16:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
this.tempMeta = null
|
|
|
|
|
|
return {
|
|
|
|
|
|
metaList: this.metaList,
|
|
|
|
|
|
formatSql: this.parseMetaToSql(this.metaList)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
formatMetaList () {
|
2022-01-25 19:47:08 +08:00
|
|
|
|
const tempMetaList = cloneMeta(this.metaList)
|
2022-01-25 17:16:56 +08:00
|
|
|
|
this.metaList = []
|
|
|
|
|
|
tempMetaList.forEach(meta => {
|
|
|
|
|
|
if (meta.meta === condition) {
|
|
|
|
|
|
if (meta.column.type === columnType.fullText) {
|
2022-01-25 19:47:08 +08:00
|
|
|
|
const m = cloneMeta(meta)
|
2022-01-25 22:58:23 +08:00
|
|
|
|
m.column.name = meta.column.name
|
2022-01-25 19:47:08 +08:00
|
|
|
|
m.column.label = m.column.name
|
|
|
|
|
|
this.metaList.push(m)
|
2022-01-25 17:16:56 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
if (_.isArray(meta.value.value)) {
|
2022-02-18 10:07:43 +08:00
|
|
|
|
const tempArr = meta.value.value.map(v => {
|
|
|
|
|
|
return meta.column.type === columnType.string ? stringInQuot(v.trim()) : v.trim()
|
|
|
|
|
|
})
|
|
|
|
|
|
meta.value.value = `(${tempArr.join(',')})`
|
|
|
|
|
|
meta.value.label = meta.value.value
|
2022-01-25 17:16:56 +08:00
|
|
|
|
} else {
|
2022-02-18 10:07:43 +08:00
|
|
|
|
const isArray = ['IN', 'NOT IN'].indexOf(meta.operator.value) > -1
|
|
|
|
|
|
if (isArray) {
|
|
|
|
|
|
const leftBracketIndex = meta.value.value.indexOf('(')
|
|
|
|
|
|
const rightBracketIndex = meta.value.value.lastIndexOf(')')
|
|
|
|
|
|
let temp = meta.value.value.substring(0, rightBracketIndex)
|
|
|
|
|
|
temp = meta.value.value.substring(leftBracketIndex + 1, temp.length)
|
|
|
|
|
|
let tempArr = temp.split(',')
|
|
|
|
|
|
tempArr = tempArr.map(t => meta.column.type === columnType.string ? stringInQuot(t.trim()) : t.trim())
|
|
|
|
|
|
meta.value.value = `(${tempArr.join(',')})`
|
2022-02-18 18:09:44 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
meta.value.value = meta.column.type === columnType.string ? stringInQuot(meta.value.value.trim()) : meta.value.value.trim()
|
2022-02-18 10:07:43 +08:00
|
|
|
|
}
|
2022-01-25 17:16:56 +08:00
|
|
|
|
meta.value.label = meta.value.value
|
|
|
|
|
|
}
|
|
|
|
|
|
this.metaList.push(meta)
|
|
|
|
|
|
}
|
2022-01-25 19:47:08 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
this.metaList.push(meta)
|
2022-01-25 17:16:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
return {
|
|
|
|
|
|
metaList: this.metaList,
|
|
|
|
|
|
formatSql: this.parseMetaToSql(this.metaList)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-25 22:58:23 +08:00
|
|
|
|
parseMetaToSql (metaList, isFullText) {
|
2022-01-25 17:16:56 +08:00
|
|
|
|
let sql = ''
|
|
|
|
|
|
metaList.forEach(meta => {
|
2022-01-25 22:58:23 +08:00
|
|
|
|
if (isFullText) {
|
|
|
|
|
|
if (meta.meta === condition) {
|
|
|
|
|
|
if (meta.column.type !== columnType.fullText) {
|
2022-02-18 10:07:43 +08:00
|
|
|
|
sql += `${meta.column.name}${handleOperatorSpace(meta.operator.value)}${meta.value.value} `
|
2022-01-25 22:58:23 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
sql += "QUERY('"
|
|
|
|
|
|
this.columnList.forEach(column => {
|
|
|
|
|
|
sql += `${column.name}:${meta.column.name.replace(/'/g, '')} `
|
|
|
|
|
|
})
|
|
|
|
|
|
sql += "') "
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (meta.meta === condition) {
|
|
|
|
|
|
sql += (meta.column.name)
|
|
|
|
|
|
if (meta.column.type !== columnType.fullText) {
|
2022-02-18 10:07:43 +08:00
|
|
|
|
sql += `${handleOperatorSpace(meta.operator.value)}${meta.value.value} `
|
2022-01-25 22:58:23 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
sql += ' '
|
|
|
|
|
|
}
|
2022-01-25 17:16:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (meta.meta === connection) {
|
|
|
|
|
|
sql += `${meta.value} `
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
return sql
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
buildMeta (type, value) {
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
|
case 'expression': {
|
|
|
|
|
|
// 如果tempMeta是空或已是完整的condition,新建meta
|
|
|
|
|
|
if (!this.tempMeta || this.tempMeta.isCompleteCondition()) {
|
|
|
|
|
|
this.tempMeta = new Meta(condition)
|
|
|
|
|
|
}
|
|
|
|
|
|
// 如果column.name为空,则参数值是column,否则是value
|
|
|
|
|
|
if (!this.tempMeta.column.name) {
|
2022-02-07 16:11:49 +08:00
|
|
|
|
// 在columnList中的,按columnList;不在则为全文检索
|
2022-01-25 17:16:56 +08:00
|
|
|
|
const column = this.columnList.find(column => {
|
|
|
|
|
|
return column.name === value
|
|
|
|
|
|
})
|
|
|
|
|
|
this.tempMeta.column.name = value
|
|
|
|
|
|
this.tempMeta.column.label = column ? column.label : value
|
2022-02-07 16:11:49 +08:00
|
|
|
|
this.tempMeta.column.type = column ? column.type : columnType.fullText
|
|
|
|
|
|
if (this.tempMeta.column.type === columnType.fullText) {
|
|
|
|
|
|
this.tempMeta.value.show = false
|
|
|
|
|
|
this.tempMeta.operator.show = false
|
|
|
|
|
|
this.metaList.push(cloneMeta(this.tempMeta))
|
2022-01-25 17:16:56 +08:00
|
|
|
|
}
|
2022-02-07 16:11:49 +08:00
|
|
|
|
} else {
|
2022-02-18 10:07:43 +08:00
|
|
|
|
if (_.isArray(value)) {
|
|
|
|
|
|
const tempArr = value.map(v => {
|
|
|
|
|
|
return this.tempMeta.column.type === columnType.string ? stringInQuot(v.trim()) : v.trim()
|
|
|
|
|
|
})
|
|
|
|
|
|
this.tempMeta.value.value = `(${tempArr.join(',')})`
|
|
|
|
|
|
this.tempMeta.value.label = this.tempMeta.value.value
|
2022-01-25 17:16:56 +08:00
|
|
|
|
} else {
|
2022-02-18 10:07:43 +08:00
|
|
|
|
const isArray = ['IN', 'NOT IN'].indexOf(this.tempMeta.operator.value) > -1
|
|
|
|
|
|
if (isArray) {
|
|
|
|
|
|
const leftBracketIndex = value.indexOf('(')
|
|
|
|
|
|
const rightBracketIndex = value.lastIndexOf(')')
|
|
|
|
|
|
let temp = value.substring(0, rightBracketIndex)
|
|
|
|
|
|
temp = value.substring(leftBracketIndex + 1, temp.length)
|
|
|
|
|
|
let tempArr = temp.split(',')
|
|
|
|
|
|
tempArr = tempArr.map(t => this.tempMeta.column.type === columnType.string ? stringInQuot(t.trim()) : t.trim())
|
|
|
|
|
|
this.tempMeta.value.value = `(${tempArr.join(',')})`
|
2022-01-25 17:16:56 +08:00
|
|
|
|
} else {
|
2022-02-18 18:09:44 +08:00
|
|
|
|
this.tempMeta.value.value = this.tempMeta.column.type === columnType.string ? stringInQuot(value.trim()) : value.trim()
|
2022-01-25 17:16:56 +08:00
|
|
|
|
}
|
2022-02-18 10:07:43 +08:00
|
|
|
|
this.tempMeta.value.label = this.tempMeta.value.value
|
2022-01-25 17:16:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
this.tempMeta.value.show = true
|
2022-01-25 19:47:08 +08:00
|
|
|
|
this.metaList.push(cloneMeta(this.tempMeta))
|
2022-01-25 17:16:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'operator': {
|
|
|
|
|
|
this.tempMeta.operator.value = value
|
|
|
|
|
|
this.tempMeta.operator.label = value
|
|
|
|
|
|
this.tempMeta.operator.show = true
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
// (not)in和(not)like特殊处理
|
|
|
|
|
|
case 'like':
|
|
|
|
|
|
case 'in': {
|
2022-02-18 10:07:43 +08:00
|
|
|
|
const { column, operator, handleValue } = handleInOrLike(value, type)
|
2022-01-25 17:16:56 +08:00
|
|
|
|
this.buildMeta('expression', column)
|
|
|
|
|
|
this.buildMeta('operator', operator)
|
|
|
|
|
|
this.buildMeta('expression', handleValue)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'connection': {
|
|
|
|
|
|
// tempMeta的value为空,则上个条件是全文搜索
|
|
|
|
|
|
if (!this.tempMeta.column.type && !this.tempMeta.value.value) {
|
|
|
|
|
|
this.tempMeta.column.type = columnType.fullText
|
|
|
|
|
|
this.tempMeta.column.label = this.tempMeta.column.name
|
2022-01-25 19:47:08 +08:00
|
|
|
|
this.metaList.push(cloneMeta(this.tempMeta))
|
2022-01-25 17:16:56 +08:00
|
|
|
|
this.tempMeta = null
|
|
|
|
|
|
}
|
|
|
|
|
|
const meta = new Meta(connection)
|
|
|
|
|
|
meta.value = value
|
|
|
|
|
|
this.metaList.push(meta)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 字段或值
|
|
|
|
|
|
visitExpressionAtomPredicate (ctx) {
|
2022-01-26 18:40:24 +08:00
|
|
|
|
const constant = ctx.getText().toLowerCase()
|
2022-01-25 17:16:56 +08:00
|
|
|
|
this.buildMeta('expression', constant)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 操作符
|
|
|
|
|
|
visitComparisonOperator (ctx) {
|
2022-01-26 18:40:24 +08:00
|
|
|
|
const comparisonOperator = ctx.getText().toLowerCase()
|
2022-01-25 17:16:56 +08:00
|
|
|
|
this.buildMeta('operator', comparisonOperator)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 连接符
|
|
|
|
|
|
visitLogicalOperator (ctx) {
|
|
|
|
|
|
const logicalOperator = ctx.getText().toUpperCase()
|
|
|
|
|
|
this.buildMeta('connection', logicalOperator)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// in语句
|
|
|
|
|
|
visitInPredicate (ctx) {
|
2022-01-26 18:40:24 +08:00
|
|
|
|
const inPredicate = ctx.getText().toLowerCase()
|
2022-01-25 17:16:56 +08:00
|
|
|
|
this.buildMeta('in', inPredicate)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// like语句
|
|
|
|
|
|
visitLikePredicate (ctx) {
|
2022-01-26 18:40:24 +08:00
|
|
|
|
const likePredicate = ctx.getText().toLowerCase()
|
2022-01-25 17:16:56 +08:00
|
|
|
|
this.buildMeta('like', likePredicate)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleType (value) {
|
|
|
|
|
|
if (_.isInteger(value)) {
|
|
|
|
|
|
return columnType.long
|
|
|
|
|
|
} else if (_.isNumber(value)) {
|
|
|
|
|
|
return columnType.number
|
|
|
|
|
|
} else if (_.isString(value)) {
|
|
|
|
|
|
return columnType.string
|
|
|
|
|
|
} else if (_.isArray(value)) {
|
|
|
|
|
|
const arr = value.split(',')
|
|
|
|
|
|
const hasString = arr.some(v => {
|
|
|
|
|
|
return handleType(v) === columnType.string
|
|
|
|
|
|
})
|
|
|
|
|
|
return hasString ? columnType.string : columnType.number
|
|
|
|
|
|
}/* else if (isStringInQuot(value)) {
|
|
|
|
|
|
return columnType.string
|
|
|
|
|
|
} */
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 使用单引号包裹
|
|
|
|
|
|
export function stringInQuot (value) {
|
2022-02-14 16:04:08 +08:00
|
|
|
|
const match = `${value}`.match(/^'.+?'$/)
|
2022-01-25 17:16:56 +08:00
|
|
|
|
return match ? value : `'${value}'`
|
|
|
|
|
|
}
|
2022-02-18 10:07:43 +08:00
|
|
|
|
// IN和LIKE前后加空格
|
|
|
|
|
|
export function handleOperatorSpace (operator) {
|
|
|
|
|
|
return ['IN', 'NOT IN', 'LIKE', 'NOT LIKE'].indexOf(operator) > -1 ? ` ${operator} ` : operator
|
|
|
|
|
|
}
|
|
|
|
|
|
// in、like拆分方法;解析后内容挤一堆,如:a in ('b')解析结果是ain('b'),需要拆分
|
2022-01-25 17:16:56 +08:00
|
|
|
|
function handleInOrLike (value, type) {
|
|
|
|
|
|
let sep
|
|
|
|
|
|
if (type === 'in') {
|
|
|
|
|
|
sep = `${type}(`
|
|
|
|
|
|
} else if (type === 'like') {
|
|
|
|
|
|
sep = `${type}'`
|
|
|
|
|
|
}
|
|
|
|
|
|
const notSep = `not${sep}`
|
|
|
|
|
|
let arr
|
|
|
|
|
|
let operator
|
2022-02-18 10:07:43 +08:00
|
|
|
|
if (value.split(notSep).length === 2) {
|
2022-01-25 17:16:56 +08:00
|
|
|
|
arr = value.split(notSep)
|
|
|
|
|
|
operator = `NOT ${type.toUpperCase()}`
|
|
|
|
|
|
} else {
|
|
|
|
|
|
arr = value.split(sep)
|
|
|
|
|
|
operator = type.toUpperCase()
|
|
|
|
|
|
}
|
|
|
|
|
|
const columnName = arr[0]
|
|
|
|
|
|
|
|
|
|
|
|
let v
|
|
|
|
|
|
if (type === 'in') {
|
2022-02-18 10:07:43 +08:00
|
|
|
|
v = `(${arr[1]}`
|
2022-01-25 17:16:56 +08:00
|
|
|
|
} else if (type === 'like') {
|
2022-02-18 10:07:43 +08:00
|
|
|
|
v = `'${arr[1]}`
|
2022-01-25 17:16:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
|
|
|
column: columnName,
|
|
|
|
|
|
operator,
|
|
|
|
|
|
handleValue: v
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-02-13 23:20:24 +08:00
|
|
|
|
|
|
|
|
|
|
function valueHandle (value, columnName) {
|
|
|
|
|
|
if (value === "'unknown'") {
|
|
|
|
|
|
return "''"
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (columnName) {
|
|
|
|
|
|
if (columnName === 'app_risk') {
|
|
|
|
|
|
const m = riskLevelMapping.find(mapping => {
|
2022-02-14 16:04:08 +08:00
|
|
|
|
return `'${mapping.name}'`.toLowerCase() === value.toLowerCase() || `'${mapping.value}'` === value
|
2022-02-13 23:20:24 +08:00
|
|
|
|
})
|
|
|
|
|
|
return (m && m.value) || value
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return value
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|