0.0.1-alpha.6:
1. 修改 `package.json` 中的项目名称和版本号。 2. 更新 `node_modules` 中的依赖包版本。 3. 修改 `src/index.ts` 中的 SQL 语句和 `caretColumn` 的计算方式。 4. 修改 `src/parse/default-rules.ts` 中的规则和导入语句。 5. 修改 `src/parse/visitor.ts` 中的访问者和规则。 6. 修改 `src/preprocess/default-preprocessor.ts` 中的预处理逻辑。 7. 修改 `src/types.ts` 中的导入语句。
This commit is contained in:
parent
d7f6568157
commit
645a73d6af
@ -12,7 +12,7 @@
|
||||
<script type="module">
|
||||
const { DtSqlParserSemAnalysePlugin } = await import(/* @vite-ignore */import.meta.env.VITE_ENTRY_PATH)
|
||||
const myPlugin = new DtSqlParserSemAnalysePlugin()
|
||||
const sql = 'SELECT a.b| FROM t'
|
||||
const sql = 'SELECT a.| AS c'
|
||||
const caretColumn = sql.indexOf('|') + 1
|
||||
const result = myPlugin.parse(sql.replace('|', ''), { lineNumber: 1, columnNumber: caretColumn })
|
||||
console.log(result)
|
||||
|
45
package-lock.json
generated
45
package-lock.json
generated
@ -1,12 +1,14 @@
|
||||
{
|
||||
"name": "dt-sql-parser-analyse-demo",
|
||||
"name": "dt-sql-parser-semantic-analyse-plugin",
|
||||
"version": "0.0.1-alpha.7",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "dt-sql-parser-analyse-demo",
|
||||
"name": "dt-sql-parser-semantic-analyse-plugin",
|
||||
"version": "0.0.1-alpha.6",
|
||||
"dependencies": {
|
||||
"dt-sql-parser": "^4.0.0-beta.4.11"
|
||||
"dt-sql-parser": "^4.0.0-beta.4.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.0.2",
|
||||
@ -1099,17 +1101,29 @@
|
||||
}
|
||||
},
|
||||
"node_modules/antlr4-c3": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/antlr4-c3/-/antlr4-c3-3.1.1.tgz",
|
||||
"integrity": "sha512-S7DixV12kxWexTkQYGvooCgHYU5AjF74oYio+ZNgm0XN3EzxDY3J6Si9GprQ4KksvgWwK//EgZnL/26WB+bOpw==",
|
||||
"version": "3.3.7",
|
||||
"resolved": "http://npm.oushu.com:14837/antlr4-c3/-/antlr4-c3-3.3.7.tgz",
|
||||
"integrity": "sha512-F3ndE38wwA6z6AjUbL3heSdEGl4TxulGDPf9xB0/IY4dbRHWBh6XNaqFwur8vHKQk9FS5yNABHeg2wqlqIYO0w==",
|
||||
"dependencies": {
|
||||
"antlr4ts": "0.5.0-alpha.4"
|
||||
"antlr4ng": "2.0.11"
|
||||
}
|
||||
},
|
||||
"node_modules/antlr4ts": {
|
||||
"version": "0.5.0-alpha.4",
|
||||
"resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz",
|
||||
"integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ=="
|
||||
"node_modules/antlr4ng": {
|
||||
"version": "2.0.11",
|
||||
"resolved": "http://npm.oushu.com:14837/antlr4ng/-/antlr4ng-2.0.11.tgz",
|
||||
"integrity": "sha512-9jM91VVtHSqHkAHQsXHaoaiewFETMvUTI1/tXvwTiFw4f7zke3IGlwEyoKN9NS0FqIwDKFvUNW2e1cKPniTkVQ==",
|
||||
"peerDependencies": {
|
||||
"antlr4ng-cli": "1.0.7"
|
||||
}
|
||||
},
|
||||
"node_modules/antlr4ng-cli": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "http://npm.oushu.com:14837/antlr4ng-cli/-/antlr4ng-cli-1.0.7.tgz",
|
||||
"integrity": "sha512-qN2FsDBmLvsQcA5CWTrPz8I8gNXeS1fgXBBhI78VyxBSBV/EJgqy8ks6IDTC9jyugpl40csCQ4sL5K4i2YZ/2w==",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"antlr4ng": "index.js"
|
||||
}
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
@ -1890,11 +1904,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dt-sql-parser": {
|
||||
"version": "4.0.0-beta.4.11",
|
||||
"integrity": "sha512-bgMJAMImikNwE0OPZApI+R+PjpI8xoJAksQIUJdtS4+piZII1LHzbmlp8T7iRJ4Fo56EwY5ILmv9VcZ/PwKV1A==",
|
||||
"version": "4.0.0-beta.4.12",
|
||||
"resolved": "http://npm.oushu.com:14837/dt-sql-parser/-/dt-sql-parser-4.0.0-beta.4.12.tgz",
|
||||
"integrity": "sha512-kfLRecn+dfdZjrKt3Ovm52ryoh9UGF+dCjNzV2pk8XI5kgF7lgQJhPZdRi+2yn1AU/BWQ1/0E6LnvFYbZ7Wr9Q==",
|
||||
"dependencies": {
|
||||
"antlr4-c3": "3.1.1",
|
||||
"antlr4ts": "0.5.0-alpha.4"
|
||||
"antlr4-c3": "3.3.7",
|
||||
"antlr4ng": "2.0.11"
|
||||
}
|
||||
},
|
||||
"node_modules/elliptic": {
|
||||
|
@ -37,6 +37,6 @@
|
||||
"vite-plugin-node-polyfills": "^0.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"dt-sql-parser": "^4.0.0-beta.4.11"
|
||||
"dt-sql-parser": "^4.0.0-beta.4.12"
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { defaultEntities, defaultRules, defaultStmts } from './parse/default-rules'
|
||||
import { defaultAlias, defaultEntities, defaultRules, defaultStmts } from './parse/default-rules'
|
||||
import { parse } from './parse'
|
||||
import { preprocess } from './preprocess'
|
||||
import { type PluginSettings, type InsertCaretPlaceholderConfig } from './types'
|
||||
import { defaultPreprocessorList } from './preprocess/default-preprocessor'
|
||||
import { insertCaret } from './caret'
|
||||
import { PostgresSQL } from 'dt-sql-parser'
|
||||
import { PostgreSQL } from 'dt-sql-parser'
|
||||
|
||||
export class DtSqlParserSemAnalysePlugin {
|
||||
private readonly settings: PluginSettings = {}
|
||||
@ -18,10 +18,11 @@ export class DtSqlParserSemAnalysePlugin {
|
||||
const sqlAfterPreprocess = preprocess(sqlAfterInsertCaret, this.settings.preprocessor || defaultPreprocessorList)
|
||||
const sqlParseResult = parse(
|
||||
sqlAfterPreprocess,
|
||||
this.settings.parse?.parser || new PostgresSQL(),
|
||||
this.settings.parse?.parser || new PostgreSQL(),
|
||||
this.settings.parse?.stmts || defaultStmts,
|
||||
this.settings.parse?.entities || defaultEntities,
|
||||
this.settings.parse?.rules || defaultRules
|
||||
this.settings.parse?.rules || defaultRules,
|
||||
this.settings.parse?.alias || defaultAlias
|
||||
)
|
||||
return sqlParseResult
|
||||
}
|
||||
|
@ -1,89 +1,39 @@
|
||||
import { PostgreSQLParser } from 'dt-sql-parser/dist/lib/pgsql/PostgreSQLParser'
|
||||
import { PostgreSqlParser } from 'dt-sql-parser/dist/lib/postgresql/PostgreSqlParser'
|
||||
|
||||
export const defaultAlias = {
|
||||
selectstmt: 'selectStatement',
|
||||
target_el: 'target_label'
|
||||
}
|
||||
|
||||
export const defaultStmts = [
|
||||
'stmt',
|
||||
// select statement
|
||||
'selectstmt'
|
||||
'simple_select',
|
||||
]
|
||||
|
||||
export const defaultEntities = [
|
||||
// column_name directly. ex: select column1
|
||||
'column_name',
|
||||
// column_name indirectly. ex: select schema.column1
|
||||
'columnref',
|
||||
'table_name',
|
||||
'view_name',
|
||||
'function_name',
|
||||
'schema_name',
|
||||
'target_el',
|
||||
'colid',
|
||||
'attr_name',
|
||||
'collabel',
|
||||
'func_arg_expr'
|
||||
'collabel'
|
||||
]
|
||||
|
||||
export const defaultRules: Record<string, number[]> = {
|
||||
// 通用的简单column规则(不带.运算符的column)
|
||||
common_column_simple: [
|
||||
PostgreSQLParser.RULE_stmt,
|
||||
PostgreSQLParser.RULE_column_name
|
||||
select_target: [
|
||||
PostgreSqlParser.RULE_simple_select,
|
||||
PostgreSqlParser.RULE_target_el,
|
||||
],
|
||||
// 通用的复合column规则(带.运算符的column)
|
||||
common_column_ref: [
|
||||
PostgreSQLParser.RULE_stmt,
|
||||
PostgreSQLParser.RULE_columnref
|
||||
select_target_colid: [
|
||||
PostgreSqlParser.RULE_target_el,
|
||||
PostgreSqlParser.RULE_function_name,
|
||||
PostgreSqlParser.RULE_colid
|
||||
],
|
||||
select_target_column_simple: [
|
||||
PostgreSQLParser.RULE_selectstmt,
|
||||
PostgreSQLParser.RULE_select_clause,
|
||||
PostgreSQLParser.RULE_target_list,
|
||||
PostgreSQLParser.RULE_column_name
|
||||
select_target_attr: [
|
||||
PostgreSqlParser.RULE_target_el,
|
||||
PostgreSqlParser.RULE_function_name,
|
||||
PostgreSqlParser.RULE_attr_name
|
||||
],
|
||||
select_target_column_ref: [
|
||||
PostgreSQLParser.RULE_selectstmt,
|
||||
PostgreSQLParser.RULE_select_clause,
|
||||
PostgreSQLParser.RULE_target_list,
|
||||
PostgreSQLParser.RULE_columnref
|
||||
],
|
||||
select_target_function: [
|
||||
PostgreSQLParser.RULE_selectstmt,
|
||||
PostgreSQLParser.RULE_select_clause,
|
||||
PostgreSQLParser.RULE_target_list,
|
||||
PostgreSQLParser.RULE_function_name
|
||||
],
|
||||
select_column_alias: [
|
||||
PostgreSQLParser.RULE_selectstmt,
|
||||
PostgreSQLParser.RULE_select_clause,
|
||||
PostgreSQLParser.RULE_target_list,
|
||||
PostgreSQLParser.RULE_collabel
|
||||
],
|
||||
select_from_table: [
|
||||
PostgreSQLParser.RULE_selectstmt,
|
||||
PostgreSQLParser.RULE_select_clause,
|
||||
PostgreSQLParser.RULE_from_clause,
|
||||
PostgreSQLParser.RULE_table_name
|
||||
],
|
||||
select_from_view: [
|
||||
PostgreSQLParser.RULE_selectstmt,
|
||||
PostgreSQLParser.RULE_select_clause,
|
||||
PostgreSQLParser.RULE_from_clause,
|
||||
PostgreSQLParser.RULE_view_name
|
||||
],
|
||||
select_from_function: [
|
||||
PostgreSQLParser.RULE_selectstmt,
|
||||
PostgreSQLParser.RULE_select_clause,
|
||||
PostgreSQLParser.RULE_from_clause,
|
||||
PostgreSQLParser.RULE_function_name
|
||||
],
|
||||
column_ref_colid: [
|
||||
PostgreSQLParser.RULE_columnref,
|
||||
PostgreSQLParser.RULE_colid
|
||||
],
|
||||
column_ref_attr: [
|
||||
PostgreSQLParser.RULE_columnref,
|
||||
PostgreSQLParser.RULE_attr_name
|
||||
],
|
||||
function_arg_expr: [
|
||||
PostgreSQLParser.RULE_function_name,
|
||||
PostgreSQLParser.RULE_func_arg_expr
|
||||
select_target_alias: [
|
||||
PostgreSqlParser.RULE_target_el,
|
||||
-PostgreSqlParser.RULE_attr_name,
|
||||
PostgreSqlParser.RULE_collabel
|
||||
]
|
||||
}
|
||||
|
@ -1,18 +1,20 @@
|
||||
import { PostgresSQL } from 'dt-sql-parser'
|
||||
import { PostgreSQL } from 'dt-sql-parser'
|
||||
import { SQLVisitor } from './visitor'
|
||||
import { type SQLParseResult } from '../types'
|
||||
import type BasicParser from 'dt-sql-parser/dist/parser/common/basicParser'
|
||||
import { type BasicSQL } from 'dt-sql-parser/dist/parser/common/basicSQL'
|
||||
|
||||
export function parse (
|
||||
sql: string,
|
||||
parser: BasicParser = new PostgresSQL(),
|
||||
parser: BasicSQL = new PostgreSQL(),
|
||||
stmts: string[] = [],
|
||||
entities: string[] = [],
|
||||
rules: Record<string, number[]> = {}
|
||||
rules: Record<string, number[]> = {},
|
||||
alias: Record<string, string> = {},
|
||||
): SQLParseResult {
|
||||
const tree = parser.parse(sql)
|
||||
console.log('tree', tree)
|
||||
const visitor = new SQLVisitor()
|
||||
visitor.visitorAlias = alias
|
||||
stmts.forEach(stmt => { visitor.addStmt(stmt) })
|
||||
entities.forEach(entity => { visitor.addEntity(entity) })
|
||||
Object.keys(rules).forEach(name => { visitor.addRules(name, rules[name]) })
|
||||
|
@ -1,21 +1,24 @@
|
||||
import { type ParserRuleContext } from 'antlr4ts'
|
||||
import { AbstractParseTreeVisitor, type PostgreSQLParserVisitor } from 'dt-sql-parser'
|
||||
import { type ProgramContext, PostgreSQLParser } from 'dt-sql-parser/dist/lib/pgsql/PostgreSQLParser'
|
||||
import { AbstractParseTreeVisitor, type RuleContext } from 'antlr4ng'
|
||||
import { type PostgreSqlParserVisitor } from 'dt-sql-parser'
|
||||
import { type ProgramContext, PostgreSqlParser } from 'dt-sql-parser/dist/lib/postgresql/PostgreSqlParser'
|
||||
import { type Entity, type SQLParseResult, type Stmt } from '../types'
|
||||
import { caretPlaceholder } from '../caret'
|
||||
|
||||
function withCaret (ctx: ParserRuleContext) {
|
||||
return ctx.text.includes(caretPlaceholder)
|
||||
function toVisitorAlias (node: string, alias: Record<string, string>) {
|
||||
const result = alias[node] || node
|
||||
return `visit${result.slice(0, 1).toUpperCase()}${result.slice(1)}`
|
||||
}
|
||||
|
||||
export class SQLVisitor extends AbstractParseTreeVisitor<void> implements PostgreSQLParserVisitor<void> {
|
||||
function withCaret (ctx: RuleContext) {
|
||||
return ctx.getText().includes(caretPlaceholder)
|
||||
}
|
||||
|
||||
export class SQLVisitor extends AbstractParseTreeVisitor<void> implements PostgreSqlParserVisitor<void> {
|
||||
private result: SQLParseResult = {
|
||||
stmtList: [],
|
||||
nerestCaretEntityList: []
|
||||
}
|
||||
|
||||
protected defaultResult = () => ({ list: [], nerestCaret: null })
|
||||
|
||||
public clear () {
|
||||
this.result = { stmtList: [], nerestCaretEntityList: [] }
|
||||
}
|
||||
@ -24,6 +27,8 @@ export class SQLVisitor extends AbstractParseTreeVisitor<void> implements Postgr
|
||||
return this.result
|
||||
}
|
||||
|
||||
public visitorAlias = {}
|
||||
|
||||
private readonly stmtStack: Stmt[] = []
|
||||
|
||||
private readonly entityStack: Entity[] = []
|
||||
@ -50,12 +55,12 @@ export class SQLVisitor extends AbstractParseTreeVisitor<void> implements Postgr
|
||||
}
|
||||
|
||||
public addEntity (name: string) {
|
||||
this.entityRules.set((PostgreSQLParser as any)[`RULE_${name}`], [])
|
||||
this.entityRules.set((PostgreSqlParser as any)[`RULE_${name}`], [])
|
||||
let isHitRule = false
|
||||
const visitorName = `visit${name.slice(0, 1).toUpperCase()}${name.slice(1)}`
|
||||
const visitorName = toVisitorAlias(name, this.visitorAlias)
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const rules = this.entityRules.get((PostgreSQLParser as any)[`RULE_${name}`])!;
|
||||
(this as any)[visitorName] = (ctx: ParserRuleContext) => {
|
||||
const rules = this.entityRules.get((PostgreSqlParser as any)[`RULE_${name}`])!;
|
||||
(this as any)[visitorName] = (ctx: RuleContext) => {
|
||||
const chain = this.getNodeChain(ctx)
|
||||
for (const rule of rules) {
|
||||
const ruleChain = this.rules.get(rule)
|
||||
@ -66,7 +71,7 @@ export class SQLVisitor extends AbstractParseTreeVisitor<void> implements Postgr
|
||||
const beginEntity = this.entityStack.find(entity => entity.type === ruleChainBegin)
|
||||
const result: Entity = {
|
||||
rule,
|
||||
text: ctx.text,
|
||||
text: ctx.getText(),
|
||||
type: ctx.ruleIndex,
|
||||
caret: withCaret(ctx),
|
||||
belongsToStmt: beginStmt || null,
|
||||
@ -91,11 +96,11 @@ export class SQLVisitor extends AbstractParseTreeVisitor<void> implements Postgr
|
||||
}
|
||||
|
||||
public addStmt (name: string) {
|
||||
this.stmtRules.set((PostgreSQLParser as any)[`RULE_${name}`], [])
|
||||
const visitorName = `visit${name.slice(0, 1).toUpperCase()}${name.slice(1)}`;
|
||||
(this as any)[visitorName] = (ctx: ParserRuleContext) => {
|
||||
this.stmtRules.set((PostgreSqlParser as any)[`RULE_${name}`], [])
|
||||
const visitorName = toVisitorAlias(name, this.visitorAlias);
|
||||
(this as any)[visitorName] = (ctx: RuleContext) => {
|
||||
this.stmtStack.push({
|
||||
text: ctx.text,
|
||||
text: ctx.getText(),
|
||||
type: ctx.ruleIndex,
|
||||
caret: withCaret(ctx),
|
||||
relatedEntities: {}
|
||||
@ -106,8 +111,8 @@ export class SQLVisitor extends AbstractParseTreeVisitor<void> implements Postgr
|
||||
}
|
||||
}
|
||||
|
||||
private getNodeChain (ctx: ParserRuleContext) {
|
||||
let _ctx: ParserRuleContext | undefined = ctx
|
||||
private getNodeChain (ctx: RuleContext) {
|
||||
let _ctx: RuleContext | null = ctx
|
||||
const result = []
|
||||
while (_ctx) {
|
||||
result.unshift(_ctx.ruleIndex)
|
||||
@ -118,10 +123,13 @@ export class SQLVisitor extends AbstractParseTreeVisitor<void> implements Postgr
|
||||
|
||||
private matchRules (chain: number[], ruleChain: number[] | undefined) {
|
||||
// 只要ruleChain里面每个元素都出现在chain里面,且顺序一致,则返回true。否则返回false
|
||||
// 当元素value为负数时,表示NOT,即不出现id为-value的规则。
|
||||
if (!ruleChain) return false
|
||||
let index = 0
|
||||
for (let i = 0; i < ruleChain.length; i++) {
|
||||
if (chain.indexOf(ruleChain[i]) < index) return false
|
||||
if (ruleChain[i] < 0) {
|
||||
if (chain.indexOf(-ruleChain[i]) >= index) return false
|
||||
} else if (chain.indexOf(ruleChain[i]) < index) return false
|
||||
else index = chain.indexOf(ruleChain[i])
|
||||
}
|
||||
return true
|
||||
|
@ -1,5 +1,14 @@
|
||||
import { type Preprocessor } from '../types'
|
||||
|
||||
export const addSuffixForParseSelectProcessor: Preprocessor = (sql: string) => {
|
||||
const suffix = ' '
|
||||
const maxWords = 3
|
||||
if (/select( )+/.test(sql.toLowerCase()) && sql.split(' ').filter(item => item).length < maxWords) {
|
||||
return sql + '' + suffix
|
||||
}
|
||||
return sql
|
||||
}
|
||||
|
||||
export const addSuffixForParseAlterFunctionProcessor: Preprocessor = (sql: string) => {
|
||||
const suffix = 'RESET ALL'
|
||||
const maxWords = 4
|
||||
@ -20,5 +29,6 @@ export const addSuffixForParseAlterTableProcessor: Preprocessor = (sql: string)
|
||||
|
||||
export const defaultPreprocessorList = [
|
||||
addSuffixForParseAlterFunctionProcessor,
|
||||
addSuffixForParseAlterTableProcessor
|
||||
addSuffixForParseAlterTableProcessor,
|
||||
addSuffixForParseSelectProcessor
|
||||
]
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type BasicParser from 'dt-sql-parser/dist/parser/common/basicParser'
|
||||
import { type BasicSQL } from 'dt-sql-parser/dist/parser/common/basicSQL'
|
||||
|
||||
export interface InsertCaretPlaceholderConfig {
|
||||
lineNumber: number
|
||||
@ -24,10 +24,11 @@ export interface PluginSettings {
|
||||
* 自定义解析逻辑
|
||||
*/
|
||||
parse?: {
|
||||
parser?: BasicParser
|
||||
parser?: BasicSQL
|
||||
stmts?: string[]
|
||||
entities?: string[]
|
||||
rules?: Record<string, number[]>
|
||||
alias?: Record<string, string>
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user