Skip to content

Commit 0002529

Browse files
committed
tmp
1 parent ae8aa6d commit 0002529

File tree

6 files changed

+793
-12
lines changed

6 files changed

+793
-12
lines changed
Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
import type {
2+
ColumnAliasSuggestion,
3+
KeywordSuggestion,
4+
VariableSuggestion,
5+
} from '@gravity-ui/websql-autocomplete/shared';
6+
import type {YqlAutocompleteResult} from '@gravity-ui/websql-autocomplete/yql';
7+
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
8+
9+
import type {FetchedColumn, FetchedEntity} from './types';
10+
import {
11+
getSuggestionIndex,
12+
isVariable,
13+
suggestionIndexToWeight,
14+
wrapStringToBackticks,
15+
} from './utils';
16+
17+
export async function generateSimpleTypesSuggestion(
18+
rangeToInsertSuggestion: monaco.IRange,
19+
simpleTypes: string[] = [],
20+
): Promise<monaco.languages.CompletionItem[]> {
21+
return simpleTypes.map((el) => ({
22+
label: el,
23+
insertText: el,
24+
kind: monaco.languages.CompletionItemKind.TypeParameter,
25+
detail: 'Type',
26+
range: rangeToInsertSuggestion,
27+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestSimpleTypes')),
28+
}));
29+
}
30+
31+
export async function generateEntitiesSuggestion(
32+
rangeToInsertSuggestion: monaco.IRange,
33+
fetchedEntities: FetchedEntity[],
34+
prefix: string,
35+
): Promise<monaco.languages.CompletionItem[]> {
36+
const withBackticks = prefix?.startsWith('`');
37+
38+
return fetchedEntities.reduce<monaco.languages.CompletionItem[]>(
39+
(acc, {value, detail, isDir}) => {
40+
const label = isDir ? `${value}/` : value;
41+
let labelAsSnippet;
42+
if (isDir && !withBackticks) {
43+
labelAsSnippet = `\`${label}$0\``;
44+
}
45+
const suggestionIndex = acc.length;
46+
acc.push({
47+
label,
48+
insertText: labelAsSnippet ?? label,
49+
kind: isDir
50+
? monaco.languages.CompletionItemKind.Folder
51+
: monaco.languages.CompletionItemKind.Text,
52+
insertTextRules: labelAsSnippet
53+
? monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
54+
: monaco.languages.CompletionItemInsertTextRule.None,
55+
detail: detail,
56+
range: rangeToInsertSuggestion,
57+
command: label.endsWith('/')
58+
? {id: 'editor.action.triggerSuggest', title: ''}
59+
: undefined,
60+
// first argument is responsible for sorting groups of suggestions, the second - to preserve suggestions order returned from backend
61+
sortText:
62+
suggestionIndexToWeight(getSuggestionIndex('suggestEntity')) +
63+
suggestionIndexToWeight(suggestionIndex),
64+
});
65+
return acc;
66+
},
67+
[],
68+
);
69+
}
70+
71+
export function generateKeywordsSuggestion(
72+
rangeToInsertSuggestion: monaco.IRange,
73+
suggestKeywords?: KeywordSuggestion[],
74+
) {
75+
if (!suggestKeywords) {
76+
return [];
77+
}
78+
return suggestKeywords.map((keywordSuggestion) => ({
79+
label: keywordSuggestion.value,
80+
insertText: keywordSuggestion.value,
81+
kind: monaco.languages.CompletionItemKind.Keyword,
82+
detail: 'Keyword',
83+
range: rangeToInsertSuggestion,
84+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestKeywords')),
85+
}));
86+
}
87+
88+
export function generateVariableSuggestion(
89+
rangeToInsertSuggestion: monaco.IRange,
90+
suggestVariables?: VariableSuggestion[],
91+
) {
92+
if (!suggestVariables) {
93+
return [];
94+
}
95+
return suggestVariables.map(({name}) => {
96+
const variable = '$' + name;
97+
return {
98+
label: variable,
99+
insertText: variable,
100+
kind: monaco.languages.CompletionItemKind.Variable,
101+
detail: 'Variable',
102+
range: rangeToInsertSuggestion,
103+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestVariables')),
104+
};
105+
});
106+
}
107+
108+
export async function generateSimpleFunctionsSuggestion(
109+
rangeToInsertSuggestion: monaco.IRange,
110+
functions: string[] = [],
111+
): Promise<monaco.languages.CompletionItem[]> {
112+
return functions.map((el) => ({
113+
label: el,
114+
insertText: el,
115+
kind: monaco.languages.CompletionItemKind.Function,
116+
detail: 'Function',
117+
range: rangeToInsertSuggestion,
118+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestFunctions')),
119+
}));
120+
}
121+
122+
export async function generateAggregateFunctionsSuggestion(
123+
rangeToInsertSuggestion: monaco.IRange,
124+
aggreagteFunctions: string[] = [],
125+
): Promise<monaco.languages.CompletionItem[]> {
126+
return aggreagteFunctions.map((el) => ({
127+
label: el,
128+
insertText: el,
129+
kind: monaco.languages.CompletionItemKind.Function,
130+
detail: 'Aggregate function',
131+
range: rangeToInsertSuggestion,
132+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestAggregateFunctions')),
133+
}));
134+
}
135+
136+
export async function generateWindowFunctionsSuggestion(
137+
rangeToInsertSuggestion: monaco.IRange,
138+
windowFunctions: string[] = [],
139+
): Promise<monaco.languages.CompletionItem[]> {
140+
return windowFunctions.map((el) => ({
141+
label: el,
142+
insertText: el,
143+
kind: monaco.languages.CompletionItemKind.Function,
144+
detail: 'Window function',
145+
range: rangeToInsertSuggestion,
146+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestWindowFunctions')),
147+
}));
148+
}
149+
150+
export async function generateTableFunctionsSuggestion(
151+
rangeToInsertSuggestion: monaco.IRange,
152+
tableFunctions: string[] = [],
153+
): Promise<monaco.languages.CompletionItem[]> {
154+
return tableFunctions.map((el) => ({
155+
label: el,
156+
insertText: el,
157+
kind: monaco.languages.CompletionItemKind.Function,
158+
detail: 'Table function',
159+
range: rangeToInsertSuggestion,
160+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestTableFunctions')),
161+
}));
162+
}
163+
164+
export async function generateUdfSuggestion(
165+
rangeToInsertSuggestion: monaco.IRange,
166+
udfs: string[] = [],
167+
): Promise<monaco.languages.CompletionItem[]> {
168+
return udfs.map((el) => ({
169+
label: el,
170+
insertText: el,
171+
kind: monaco.languages.CompletionItemKind.Function,
172+
detail: 'UDF',
173+
range: rangeToInsertSuggestion,
174+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestUdfs')),
175+
}));
176+
}
177+
178+
export async function generatePragmasSuggestion(
179+
rangeToInsertSuggestion: monaco.IRange,
180+
pragmas: string[] = [],
181+
): Promise<monaco.languages.CompletionItem[]> {
182+
return pragmas.map((el) => ({
183+
label: el,
184+
insertText: el,
185+
kind: monaco.languages.CompletionItemKind.Module,
186+
detail: 'Pragma',
187+
range: rangeToInsertSuggestion,
188+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestPragmas')),
189+
}));
190+
}
191+
192+
export async function generateEntitySettingsSuggestion(
193+
rangeToInsertSuggestion: monaco.IRange,
194+
entitySettings: string[] = [],
195+
): Promise<monaco.languages.CompletionItem[]> {
196+
return entitySettings.map((el) => ({
197+
label: el,
198+
insertText: el,
199+
kind: monaco.languages.CompletionItemKind.Property,
200+
detail: 'Setting',
201+
range: rangeToInsertSuggestion,
202+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestEntitySettings')),
203+
}));
204+
}
205+
206+
export function generateColumnAliasesSuggestion(
207+
rangeToInsertSuggestion: monaco.IRange,
208+
suggestColumnAliases: ColumnAliasSuggestion[] = [],
209+
) {
210+
return suggestColumnAliases.map((columnAliasSuggestion) => ({
211+
label: columnAliasSuggestion.name,
212+
insertText: columnAliasSuggestion.name,
213+
kind: monaco.languages.CompletionItemKind.Variable,
214+
detail: 'Column alias',
215+
range: rangeToInsertSuggestion,
216+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestColumnAliases')),
217+
}));
218+
}
219+
220+
export async function generateColumnsSuggestion(
221+
rangeToInsertSuggestion: monaco.IRange,
222+
suggestColumns: YqlAutocompleteResult['suggestColumns'],
223+
suggestVariables: YqlAutocompleteResult['suggestVariables'],
224+
fetchedColumns: FetchedColumn[],
225+
): Promise<monaco.languages.CompletionItem[]> {
226+
if (!suggestColumns?.tables) {
227+
return [];
228+
}
229+
const suggestions: monaco.languages.CompletionItem[] = [];
230+
const allColumnsSuggestion = suggestColumns.all ? ([] as string[]) : undefined;
231+
const multi = suggestColumns.tables.length > 1;
232+
233+
const tableNames = suggestColumns.tables.map((entity) => entity.name);
234+
const filteredTableNames = Array.from(new Set(tableNames));
235+
236+
const variableSources = filteredTableNames.filter(isVariable);
237+
238+
const columnsFromVariable: FetchedColumn[] = [];
239+
if (variableSources.length) {
240+
variableSources.forEach((source) => {
241+
const newColumns =
242+
suggestVariables
243+
// Variable name from suggestions doesn't include $ sign
244+
?.find((variable) => source.slice(1) === variable.name)
245+
?.value?.columns?.map((col) => ({
246+
name: col,
247+
parent: source,
248+
})) ?? [];
249+
columnsFromVariable.push(...newColumns);
250+
});
251+
}
252+
253+
const predefinedColumns: FetchedColumn[] = suggestColumns.tables.reduce<FetchedColumn[]>(
254+
(acc, entity) => {
255+
const columns = entity.columns;
256+
if (columns) {
257+
acc.push(
258+
...columns.map((col) => ({
259+
name: col,
260+
parent: entity.name,
261+
})),
262+
);
263+
}
264+
return acc;
265+
},
266+
[],
267+
);
268+
269+
const tableNameToAliasMap = suggestColumns.tables?.reduce(
270+
(acc, entity) => {
271+
const name = entity.name;
272+
const aliases = acc[name] ?? [];
273+
if (entity.alias) {
274+
aliases.push(entity.alias);
275+
}
276+
acc[name] = aliases;
277+
return acc;
278+
},
279+
{} as Record<string, string[]>,
280+
);
281+
282+
[...fetchedColumns, ...columnsFromVariable, ...predefinedColumns].forEach((col) => {
283+
const normalizedName = wrapStringToBackticks(col.name);
284+
285+
const aliases = tableNameToAliasMap[col.parent];
286+
const currentSuggestionIndex = suggestions.length;
287+
if (aliases?.length) {
288+
aliases.forEach((a) => {
289+
const columnNameSuggestion = `${a}.${normalizedName}`;
290+
suggestions.push({
291+
label: {label: columnNameSuggestion, description: col.detail},
292+
insertText: columnNameSuggestion,
293+
kind: monaco.languages.CompletionItemKind.Variable,
294+
detail: 'Column',
295+
range: rangeToInsertSuggestion,
296+
sortText:
297+
suggestionIndexToWeight(getSuggestionIndex('suggestColumns')) +
298+
suggestionIndexToWeight(currentSuggestionIndex),
299+
});
300+
allColumnsSuggestion?.push(columnNameSuggestion);
301+
});
302+
} else {
303+
let columnNameSuggestion = normalizedName;
304+
if (multi) {
305+
columnNameSuggestion = `${wrapStringToBackticks(col.parent)}.${normalizedName}`;
306+
}
307+
suggestions.push({
308+
label: {
309+
label: columnNameSuggestion,
310+
description: col.detail,
311+
},
312+
insertText: columnNameSuggestion,
313+
kind: monaco.languages.CompletionItemKind.Variable,
314+
detail: 'Column',
315+
range: rangeToInsertSuggestion,
316+
sortText:
317+
suggestionIndexToWeight(getSuggestionIndex('suggestColumns')) +
318+
suggestionIndexToWeight(currentSuggestionIndex),
319+
});
320+
allColumnsSuggestion?.push(columnNameSuggestion);
321+
}
322+
});
323+
if (allColumnsSuggestion && allColumnsSuggestion.length > 1) {
324+
const allColumns = allColumnsSuggestion.join(', ');
325+
suggestions.push({
326+
label: allColumns,
327+
insertText: allColumns,
328+
kind: monaco.languages.CompletionItemKind.Variable,
329+
range: rangeToInsertSuggestion,
330+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestAllColumns')),
331+
});
332+
}
333+
return suggestions;
334+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import type {YQLEntity} from '@gravity-ui/websql-autocomplete/yql';
2+
3+
export type CursorPosition = {lineNumber: number; column: number};
4+
5+
export type AutocompleteEntityType = YQLEntity | 'directory';
6+
7+
export type FetchedEntity = {
8+
value: string;
9+
autocompleteType?: AutocompleteEntityType;
10+
isDir?: boolean;
11+
detail?: string;
12+
};
13+
14+
export type FetchedColumn = {name: string; detail?: string; parent: string};
15+
16+
type ConstantsGetter = () => string[] | Promise<string[]>;
17+
18+
export type AutocompleteConstant =
19+
| 'types'
20+
| 'windowFunctions'
21+
| 'udfs'
22+
| 'pragmas'
23+
| 'simpleFunctions'
24+
| 'tableFunctions'
25+
| 'aggregateFunctions';
26+
27+
export type AutocompleteConstantsInit = Partial<
28+
Record<AutocompleteConstant, string[] | ConstantsGetter>
29+
>;
30+
export type AutocompleteConstants = Partial<Record<AutocompleteConstant, string[]>>;

0 commit comments

Comments
 (0)