Skip to content

Commit 8071ec7

Browse files
committed
chore: duplicate logic from library
1 parent ae8aa6d commit 8071ec7

File tree

4 files changed

+730
-0
lines changed

4 files changed

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

0 commit comments

Comments
 (0)