fix(plugin-sql-editor): reduce server calls

This commit is contained in:
Wroud
2022-04-05 14:04:32 +03:00
parent 152c1fb8e3
commit 1c992d1b60
3 changed files with 80 additions and 19 deletions
@@ -316,6 +316,11 @@ export class SQLParser {
return this;
}
isEndsWithDelimiter(): boolean {
this.update();
return this.scriptDelimiters.some(delimiter => this.parsedScript?.endsWith(delimiter));
}
private update() {
if (this.parsedScript !== this.script) {
this.parse(this.script);
@@ -18,14 +18,19 @@ import { action } from 'mobx';
import type { IControlledCodeMirror } from 'react-codemirror2';
import { useExecutor, useObservableRef } from '@cloudbeaver/core-blocks';
import { throttleAsync } from '@cloudbeaver/core-utils';
import type { SqlCompletionProposal } from '@cloudbeaver/core-sdk';
import type { SQLCodeEditorController } from '../SQLCodeEditor/SQLCodeEditorController';
import type { ISQLEditorData } from '../useSqlEditor';
interface ISQLCodeEditorPanelData {
proposalsWordFrom: Position | null;
proposalsWord: string | null;
proposalsMode: boolean | null;
proposals: SqlCompletionProposal[] | null;
readonly activeSuggest: boolean;
readonly bindings: Omit<IControlledCodeMirror, 'value'>;
closeHint(): void;
}
interface ISQLCodeEditorPanelDataPrivate extends ISQLCodeEditorPanelData {
@@ -46,6 +51,7 @@ export function useSQLCodeEditorPanel(
controller: SQLCodeEditorController | null
): ISQLCodeEditorPanelData {
const editorPanelData = useObservableRef<ISQLCodeEditorPanelDataPrivate>(() => ({
proposals: null,
activeSuggest: true,
options: {
theme: 'material',
@@ -121,7 +127,7 @@ export function useSQLCodeEditorPanel(
const nextCursor = editor.getCursor('from');
if (nextCursor.line !== lastChange.from.line) {
editor.closeHint();
this.closeHint();
return;
}
@@ -155,7 +161,7 @@ export function useSQLCodeEditorPanel(
cursor = from;
if (closeCharacters.test(ch) || from.line !== cursor.line) {
editor.closeHint();
this.closeHint();
} else {
editor.state.completionActive.update();
}
@@ -167,6 +173,16 @@ export function useSQLCodeEditorPanel(
this.highlightActiveQuery();
},
closeHint() {
const editor = this.controller?.getEditor();
if (!editor) {
return;
}
editor.closeHint();
},
async showHint(activeSuggest: boolean) {
const editor = this.controller?.getEditor();
@@ -191,24 +207,62 @@ export function useSQLCodeEditorPanel(
},
getHandleAutocomplete: throttleAsync(async function getHandleAutocomplete(
async getHandleAutocomplete(
editor: Editor,
options: ShowHintOptions
): Promise<Hints | undefined> {
const cursor = editor.getCursor('from');
const cursorPosition = getAbsolutePosition(editor, cursor);
const [from, to, word] = getWordRange(editor, cursor);
let proposals = await editorPanelData.data.getHintProposals(cursorPosition, !options.completeSingle);
proposals = proposals.filter(
({ displayString }) => displayString.toLocaleLowerCase() !== word.toLocaleLowerCase()
const cursorPosition = getAbsolutePosition(
editor, word.length > 0
? { ...from, ch: from.ch + 1 }
: from
);
if (proposals.length === 0) {
return;
const proposalWord = word.slice(0, 1);
let proposals = editorPanelData.proposals;
if (
proposals === null
|| editorPanelData.proposalsWord !== proposalWord
|| editorPanelData.proposalsMode !== options.completeSingle
|| editorPanelData.proposalsWordFrom?.ch !== from.ch
|| editorPanelData.proposalsWordFrom.line !== from.line
|| !word.startsWith(editorPanelData.proposalsWord)
) {
const proposalsMode = options.completeSingle ?? false;
editorPanelData.proposalsMode = proposalsMode;
editorPanelData.proposalsWord = proposalWord;
editorPanelData.proposalsWordFrom = from;
editorPanelData.proposals = [];
proposals = await editorPanelData.data.getHintProposals(cursorPosition, !options.completeSingle);
if (
editorPanelData.proposalsWord === proposalWord
&& editorPanelData.proposalsWordFrom === from
&& editorPanelData.proposalsMode === proposalsMode
) {
editorPanelData.proposals = proposals;
if (editor.state.completionActive && proposals.length > 0) {
editor.state.completionActive.update();
return;
}
}
}
proposals = proposals.filter(
({ displayString }) => (
displayString.toLocaleLowerCase() !== word.toLocaleLowerCase()
&& displayString.toLocaleLowerCase().startsWith(word.toLocaleLowerCase())
)
);
// if (proposals.length === 0) {
// return;
// }
const hints: Hints = {
from,
to,
@@ -219,7 +273,7 @@ export function useSQLCodeEditorPanel(
};
return hints;
}, 1000 / 3),
},
highlightActiveQuery() {
this.controller?.highlightSegment(true);
@@ -249,7 +303,7 @@ export function useSQLCodeEditorPanel(
useExecutor({
executor: data.onExecute,
handlers: [function updateHighlight() {
controller?.getEditor()?.closeHint();
editorPanelData.closeHint();
controller?.resetLineStateHighlight();
}],
});
@@ -188,7 +188,7 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
this.onUpdate.execute();
},
async getHintProposals(position, simple) {
getHintProposals: throttleAsync(async function getHintProposals(this: ISQLEditorDataPrivate, position, simple) {
if (!this.state.executionContext) {
return [];
}
@@ -204,7 +204,7 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
);
return proposals;
},
}, 1000 / 3),
async formatScript(): Promise<void> {
if (this.isDisabled || this.isScriptEmpty || !this.state.executionContext) {
@@ -225,8 +225,8 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
this.setQuery(
query.substring(0, script.begin)
+ formatted
+ query.substring(script.end)
+ formatted
+ query.substring(script.end)
);
} finally {
this.readonlyState = false;
@@ -333,7 +333,9 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
setQuery(query: string): void {
this.state.query = query;
this.parser.setScript(query);
this.updateParserScriptsThrottle();
if (this.parser.isEndsWithDelimiter()) {
this.updateParserScriptsThrottle();
}
this.onUpdate.execute();
},