This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
cyber-narrator-cn-ui/src/components/advancedSearch/meta/sql-parser.js

312 lines
10 KiB
JavaScript
Raw Normal View History

2022-06-09 18:20:28 +08:00
// import { GenericSQL, SqlParserVisitor } from 'dt-sql-parser'
import Meta, { connection, condition, columnType, cloneMeta } from '@/components/advancedSearch/meta/meta'
import { riskLevelMapping } from '@/utils/constants'
2022-01-25 17:16:56 +08:00
import _ from 'lodash'
// 补全语句,用于解析
const sqlPrev = 'select a from b where '
2022-12-08 16:09:46 +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
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 () {
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) {
const m = cloneMeta(meta)
m.column.name = meta.column.name
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(',')})`
} 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)
}
} else {
this.metaList.push(meta)
2022-01-25 17:16:56 +08:00
}
})
return {
metaList: this.metaList,
formatSql: this.parseMetaToSql(this.metaList)
}
}
parseMetaToSql (metaList, isFullText) {
2022-01-25 17:16:56 +08:00
let sql = ''
metaList.forEach(meta => {
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} `
} 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} `
} 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) {
// 在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
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
}
} 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 {
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
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
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) {
const constant = ctx.getText().toLowerCase()
2022-01-25 17:16:56 +08:00
this.buildMeta('expression', constant)
}
// 操作符
visitComparisonOperator (ctx) {
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) {
const inPredicate = ctx.getText().toLowerCase()
2022-01-25 17:16:56 +08:00
this.buildMeta('in', inPredicate)
}
// like语句
visitLikePredicate (ctx) {
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) {
if (value.indexOf("'") > -1) {
value = value.split("'").join("''") // 如xi'an多添加一个单引号处理为xi''an
}
2022-02-14 16:04:08 +08:00
const match = `${value}`.match(/^'.+?'$/)
return match ? value : `'${value}'`
2022-01-25 17:16:56 +08:00
}
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
}
}
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
})
return (m && m.value) || value
}
}
return value
}
}