mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-04 00:10:25 +08:00
!59 fix: sql代码提示修复:支持跨schema提示
Merge pull request !59 from zongyangleo/dev_1109
This commit is contained in:
@@ -93,6 +93,52 @@ export class DbInst {
|
|||||||
return tables;
|
return tables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async loadTableSuggestions(dbName: string, range: any, reload?: boolean) {
|
||||||
|
const tables = await this.loadTables(dbName, reload);
|
||||||
|
// 表名联想
|
||||||
|
let suggestions: languages.CompletionItem[] = [];
|
||||||
|
tables?.forEach((tableMeta: any, index: any) => {
|
||||||
|
const { tableName, tableComment } = tableMeta;
|
||||||
|
suggestions.push({
|
||||||
|
label: {
|
||||||
|
label: tableName + ' - ' + tableComment,
|
||||||
|
description: 'table',
|
||||||
|
},
|
||||||
|
kind: monaco.languages.CompletionItemKind.File,
|
||||||
|
detail: tableComment,
|
||||||
|
insertText: tableName + ' ',
|
||||||
|
range,
|
||||||
|
sortText: 300 + index + '',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return { suggestions };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载列信息提示 */
|
||||||
|
async loadTableColumnSuggestions(db: string, tableName: string, range: any) {
|
||||||
|
let dbHits = await this.loadDbHints(db);
|
||||||
|
let columns = dbHits[tableName];
|
||||||
|
let suggestions: languages.CompletionItem[] = [];
|
||||||
|
columns?.forEach((a: string, index: any) => {
|
||||||
|
// 字段数据格式 字段名 字段注释, 如: create_time [datetime][创建时间]
|
||||||
|
const nameAndComment = a.split(' ');
|
||||||
|
const fieldName = nameAndComment[0];
|
||||||
|
suggestions.push({
|
||||||
|
label: {
|
||||||
|
label: a,
|
||||||
|
description: 'column',
|
||||||
|
},
|
||||||
|
kind: monaco.languages.CompletionItemKind.Property,
|
||||||
|
detail: '', // 不显示detail, 否则选中时备注等会被遮挡
|
||||||
|
insertText: fieldName, // create_time
|
||||||
|
range,
|
||||||
|
sortText: 100 + index + '', // 使用表字段声明顺序排序,排序需为字符串类型
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return { suggestions };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取表的所有列信息
|
* 获取表的所有列信息
|
||||||
* @param table 表名
|
* @param table 表名
|
||||||
@@ -482,7 +528,7 @@ export type FieldsMeta = {
|
|||||||
* @param db 库名
|
* @param db 库名
|
||||||
* @param dbs 该库所有库名
|
* @param dbs 该库所有库名
|
||||||
*/
|
*/
|
||||||
export function registerDbCompletionItemProvider(language: string, dbId: number, db: string, dbs: [] = []) {
|
export function registerDbCompletionItemProvider(language: string, dbId: number, db: string, dbs: any[] = []) {
|
||||||
registerCompletionItemProvider(language, {
|
registerCompletionItemProvider(language, {
|
||||||
triggerCharacters: ['.', ' '],
|
triggerCharacters: ['.', ' '],
|
||||||
provideCompletionItems: async (model: editor.ITextModel, position: Position): Promise<languages.CompletionList | null | undefined> => {
|
provideCompletionItems: async (model: editor.ITextModel, position: Position): Promise<languages.CompletionList | null | undefined> => {
|
||||||
@@ -518,29 +564,6 @@ export function registerDbCompletionItemProvider(language: string, dbId: number,
|
|||||||
let lastToken = tokens[tokens.length - 1].toLowerCase();
|
let lastToken = tokens[tokens.length - 1].toLowerCase();
|
||||||
const secondToken = (tokens.length > 2 && tokens[tokens.length - 2].toLowerCase()) || '';
|
const secondToken = (tokens.length > 2 && tokens[tokens.length - 2].toLowerCase()) || '';
|
||||||
|
|
||||||
// console.log("光标前文本:=>" + textBeforePointerMulti)
|
|
||||||
// console.log("最后输入的:=>" + lastToken)
|
|
||||||
|
|
||||||
let suggestions: languages.CompletionItem[] = [];
|
|
||||||
|
|
||||||
let alias = '';
|
|
||||||
if (lastToken.indexOf('.') > -1 || secondToken.indexOf('.') > -1) {
|
|
||||||
// 如果是.触发代码提示,则进行【 库.表名联想 】 或 【 表别名.表字段联想 】
|
|
||||||
alias = lastToken.substring(0, lastToken.lastIndexOf('.'));
|
|
||||||
if (lastToken.trim().startsWith('.')) {
|
|
||||||
alias = secondToken;
|
|
||||||
}
|
|
||||||
// 如果字符串粘连起了如:'a.creator,a.',需要重新取出别名
|
|
||||||
let aliasArr = lastToken.split(',');
|
|
||||||
if (aliasArr.length > 1) {
|
|
||||||
lastToken = aliasArr[aliasArr.length - 1];
|
|
||||||
alias = lastToken.substring(0, lastToken.lastIndexOf('.'));
|
|
||||||
if (lastToken.trim().startsWith('.')) {
|
|
||||||
alias = secondToken;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取光标所在行之前的所有文本内容
|
// 获取光标所在行之前的所有文本内容
|
||||||
const textBeforeCursor = model.getValueInRange({
|
const textBeforeCursor = model.getValueInRange({
|
||||||
startLineNumber: 1,
|
startLineNumber: 1,
|
||||||
@@ -579,39 +602,62 @@ export function registerDbCompletionItemProvider(language: string, dbId: number,
|
|||||||
sqlStatement = textBeforeCursor + textAfterCursor;
|
sqlStatement = textBeforeCursor + textAfterCursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableName = getTableName4SqlCtx(sqlStatement, alias);
|
let suggestions: languages.CompletionItem[] = [];
|
||||||
// 提出到表名,则将表对应的字段也添加进提示建议
|
|
||||||
if (tableName) {
|
// 库名提示
|
||||||
let dbHits = await dbInst.loadDbHints(db);
|
if (dbs && dbs.length > 0) {
|
||||||
let columns = dbHits[tableName];
|
dbs.forEach((a: any) => {
|
||||||
columns?.forEach((a: string, index: any) => {
|
|
||||||
// 字段数据格式 字段名 字段注释, 如: create_time [datetime][创建时间]
|
|
||||||
const nameAndComment = a.split(' ');
|
|
||||||
const fieldName = nameAndComment[0];
|
|
||||||
suggestions.push({
|
suggestions.push({
|
||||||
label: {
|
label: {
|
||||||
label: a,
|
label: a,
|
||||||
description: 'column',
|
description: 'schema',
|
||||||
},
|
},
|
||||||
kind: monaco.languages.CompletionItemKind.Property,
|
kind: monaco.languages.CompletionItemKind.Folder,
|
||||||
detail: '', // 不显示detail, 否则选中时备注等会被遮挡
|
insertText: a,
|
||||||
insertText: fieldName, // create_time
|
|
||||||
range,
|
range,
|
||||||
sortText: 100 + index + '', // 使用表字段声明顺序排序,排序需为字符串类型
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 若存在字段提示,并且有别名,则提示字段即可,不完善后续的表名以及函数等
|
let alias = '';
|
||||||
if (suggestions.length > 0 && alias) {
|
if (lastToken.indexOf('.') > -1 || secondToken.indexOf('.') > -1) {
|
||||||
return {
|
// 如果是.触发代码提示,则进行【 库.表名联想 】 或 【 表别名.表字段联想 】
|
||||||
suggestions: suggestions,
|
alias = lastToken.substring(0, lastToken.lastIndexOf('.'));
|
||||||
};
|
if (lastToken.trim().startsWith('.')) {
|
||||||
|
alias = secondToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果字符串粘连起了如:'a.creator,a.',需要重新取出别名
|
||||||
|
let aliasArr = lastToken.split(',');
|
||||||
|
if (aliasArr.length > 1) {
|
||||||
|
lastToken = aliasArr[aliasArr.length - 1];
|
||||||
|
alias = lastToken.substring(0, lastToken.lastIndexOf('.'));
|
||||||
|
if (lastToken.trim().startsWith('.')) {
|
||||||
|
alias = secondToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果是【库.表名联想】.前的字符串是库名
|
||||||
|
if (dbs.indexOf(alias) >= 0) {
|
||||||
|
return await dbInst.loadTableSuggestions(alias, range);
|
||||||
|
}
|
||||||
|
// 表下列名联想 .前的字符串是表名或表别名
|
||||||
|
const sqlInfo = getTableName4SqlCtx(sqlStatement, alias, db);
|
||||||
|
// 提出到表名,则将表对应的字段也添加进提示建议
|
||||||
|
if (sqlInfo) {
|
||||||
|
return await dbInst.loadTableColumnSuggestions(sqlInfo.db, sqlInfo.tableName, range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 空格触发也会提示字段信息
|
||||||
|
const sqlInfo = getTableName4SqlCtx(sqlStatement, alias, db);
|
||||||
|
if (sqlInfo) {
|
||||||
|
const columnSuggestions = await dbInst.loadTableColumnSuggestions(sqlInfo.db, sqlInfo.tableName, range);
|
||||||
|
suggestions.push(...columnSuggestions.suggestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前库的表名联想
|
||||||
const tables = await dbInst.loadTables(db);
|
const tables = await dbInst.loadTables(db);
|
||||||
|
|
||||||
// 表名联想
|
|
||||||
tables.forEach((tableMeta: any, index: any) => {
|
tables.forEach((tableMeta: any, index: any) => {
|
||||||
const { tableName, tableComment } = tableMeta;
|
const { tableName, tableComment } = tableMeta;
|
||||||
suggestions.push({
|
suggestions.push({
|
||||||
@@ -695,21 +741,6 @@ export function registerDbCompletionItemProvider(language: string, dbId: number,
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 库名提示
|
|
||||||
if (dbs && dbs.length > 0) {
|
|
||||||
dbs.forEach((a: any) => {
|
|
||||||
suggestions.push({
|
|
||||||
label: {
|
|
||||||
label: a,
|
|
||||||
description: 'schema',
|
|
||||||
},
|
|
||||||
kind: monaco.languages.CompletionItemKind.Folder,
|
|
||||||
insertText: a,
|
|
||||||
range,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认提示
|
// 默认提示
|
||||||
return {
|
return {
|
||||||
suggestions: suggestions,
|
suggestions: suggestions,
|
||||||
@@ -718,31 +749,33 @@ export function registerDbCompletionItemProvider(language: string, dbId: number,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTableName4SqlCtx(sql: string, alias: string = '') {
|
function getTableName4SqlCtx(sql: string, alias: string = '', defaultDb: string): { tableName: string; tableAlias: string; db: string } | undefined {
|
||||||
// 去除多余的换行、空格和制表符
|
// 去除多余的换行、空格和制表符
|
||||||
sql = sql.replace(/[\r\n\s\t]+/g, ' ');
|
sql = sql.replace(/[\r\n\s\t]+/g, ' ');
|
||||||
|
|
||||||
// 提取所有可能的表名和别名
|
// 提取所有可能的表名和别名
|
||||||
const regex = /(?:(?:FROM|JOIN|UPDATE)\s+(\S+)\s+(?:AS\s+)?(\S+))/gi;
|
const regex = /(?:FROM|JOIN|UPDATE)\s+(\S+)\s+(?:AS\s+)?(\S+)/gi;
|
||||||
let matches;
|
let matches;
|
||||||
const tables = [];
|
const tables = [];
|
||||||
|
|
||||||
// 使用正则表达式匹配所有的表和别名
|
// 使用正则表达式匹配所有的表和别名
|
||||||
while ((matches = regex.exec(sql)) !== null) {
|
while ((matches = regex.exec(sql)) !== null) {
|
||||||
const tableName = matches[1].replace(/[`"]/g, '');
|
let tableName = matches[1].replace(/[`"]/g, '');
|
||||||
|
let db = defaultDb;
|
||||||
|
if (tableName.indexOf('.') >= 0) {
|
||||||
|
let info = tableName.split('.');
|
||||||
|
db = info[0];
|
||||||
|
tableName = info[1];
|
||||||
|
}
|
||||||
const tableAlias = matches[2] ? matches[2].replace(/[`"]/g, '') : tableName;
|
const tableAlias = matches[2] ? matches[2].replace(/[`"]/g, '') : tableName;
|
||||||
tables.push({ tableName, tableAlias });
|
tables.push({ tableName, tableAlias, db });
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('sql....', sql);
|
|
||||||
// console.log('alias....', alias);
|
|
||||||
// console.log('parset tables...', tables);
|
|
||||||
if (alias) {
|
if (alias) {
|
||||||
// 如果指定了别名参数,则返回对应的表名
|
// 如果指定了别名参数,则返回对应的表名
|
||||||
const table = tables.find((t) => t.tableAlias === alias);
|
return tables.find((t) => t.tableAlias === alias);
|
||||||
return table ? table.tableName : '';
|
|
||||||
} else {
|
} else {
|
||||||
// 如果未指定别名参数,则返回第一个表名
|
// 如果未指定别名参数,则返回第一个表名
|
||||||
return tables.length > 0 ? tables[0].tableName : '';
|
return tables.length > 0 ? tables[0] : undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user