mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 07:20:24 +08:00
fix: sql代码提示修复:支持跨schema提示
This commit is contained in:
@@ -93,6 +93,52 @@ export class DbInst {
|
||||
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 表名
|
||||
@@ -482,7 +528,7 @@ export type FieldsMeta = {
|
||||
* @param db 库名
|
||||
* @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, {
|
||||
triggerCharacters: ['.', ' '],
|
||||
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();
|
||||
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({
|
||||
startLineNumber: 1,
|
||||
@@ -579,39 +602,62 @@ export function registerDbCompletionItemProvider(language: string, dbId: number,
|
||||
sqlStatement = textBeforeCursor + textAfterCursor;
|
||||
}
|
||||
|
||||
const tableName = getTableName4SqlCtx(sqlStatement, alias);
|
||||
// 提出到表名,则将表对应的字段也添加进提示建议
|
||||
if (tableName) {
|
||||
let dbHits = await dbInst.loadDbHints(db);
|
||||
let columns = dbHits[tableName];
|
||||
columns?.forEach((a: string, index: any) => {
|
||||
// 字段数据格式 字段名 字段注释, 如: create_time [datetime][创建时间]
|
||||
const nameAndComment = a.split(' ');
|
||||
const fieldName = nameAndComment[0];
|
||||
let suggestions: languages.CompletionItem[] = [];
|
||||
|
||||
// 库名提示
|
||||
if (dbs && dbs.length > 0) {
|
||||
dbs.forEach((a: any) => {
|
||||
suggestions.push({
|
||||
label: {
|
||||
label: a,
|
||||
description: 'column',
|
||||
description: 'schema',
|
||||
},
|
||||
kind: monaco.languages.CompletionItemKind.Property,
|
||||
detail: '', // 不显示detail, 否则选中时备注等会被遮挡
|
||||
insertText: fieldName, // create_time
|
||||
kind: monaco.languages.CompletionItemKind.Folder,
|
||||
insertText: a,
|
||||
range,
|
||||
sortText: 100 + index + '', // 使用表字段声明顺序排序,排序需为字符串类型
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 若存在字段提示,并且有别名,则提示字段即可,不完善后续的表名以及函数等
|
||||
if (suggestions.length > 0 && alias) {
|
||||
return {
|
||||
suggestions: suggestions,
|
||||
};
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是【库.表名联想】.前的字符串是库名
|
||||
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 tables = await dbInst.loadTables(db);
|
||||
// 空格触发也会提示字段信息
|
||||
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);
|
||||
tables.forEach((tableMeta: any, index: any) => {
|
||||
const { tableName, tableComment } = tableMeta;
|
||||
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 {
|
||||
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, ' ');
|
||||
|
||||
// 提取所有可能的表名和别名
|
||||
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;
|
||||
const tables = [];
|
||||
|
||||
// 使用正则表达式匹配所有的表和别名
|
||||
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;
|
||||
tables.push({ tableName, tableAlias });
|
||||
tables.push({ tableName, tableAlias, db });
|
||||
}
|
||||
|
||||
// console.log('sql....', sql);
|
||||
// console.log('alias....', alias);
|
||||
// console.log('parset tables...', tables);
|
||||
if (alias) {
|
||||
// 如果指定了别名参数,则返回对应的表名
|
||||
const table = tables.find((t) => t.tableAlias === alias);
|
||||
return table ? table.tableName : '';
|
||||
return tables.find((t) => t.tableAlias === alias);
|
||||
} else {
|
||||
// 如果未指定别名参数,则返回第一个表名
|
||||
return tables.length > 0 ? tables[0].tableName : '';
|
||||
return tables.length > 0 ? tables[0] : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user