Skip to content

Commit 1095d96

Browse files
authored
feat(autocomplete): suggest columns from subqueries (#1788)
1 parent 7fca7d2 commit 1095d96

File tree

4 files changed

+68
-21
lines changed

4 files changed

+68
-21
lines changed

package-lock.json

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"@gravity-ui/react-data-table": "^2.1.1",
2525
"@gravity-ui/table": "^1.7.0",
2626
"@gravity-ui/uikit": "^6.33.0",
27-
"@gravity-ui/websql-autocomplete": "^12.7.0",
27+
"@gravity-ui/websql-autocomplete": "^13.1.0",
2828
"@hookform/resolvers": "^3.9.0",
2929
"@reduxjs/toolkit": "^2.2.3",
3030
"@tanstack/react-table": "^8.19.3",

src/utils/monaco/yql/generateSuggestions.ts

+62-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {
22
ColumnAliasSuggestion,
33
KeywordSuggestion,
4+
VariableSuggestion,
45
} from '@gravity-ui/websql-autocomplete/shared';
56
import type {YQLEntity, YqlAutocompleteResult} from '@gravity-ui/websql-autocomplete/yql';
67
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
@@ -107,6 +108,10 @@ function removeBackticks(value: string) {
107108
return value.slice(sliceStart, sliceEnd);
108109
}
109110

111+
function isVariable(value: string) {
112+
return value.startsWith('$');
113+
}
114+
110115
function removeStartSlash(value: string) {
111116
if (value.startsWith('/')) {
112117
return value.slice(1);
@@ -199,7 +204,8 @@ function getColumnDetails(col: AutocompleteColumn) {
199204

200205
export async function generateColumnsSuggestion(
201206
rangeToInsertSuggestion: monaco.IRange,
202-
suggestColumns: YqlAutocompleteResult['suggestColumns'] | undefined,
207+
suggestColumns: YqlAutocompleteResult['suggestColumns'],
208+
suggestVariables: YqlAutocompleteResult['suggestVariables'],
203209
database: string,
204210
): Promise<monaco.languages.CompletionItem[]> {
205211
if (!suggestColumns?.tables) {
@@ -209,27 +215,67 @@ export async function generateColumnsSuggestion(
209215
const normalizedColumns = suggestColumns.all ? ([] as string[]) : undefined;
210216
const multi = suggestColumns.tables.length > 1;
211217

212-
const normalizedTableNames =
218+
const normalizedSuggestions =
213219
suggestColumns.tables?.map((entity) => {
214220
let normalizedEntityName = removeBackticks(entity.name);
215-
if (!normalizedEntityName.endsWith('/')) {
221+
if (!normalizedEntityName.endsWith('/') && !isVariable(normalizedEntityName)) {
216222
normalizedEntityName = `${normalizedEntityName}/`;
217223
}
218-
return normalizeEntityPrefix(normalizedEntityName, database);
224+
return {...entity, name: normalizeEntityPrefix(normalizedEntityName, database)};
219225
}) ?? [];
220226

227+
const normalizedTableNames = normalizedSuggestions.map((entity) => entity.name);
228+
221229
// remove duplicates if any
222230
const filteredTableNames = Array.from(new Set(normalizedTableNames));
223231

224-
const autocompleteResponse = await window.api.viewer.autocomplete({
225-
database,
226-
table: filteredTableNames,
227-
limit: 1000,
228-
});
229-
if (!autocompleteResponse.Success) {
230-
return [];
232+
const tableSources = filteredTableNames.filter((name) => !isVariable(name));
233+
234+
let autocompleteEntities: TAutocompleteEntity[] = [];
235+
if (tableSources.length) {
236+
const autocompleteResponse = await window.api.viewer.autocomplete({
237+
database,
238+
table: tableSources,
239+
limit: 1000,
240+
});
241+
if (autocompleteResponse.Success) {
242+
autocompleteEntities = autocompleteResponse.Result.Entities ?? [];
243+
}
244+
}
245+
246+
const variableSources = filteredTableNames.filter(isVariable);
247+
const columnsFromVariable: TAutocompleteEntity[] = [];
248+
if (variableSources.length) {
249+
variableSources.forEach((source) => {
250+
const newColumns =
251+
suggestVariables
252+
// Variable name from suggestions doesn't include $ sign
253+
?.find((variable) => source.slice(1) === variable.name)
254+
?.value?.columns?.map((col) => ({
255+
Name: col,
256+
Type: 'column' as const,
257+
Parent: source,
258+
})) ?? [];
259+
columnsFromVariable.push(...newColumns);
260+
});
231261
}
232262

263+
const predefinedColumns: TAutocompleteEntity[] = normalizedSuggestions.reduce<
264+
TAutocompleteEntity[]
265+
>((acc, entity) => {
266+
const columns = entity.columns;
267+
if (columns) {
268+
acc.push(
269+
...columns.map((col) => ({
270+
Name: col,
271+
Type: 'column' as const,
272+
Parent: entity.name,
273+
})),
274+
);
275+
}
276+
return acc;
277+
}, []);
278+
233279
const tableNameToAliasMap = suggestColumns.tables?.reduce(
234280
(acc, entity) => {
235281
const normalizedEntityName = normalizeEntityPrefix(
@@ -246,7 +292,7 @@ export async function generateColumnsSuggestion(
246292
{} as Record<string, string[]>,
247293
);
248294

249-
autocompleteResponse.Result.Entities?.forEach((col) => {
295+
[...autocompleteEntities, ...columnsFromVariable, ...predefinedColumns].forEach((col) => {
250296
if (!isAutocompleteColumn(col)) {
251297
return;
252298
}
@@ -293,7 +339,7 @@ export async function generateColumnsSuggestion(
293339
normalizedColumns?.push(columnNameSuggestion);
294340
}
295341
});
296-
if (normalizedColumns && normalizedColumns.length > 0) {
342+
if (normalizedColumns && normalizedColumns.length > 1) {
297343
const allColumns = normalizedColumns.join(', ');
298344
suggestions.push({
299345
label: allColumns,
@@ -341,13 +387,13 @@ export function generateKeywordsSuggestion(
341387

342388
export function generateVariableSuggestion(
343389
rangeToInsertSuggestion: monaco.IRange,
344-
suggestVariables?: string[],
390+
suggestVariables?: VariableSuggestion[],
345391
) {
346392
if (!suggestVariables) {
347393
return [];
348394
}
349-
return suggestVariables.map((rawVariable) => {
350-
const variable = '$' + rawVariable;
395+
return suggestVariables.map(({name}) => {
396+
const variable = '$' + name;
351397
return {
352398
label: variable,
353399
insertText: variable,

src/utils/monaco/yql/yqlSuggestions.ts

+1
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ async function getSuggestions(
128128
const columnsSuggestions = await generateColumnsSuggestion(
129129
rangeToInsertSuggestion,
130130
parseResult.suggestColumns,
131+
parseResult.suggestVariables,
131132
database,
132133
);
133134

0 commit comments

Comments
 (0)