ydb-embedded-ui 6.0.1 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CriticalActionDialog/CriticalActionDialog.scss +0 -2
- package/dist/containers/PDiskPage/PDiskPage.js +6 -1
- package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +2 -1
- package/dist/containers/Tenant/Query/QueryEditor/helpers.js +4 -3
- package/dist/containers/Tenant/Tenant.js +1 -1
- package/dist/containers/UserSettings/i18n/en.json +2 -0
- package/dist/containers/UserSettings/i18n/index.d.ts +1 -1
- package/dist/containers/UserSettings/settings.d.ts +1 -0
- package/dist/containers/UserSettings/settings.js +7 -2
- package/dist/services/api.d.ts +9 -1
- package/dist/services/api.js +5 -0
- package/dist/services/settings.js +2 -1
- package/dist/types/api/autocomplete.d.ts +21 -0
- package/dist/types/api/autocomplete.js +1 -0
- package/dist/types/api/restartPDisk.d.ts +4 -0
- package/dist/types/api/restartPDisk.js +1 -0
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.js +1 -0
- package/dist/utils/monaco/index.js +2 -0
- package/dist/utils/monaco/{yqlSuggestions → yql}/constants.d.ts +1 -0
- package/dist/utils/monaco/{yqlSuggestions → yql}/constants.js +1 -0
- package/dist/utils/monaco/{yqlSuggestions → yql}/generateSuggestions.d.ts +3 -3
- package/dist/utils/monaco/{yqlSuggestions → yql}/generateSuggestions.js +124 -64
- package/dist/utils/monaco/yql/registerLanguage.d.ts +1 -0
- package/dist/utils/monaco/yql/registerLanguage.js +8 -0
- package/dist/utils/monaco/{yqlSuggestions/registerCompletionItemProvider.js → yql/yql.completionItemProvider.js} +3 -2
- package/dist/utils/monaco/yql/yql.d.ts +7 -0
- package/dist/utils/monaco/yql/yql.js +180 -0
- package/dist/utils/monaco/yql/yql.keywords.d.ts +3 -0
- package/dist/utils/monaco/yql/yql.keywords.js +3 -0
- package/dist/utils/monaco/{yqlSuggestions → yql}/yqlSuggestions.js +14 -7
- package/package.json +3 -3
- /package/dist/utils/monaco/{yqlSuggestions/registerCompletionItemProvider.d.ts → yql/yql.completionItemProvider.d.ts} +0 -0
- /package/dist/utils/monaco/{yqlSuggestions → yql}/yqlSuggestions.d.ts +0 -0
@@ -46,7 +46,12 @@ export function PDiskPage() {
|
|
46
46
|
const groupsData = (_a = pDiskStorageQuery.currentData) !== null && _a !== void 0 ? _a : [];
|
47
47
|
const handleRestart = async () => {
|
48
48
|
if (valueIsDefined(nodeId) && valueIsDefined(pDiskId)) {
|
49
|
-
return window.api.restartPDisk(nodeId, pDiskId)
|
49
|
+
return window.api.restartPDisk(nodeId, pDiskId).then((res) => {
|
50
|
+
if ((res === null || res === void 0 ? void 0 : res.result) === false) {
|
51
|
+
const err = { statusText: res.error };
|
52
|
+
throw err;
|
53
|
+
}
|
54
|
+
});
|
50
55
|
}
|
51
56
|
return undefined;
|
52
57
|
};
|
@@ -10,6 +10,7 @@ import { setShowPreview } from '../../../../store/reducers/schema/schema';
|
|
10
10
|
import { cn } from '../../../../utils/cn';
|
11
11
|
import { DEFAULT_IS_QUERY_RESULT_COLLAPSED, DEFAULT_SIZE_RESULT_PANE_KEY, LAST_USED_QUERY_ACTION_KEY, QUERY_USE_MULTI_SCHEMA_KEY, SAVED_QUERIES_KEY, } from '../../../../utils/constants';
|
12
12
|
import { useQueryModes, useSetting } from '../../../../utils/hooks';
|
13
|
+
import { LANGUAGE_YQL_ID } from '../../../../utils/monaco/yql/constants';
|
13
14
|
import { QUERY_ACTIONS } from '../../../../utils/query';
|
14
15
|
import { parseJson } from '../../../../utils/utils';
|
15
16
|
import { PaneVisibilityActionTypes, paneVisibilityToggleReducerCreator, } from '../../utils/paneVisibilityToggleHelpers';
|
@@ -286,7 +287,7 @@ function QueryEditor(props) {
|
|
286
287
|
};
|
287
288
|
return (_jsx("div", { className: b(), children: _jsxs(SplitPane, { direction: "vertical", defaultSizePaneKey: DEFAULT_SIZE_RESULT_PANE_KEY, triggerCollapse: resultVisibilityState.triggerCollapse, triggerExpand: resultVisibilityState.triggerExpand, minSize: [0, 52], collapsedSizes: [100, 0], onSplitStartDragAdditional: onSplitStartDragAdditional, children: [_jsxs("div", { className: b('pane-wrapper', {
|
288
289
|
top: true,
|
289
|
-
}), children: [_jsx("div", { className: b('monaco-wrapper'), children: _jsx("div", { className: b('monaco'), children: _jsx(MonacoEditor, { language:
|
290
|
+
}), children: [_jsx("div", { className: b('monaco-wrapper'), children: _jsx("div", { className: b('monaco'), children: _jsx(MonacoEditor, { language: LANGUAGE_YQL_ID, value: executeQuery.input, options: editorOptions, onChange: onChange, editorDidMount: editorDidMount, theme: `vs-${theme}` }) }) }), renderControls()] }), _jsx("div", { className: b('pane-wrapper'), children: _jsx(Result, { executeQuery: executeQuery, explainQuery: explainQuery, resultVisibilityState: resultVisibilityState, onExpandResultHandler: onExpandResultHandler, onCollapseResultHandler: onCollapseResultHandler, type: type, handleAstQuery: handleAstQuery, theme: theme, resultType: resultType, path: path, showPreview: showPreview }) })] }) }));
|
290
291
|
}
|
291
292
|
const mapStateToProps = (state) => {
|
292
293
|
return {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { ENABLE_AUTOCOMPLETE, useSetting } from '../../../../lib';
|
2
|
+
import { AUTOCOMPLETE_ON_ENTER, ENABLE_AUTOCOMPLETE, useSetting } from '../../../../lib';
|
3
3
|
export const EDITOR_OPTIONS = {
|
4
4
|
automaticLayout: true,
|
5
5
|
selectOnLineNumbers: true,
|
@@ -9,9 +9,10 @@ export const EDITOR_OPTIONS = {
|
|
9
9
|
};
|
10
10
|
export function useEditorOptions() {
|
11
11
|
const [enableAutocomplete] = useSetting(ENABLE_AUTOCOMPLETE);
|
12
|
+
const [autocompleteOnEnter] = useSetting(AUTOCOMPLETE_ON_ENTER);
|
12
13
|
const options = React.useMemo(() => {
|
13
14
|
const useAutocomplete = Boolean(enableAutocomplete);
|
14
|
-
return Object.assign({ quickSuggestions: useAutocomplete, suggestOnTriggerCharacters: useAutocomplete }, EDITOR_OPTIONS);
|
15
|
-
}, [enableAutocomplete]);
|
15
|
+
return Object.assign({ quickSuggestions: useAutocomplete, suggestOnTriggerCharacters: useAutocomplete, acceptSuggestionOnEnter: autocompleteOnEnter ? 'on' : 'off' }, EDITOR_OPTIONS);
|
16
|
+
}, [enableAutocomplete, autocompleteOnEnter]);
|
16
17
|
return options;
|
17
18
|
}
|
@@ -47,7 +47,7 @@ function Tenant(props) {
|
|
47
47
|
React.useEffect(() => {
|
48
48
|
if (tenantName && typeof tenantName === 'string' && previousTenant.current !== tenantName) {
|
49
49
|
const register = async () => {
|
50
|
-
const { registerYQLCompletionItemProvider } = await import('../../utils/monaco/
|
50
|
+
const { registerYQLCompletionItemProvider } = await import('../../utils/monaco/yql/yql.completionItemProvider');
|
51
51
|
registerYQLCompletionItemProvider(tenantName);
|
52
52
|
};
|
53
53
|
register().catch(console.error);
|
@@ -7,6 +7,8 @@
|
|
7
7
|
"section.dev-setting": "Development settings",
|
8
8
|
"settings.editor.autocomplete.title": "Enable autocomplete",
|
9
9
|
"settings.editor.autocomplete.description": "You’re always able to get suggestions by pressing Ctrl+Space.",
|
10
|
+
"settings.editor.autocomplete-on-enter.title": "Accept suggestion on Enter",
|
11
|
+
"settings.editor.autocomplete-on-enter.description": "Controls whether suggestions should be accepted on Enter, in addition to Tab. Helps to avoid ambiguity between inserting new lines or accepting suggestions.",
|
10
12
|
"settings.theme.title": "Interface theme",
|
11
13
|
"settings.theme.option-dark": "Dark",
|
12
14
|
"settings.theme.option-light": "Light",
|
@@ -1,2 +1,2 @@
|
|
1
|
-
declare const _default: (key: "page.general" | "section.appearance" | "page.experiments" | "section.experiments" | "page.editor" | "section.dev-setting" | "settings.editor.autocomplete.title" | "settings.editor.autocomplete.description" | "settings.theme.title" | "settings.theme.option-dark" | "settings.theme.option-light" | "settings.theme.option-system" | "settings.language.title" | "settings.language.option-russian" | "settings.language.option-english" | "settings.binaryDataInPlainTextDisplay.title" | "settings.binaryDataInPlainTextDisplay.description" | "settings.invertedDisks.title" | "settings.useNodesEndpoint.title" | "settings.useNodesEndpoint.popover" | "settings.useVirtualTables.title" | "settings.useVirtualTables.popover" | "settings.queryUseMultiSchema.title" | "settings.queryUseMultiSchema.popover", params?: import("@gravity-ui/i18n").Params | undefined) => string;
|
1
|
+
declare const _default: (key: "page.general" | "section.appearance" | "page.experiments" | "section.experiments" | "page.editor" | "section.dev-setting" | "settings.editor.autocomplete.title" | "settings.editor.autocomplete.description" | "settings.editor.autocomplete-on-enter.title" | "settings.editor.autocomplete-on-enter.description" | "settings.theme.title" | "settings.theme.option-dark" | "settings.theme.option-light" | "settings.theme.option-system" | "settings.language.title" | "settings.language.option-russian" | "settings.language.option-english" | "settings.binaryDataInPlainTextDisplay.title" | "settings.binaryDataInPlainTextDisplay.description" | "settings.invertedDisks.title" | "settings.useNodesEndpoint.title" | "settings.useNodesEndpoint.popover" | "settings.useVirtualTables.title" | "settings.useVirtualTables.popover" | "settings.queryUseMultiSchema.title" | "settings.queryUseMultiSchema.popover", params?: import("@gravity-ui/i18n").Params | undefined) => string;
|
2
2
|
export default _default;
|
@@ -20,6 +20,7 @@ export declare const useNodesEndpointSetting: SettingProps;
|
|
20
20
|
export declare const useVirtualTables: SettingProps;
|
21
21
|
export declare const queryUseMultiSchemaSetting: SettingProps;
|
22
22
|
export declare const enableAutocompleteSetting: SettingProps;
|
23
|
+
export declare const autocompleteOnEnterSetting: SettingProps;
|
23
24
|
export declare const appearanceSection: SettingsSection;
|
24
25
|
export declare const experimentsSection: SettingsSection;
|
25
26
|
export declare const devSettingsSection: SettingsSection;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
2
2
|
import { Flask, PencilToSquare, StarFill } from '@gravity-ui/icons';
|
3
|
-
import { BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, ENABLE_AUTOCOMPLETE, INVERTED_DISKS_KEY, LANGUAGE_KEY, QUERY_USE_MULTI_SCHEMA_KEY, THEME_KEY, USE_BACKEND_PARAMS_FOR_TABLES_KEY, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, } from '../../utils/constants';
|
3
|
+
import { AUTOCOMPLETE_ON_ENTER, BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, ENABLE_AUTOCOMPLETE, INVERTED_DISKS_KEY, LANGUAGE_KEY, QUERY_USE_MULTI_SCHEMA_KEY, THEME_KEY, USE_BACKEND_PARAMS_FOR_TABLES_KEY, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, } from '../../utils/constants';
|
4
4
|
import { Lang, defaultLang } from '../../utils/i18n';
|
5
5
|
import { ClusterModeGuard } from '../ClusterModeGuard';
|
6
6
|
import i18n from './i18n';
|
@@ -73,6 +73,11 @@ export const enableAutocompleteSetting = {
|
|
73
73
|
title: i18n('settings.editor.autocomplete.title'),
|
74
74
|
description: i18n('settings.editor.autocomplete.description'),
|
75
75
|
};
|
76
|
+
export const autocompleteOnEnterSetting = {
|
77
|
+
settingKey: AUTOCOMPLETE_ON_ENTER,
|
78
|
+
title: i18n('settings.editor.autocomplete-on-enter.title'),
|
79
|
+
description: i18n('settings.editor.autocomplete-on-enter.description'),
|
80
|
+
};
|
76
81
|
export const appearanceSection = {
|
77
82
|
id: 'appearanceSection',
|
78
83
|
title: i18n('section.appearance'),
|
@@ -86,7 +91,7 @@ export const experimentsSection = {
|
|
86
91
|
export const devSettingsSection = {
|
87
92
|
id: 'devSettingsSection',
|
88
93
|
title: i18n('section.dev-setting'),
|
89
|
-
settings: [enableAutocompleteSetting],
|
94
|
+
settings: [enableAutocompleteSetting, autocompleteOnEnterSetting],
|
90
95
|
};
|
91
96
|
export const generalPage = {
|
92
97
|
id: 'generalPage',
|
package/dist/services/api.d.ts
CHANGED
@@ -2,6 +2,7 @@ import AxiosWrapper from '@gravity-ui/axios-wrapper';
|
|
2
2
|
import type { ComputeApiRequestParams, NodesApiRequestParams } from '../store/reducers/nodes/types';
|
3
3
|
import type { StorageApiRequestParams } from '../store/reducers/storage/types';
|
4
4
|
import type { TMetaInfo } from '../types/api/acl';
|
5
|
+
import type { TQueryAutocomplete } from '../types/api/autocomplete';
|
5
6
|
import type { TClusterInfo } from '../types/api/cluster';
|
6
7
|
import type { TComputeInfo } from '../types/api/compute';
|
7
8
|
import type { DescribeConsumerResult } from '../types/api/consumer';
|
@@ -14,6 +15,7 @@ import type { TEvNodesInfo } from '../types/api/nodesList';
|
|
14
15
|
import type { TEvPDiskStateResponse } from '../types/api/pdisk';
|
15
16
|
import type { Actions, ExplainActions, ExplainResponse, QueryAPIResponse, Schemas } from '../types/api/query';
|
16
17
|
import type { JsonRenderRequestParams, JsonRenderResponse } from '../types/api/render';
|
18
|
+
import type { RestartPDiskResponse } from '../types/api/restartPDisk';
|
17
19
|
import type { TEvDescribeSchemeResult } from '../types/api/schema';
|
18
20
|
import type { TStorageInfo } from '../types/api/storage';
|
19
21
|
import type { TEvSystemStateResponse } from '../types/api/systemState';
|
@@ -104,7 +106,7 @@ export declare class YdbEmbeddedAPI extends AxiosWrapper {
|
|
104
106
|
failDomainIdx: string | number;
|
105
107
|
vDiskIdx: string | number;
|
106
108
|
}): Promise<any>;
|
107
|
-
restartPDisk(nodeId: number | string, pDiskId: number | string): Promise<
|
109
|
+
restartPDisk(nodeId: number | string, pDiskId: number | string): Promise<RestartPDiskResponse>;
|
108
110
|
killTablet(id?: string): Promise<string>;
|
109
111
|
stopTablet(id?: string, hiveId?: string): Promise<string>;
|
110
112
|
resumeTablet(id?: string, hiveId?: string): Promise<string>;
|
@@ -115,6 +117,12 @@ export declare class YdbEmbeddedAPI extends AxiosWrapper {
|
|
115
117
|
authenticate(user: string, password: string): Promise<any>;
|
116
118
|
logout(): Promise<any>;
|
117
119
|
whoami(): Promise<TUserToken>;
|
120
|
+
autocomplete(params: {
|
121
|
+
database: string;
|
122
|
+
prefix?: string;
|
123
|
+
limit?: number;
|
124
|
+
table?: string[];
|
125
|
+
}): Promise<TQueryAutocomplete>;
|
118
126
|
getClustersList(_?: never, { signal }?: {
|
119
127
|
signal?: AbortSignal;
|
120
128
|
}): Promise<MetaClusters>;
|
package/dist/services/api.js
CHANGED
@@ -302,6 +302,11 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
302
302
|
whoami() {
|
303
303
|
return this.get(this.getPath('/viewer/json/whoami'), {});
|
304
304
|
}
|
305
|
+
autocomplete(params) {
|
306
|
+
const { table } = params, rest = __rest(params, ["table"]);
|
307
|
+
const tablesParam = table === null || table === void 0 ? void 0 : table.join(',');
|
308
|
+
return this.get(this.getPath('/viewer/json/autocomplete'), Object.assign(Object.assign({}, rest), { table: tablesParam }), { concurrentId: 'sql-autocomplete' });
|
309
|
+
}
|
305
310
|
// used if not single cluster mode
|
306
311
|
getClustersList(_, { signal } = {}) {
|
307
312
|
return this.get(`${META_BACKEND || ''}/meta/clusters`, null, {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { TENANT_PAGES_IDS } from '../store/reducers/tenant/constants';
|
2
|
-
import { ASIDE_HEADER_COMPACT_KEY, BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, ENABLE_AUTOCOMPLETE, INVERTED_DISKS_KEY, LANGUAGE_KEY, LAST_USED_QUERY_ACTION_KEY, PARTITIONS_HIDDEN_COLUMNS_KEY, QUERY_INITIAL_MODE_KEY, QUERY_USE_MULTI_SCHEMA_KEY, SAVED_QUERIES_KEY, TENANT_INITIAL_PAGE_KEY, THEME_KEY, USE_BACKEND_PARAMS_FOR_TABLES_KEY, USE_CLUSTER_BALANCER_AS_BACKEND_KEY, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, } from '../utils/constants';
|
2
|
+
import { ASIDE_HEADER_COMPACT_KEY, AUTOCOMPLETE_ON_ENTER, BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, ENABLE_AUTOCOMPLETE, INVERTED_DISKS_KEY, LANGUAGE_KEY, LAST_USED_QUERY_ACTION_KEY, PARTITIONS_HIDDEN_COLUMNS_KEY, QUERY_INITIAL_MODE_KEY, QUERY_USE_MULTI_SCHEMA_KEY, SAVED_QUERIES_KEY, TENANT_INITIAL_PAGE_KEY, THEME_KEY, USE_BACKEND_PARAMS_FOR_TABLES_KEY, USE_CLUSTER_BALANCER_AS_BACKEND_KEY, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, } from '../utils/constants';
|
3
3
|
import { QUERY_ACTIONS, QUERY_MODES } from '../utils/query';
|
4
4
|
import { parseJson } from '../utils/utils';
|
5
5
|
/** User settings keys and their default values */
|
@@ -19,6 +19,7 @@ export const DEFAULT_USER_SETTINGS = {
|
|
19
19
|
[USE_BACKEND_PARAMS_FOR_TABLES_KEY]: false,
|
20
20
|
[USE_CLUSTER_BALANCER_AS_BACKEND_KEY]: true,
|
21
21
|
[ENABLE_AUTOCOMPLETE]: false,
|
22
|
+
[AUTOCOMPLETE_ON_ENTER]: true,
|
22
23
|
};
|
23
24
|
class SettingsManager {
|
24
25
|
constructor() {
|
@@ -0,0 +1,21 @@
|
|
1
|
+
/**
|
2
|
+
* endpoint: /viewer/json/autocomplete
|
3
|
+
*
|
4
|
+
* source: https://github.com/ydb-platform/ydb/blob/main/ydb/core/viewer/protos/viewer.proto
|
5
|
+
*/
|
6
|
+
export interface TQueryAutocomplete {
|
7
|
+
Success: boolean;
|
8
|
+
Error?: string[];
|
9
|
+
Result: TAutocompleteResult;
|
10
|
+
}
|
11
|
+
interface TAutocompleteResult {
|
12
|
+
Entities: TAutocompleteEntity[];
|
13
|
+
Total?: number;
|
14
|
+
}
|
15
|
+
export interface TAutocompleteEntity {
|
16
|
+
Name: string;
|
17
|
+
Type: AutocompleteEntityType;
|
18
|
+
Parent: string;
|
19
|
+
}
|
20
|
+
export type AutocompleteEntityType = 'unknown' | 'dir' | 'table' | 'pers_queue_group' | 'sub_domain' | 'rtmr_volume' | 'block_store_volume' | 'kesus' | 'solomon_volume' | 'table_index' | 'ext_sub_domain' | 'file_store' | 'column_store' | 'column_table' | 'cdc_stream' | 'sequence' | 'replication' | 'blob_depot' | 'external_table' | 'external_data_source' | 'view' | 'column' | 'index';
|
21
|
+
export {};
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -88,3 +88,4 @@ export declare const USE_BACKEND_PARAMS_FOR_TABLES_KEY = "useBackendParamsForTab
|
|
88
88
|
export declare const QUERY_USE_MULTI_SCHEMA_KEY = "queryUseMultiSchema";
|
89
89
|
export declare const USE_CLUSTER_BALANCER_AS_BACKEND_KEY = "useClusterBalancerAsBacked";
|
90
90
|
export declare const ENABLE_AUTOCOMPLETE = "enableAutocomplete";
|
91
|
+
export declare const AUTOCOMPLETE_ON_ENTER = "autocompleteOnEnter";
|
package/dist/utils/constants.js
CHANGED
@@ -101,3 +101,4 @@ export const USE_BACKEND_PARAMS_FOR_TABLES_KEY = 'useBackendParamsForTables';
|
|
101
101
|
export const QUERY_USE_MULTI_SCHEMA_KEY = 'queryUseMultiSchema';
|
102
102
|
export const USE_CLUSTER_BALANCER_AS_BACKEND_KEY = 'useClusterBalancerAsBacked';
|
103
103
|
export const ENABLE_AUTOCOMPLETE = 'enableAutocomplete';
|
104
|
+
export const AUTOCOMPLETE_ON_ENTER = 'autocompleteOnEnter';
|
@@ -1,5 +1,5 @@
|
|
1
|
-
import type { ColumnAliasSuggestion, KeywordSuggestion, YqlAutocompleteResult } from '@gravity-ui/websql-autocomplete';
|
2
|
-
import
|
1
|
+
import type { ColumnAliasSuggestion, KeywordSuggestion, YQLEntity, YqlAutocompleteResult } from '@gravity-ui/websql-autocomplete';
|
2
|
+
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
|
3
3
|
export declare function generateColumnsSuggestion(rangeToInsertSuggestion: monaco.IRange, suggestColumns: YqlAutocompleteResult['suggestColumns'] | undefined, database: string): Promise<monaco.languages.CompletionItem[]>;
|
4
4
|
export declare function generateColumnAliasesSuggestion(rangeToInsertSuggestion: monaco.IRange, suggestColumnAliases?: ColumnAliasSuggestion[]): {
|
5
5
|
label: string;
|
@@ -17,7 +17,7 @@ export declare function generateKeywordsSuggestion(rangeToInsertSuggestion: mona
|
|
17
17
|
range: monaco.IRange;
|
18
18
|
sortText: string;
|
19
19
|
}[];
|
20
|
-
export declare function generateEntitiesSuggestion(
|
20
|
+
export declare function generateEntitiesSuggestion(rangeToInsertSuggestion: monaco.IRange, suggestEntities: YQLEntity[], database: string, prefix?: string): Promise<monaco.languages.CompletionItem[]>;
|
21
21
|
export declare function generateSimpleFunctionsSuggestion(rangeToInsertSuggestion: monaco.IRange): Promise<monaco.languages.CompletionItem[]>;
|
22
22
|
export declare function generateSimpleTypesSuggestion(rangeToInsertSuggestion: monaco.IRange): Promise<monaco.languages.CompletionItem[]>;
|
23
23
|
export declare function generateUdfSuggestion(rangeToInsertSuggestion: monaco.IRange): Promise<monaco.languages.CompletionItem[]>;
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
|
1
2
|
import { AggregateFunctions, Pragmas, SimpleFunctions, SimpleTypes, TableFunction, Udfs, WindowFunctions, } from './constants';
|
2
3
|
const CompletionItemKind = {
|
3
4
|
Method: 0,
|
@@ -30,6 +31,27 @@ const CompletionItemKind = {
|
|
30
31
|
Snippet: 27,
|
31
32
|
};
|
32
33
|
const re = /[\s'"-/@]/;
|
34
|
+
const suggestionEntityToAutocomplete = {
|
35
|
+
externalDataSource: ['external_data_source'],
|
36
|
+
replication: ['replication'],
|
37
|
+
table: ['table'],
|
38
|
+
tableStore: ['column_store'],
|
39
|
+
topic: ['pers_queue_group'],
|
40
|
+
view: ['view'],
|
41
|
+
//TODO: add after websql-autocomplete support indexex
|
42
|
+
// index: ['table_index', 'index'],
|
43
|
+
};
|
44
|
+
const commonSuggestionEntities = ['dir', 'unknown'];
|
45
|
+
function filterAutocompleteEntities(autocompleteEntities, suggestions) {
|
46
|
+
const suggestionsSet = suggestions.reduce((acc, el) => {
|
47
|
+
const autocompleteEntity = suggestionEntityToAutocomplete[el];
|
48
|
+
if (autocompleteEntity) {
|
49
|
+
autocompleteEntity.forEach((el) => acc.add(el));
|
50
|
+
}
|
51
|
+
return acc;
|
52
|
+
}, new Set(commonSuggestionEntities));
|
53
|
+
return autocompleteEntities.filter(({ Type }) => suggestionsSet.has(Type));
|
54
|
+
}
|
33
55
|
function wrapStringToBackticks(value) {
|
34
56
|
let result = value;
|
35
57
|
if (value.match(re)) {
|
@@ -38,11 +60,29 @@ function wrapStringToBackticks(value) {
|
|
38
60
|
return result;
|
39
61
|
}
|
40
62
|
function removeBackticks(value) {
|
41
|
-
let
|
63
|
+
let sliceStart = 0;
|
64
|
+
let sliceEnd = value.length;
|
42
65
|
if (value.startsWith('`')) {
|
43
|
-
|
66
|
+
sliceStart = 1;
|
67
|
+
}
|
68
|
+
if (value.endsWith('`')) {
|
69
|
+
sliceEnd = -1;
|
70
|
+
}
|
71
|
+
return value.slice(sliceStart, sliceEnd);
|
72
|
+
}
|
73
|
+
function removeStartSlash(value) {
|
74
|
+
if (value.startsWith('/')) {
|
75
|
+
return value.slice(1);
|
76
|
+
}
|
77
|
+
return value;
|
78
|
+
}
|
79
|
+
function normalizeEntityPrefix(value = '', database) {
|
80
|
+
let cleanedValue = removeStartSlash(removeBackticks(value));
|
81
|
+
const cleanedDatabase = removeStartSlash(database);
|
82
|
+
if (cleanedValue.startsWith(cleanedDatabase)) {
|
83
|
+
cleanedValue = cleanedValue.slice(cleanedDatabase.length);
|
44
84
|
}
|
45
|
-
return
|
85
|
+
return removeStartSlash(cleanedValue);
|
46
86
|
}
|
47
87
|
const SuggestionsWeight = {
|
48
88
|
suggestTemplates: 0,
|
@@ -58,50 +98,6 @@ const SuggestionsWeight = {
|
|
58
98
|
suggestUdfs: 10,
|
59
99
|
suggestSimpleTypes: 11,
|
60
100
|
};
|
61
|
-
const KEEP_CACHE_MILLIS = 5 * 60 * 1000;
|
62
|
-
function getColumnsWithCache() {
|
63
|
-
const cache = new Map();
|
64
|
-
return async (path) => {
|
65
|
-
var _a, _b, _c, _d;
|
66
|
-
const normalizedPath = removeBackticks(path);
|
67
|
-
const existed = cache.get(path);
|
68
|
-
if (existed) {
|
69
|
-
return existed;
|
70
|
-
}
|
71
|
-
const columns = [];
|
72
|
-
const data = await window.api.getDescribe({ path: normalizedPath });
|
73
|
-
if ((data === null || data === void 0 ? void 0 : data.Status) === 'StatusSuccess') {
|
74
|
-
const desc = data.PathDescription;
|
75
|
-
if ((_a = desc === null || desc === void 0 ? void 0 : desc.Table) === null || _a === void 0 ? void 0 : _a.Columns) {
|
76
|
-
for (const c of desc.Table.Columns) {
|
77
|
-
if (c.Name) {
|
78
|
-
columns.push(c.Name);
|
79
|
-
}
|
80
|
-
}
|
81
|
-
}
|
82
|
-
if ((_c = (_b = desc === null || desc === void 0 ? void 0 : desc.ColumnTableDescription) === null || _b === void 0 ? void 0 : _b.Schema) === null || _c === void 0 ? void 0 : _c.Columns) {
|
83
|
-
for (const c of desc.ColumnTableDescription.Schema.Columns) {
|
84
|
-
if (c.Name) {
|
85
|
-
columns.push(c.Name);
|
86
|
-
}
|
87
|
-
}
|
88
|
-
}
|
89
|
-
if ((_d = desc === null || desc === void 0 ? void 0 : desc.ExternalTableDescription) === null || _d === void 0 ? void 0 : _d.Columns) {
|
90
|
-
for (const c of desc.ExternalTableDescription.Columns) {
|
91
|
-
if (c.Name) {
|
92
|
-
columns.push(c.Name);
|
93
|
-
}
|
94
|
-
}
|
95
|
-
}
|
96
|
-
}
|
97
|
-
cache.set(path, columns);
|
98
|
-
setTimeout(() => {
|
99
|
-
cache.delete(path);
|
100
|
-
}, KEEP_CACHE_MILLIS);
|
101
|
-
return columns;
|
102
|
-
};
|
103
|
-
}
|
104
|
-
const getColumns = getColumnsWithCache();
|
105
101
|
function getSuggestionIndex(suggestionType) {
|
106
102
|
return SuggestionsWeight[suggestionType];
|
107
103
|
}
|
@@ -127,28 +123,63 @@ async function getSimpleTypes() {
|
|
127
123
|
return SimpleTypes;
|
128
124
|
}
|
129
125
|
export async function generateColumnsSuggestion(rangeToInsertSuggestion, suggestColumns, database) {
|
130
|
-
var _a;
|
126
|
+
var _a, _b, _c;
|
131
127
|
if (!(suggestColumns === null || suggestColumns === void 0 ? void 0 : suggestColumns.tables)) {
|
132
128
|
return [];
|
133
129
|
}
|
134
130
|
const suggestions = [];
|
135
131
|
const multi = suggestColumns.tables.length > 1;
|
136
|
-
|
132
|
+
const normalizedTableNames = (_b = (_a = suggestColumns.tables) === null || _a === void 0 ? void 0 : _a.map((entity) => {
|
137
133
|
let normalizedEntityName = removeBackticks(entity.name);
|
138
|
-
|
139
|
-
|
140
|
-
normalizedEntityName = `${database}/${normalizedEntityName}`;
|
134
|
+
if (!normalizedEntityName.endsWith('/')) {
|
135
|
+
normalizedEntityName = `${normalizedEntityName}/`;
|
141
136
|
}
|
142
|
-
|
143
|
-
|
144
|
-
|
137
|
+
return normalizeEntityPrefix(normalizedEntityName, database);
|
138
|
+
})) !== null && _b !== void 0 ? _b : [];
|
139
|
+
// remove duplicates if any
|
140
|
+
const filteredTableNames = Array.from(new Set(normalizedTableNames));
|
141
|
+
const autocompleteResponse = await window.api.autocomplete({
|
142
|
+
database,
|
143
|
+
table: filteredTableNames,
|
144
|
+
limit: 1000,
|
145
|
+
});
|
146
|
+
if (!autocompleteResponse.Success) {
|
147
|
+
return [];
|
148
|
+
}
|
149
|
+
const tableNameToAliasMap = (_c = suggestColumns.tables) === null || _c === void 0 ? void 0 : _c.reduce((acc, entity) => {
|
150
|
+
var _a;
|
151
|
+
const normalizedEntityName = normalizeEntityPrefix(removeBackticks(entity.name), database);
|
152
|
+
const aliases = (_a = acc[normalizedEntityName]) !== null && _a !== void 0 ? _a : [];
|
153
|
+
if (entity.alias) {
|
154
|
+
aliases.push(entity.alias);
|
155
|
+
}
|
156
|
+
acc[normalizedEntityName] = aliases;
|
157
|
+
return acc;
|
158
|
+
}, {});
|
159
|
+
autocompleteResponse.Result.Entities.forEach((col) => {
|
160
|
+
if (col.Type !== 'column') {
|
161
|
+
return;
|
162
|
+
}
|
163
|
+
const normalizedName = wrapStringToBackticks(col.Name);
|
164
|
+
const normalizedParentName = normalizeEntityPrefix(col.Parent, database);
|
165
|
+
const aliases = tableNameToAliasMap[normalizedParentName];
|
166
|
+
if (aliases === null || aliases === void 0 ? void 0 : aliases.length) {
|
167
|
+
aliases.forEach((a) => {
|
168
|
+
const columnNameSuggestion = `${a}.${normalizedName}`;
|
169
|
+
suggestions.push({
|
170
|
+
label: columnNameSuggestion,
|
171
|
+
insertText: columnNameSuggestion,
|
172
|
+
kind: CompletionItemKind.Field,
|
173
|
+
detail: 'Column',
|
174
|
+
range: rangeToInsertSuggestion,
|
175
|
+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestColumns')),
|
176
|
+
});
|
177
|
+
});
|
178
|
+
}
|
179
|
+
else {
|
145
180
|
let columnNameSuggestion = normalizedName;
|
146
|
-
if (
|
147
|
-
columnNameSuggestion = `${
|
148
|
-
}
|
149
|
-
else if (multi) {
|
150
|
-
// no need to wrap entity.name to backticks, because it's already with them if needed
|
151
|
-
columnNameSuggestion = `${entity.name}.${normalizedName}`;
|
181
|
+
if (multi) {
|
182
|
+
columnNameSuggestion = `${wrapStringToBackticks(normalizedParentName)}.${normalizedName}`;
|
152
183
|
}
|
153
184
|
suggestions.push({
|
154
185
|
label: columnNameSuggestion,
|
@@ -158,8 +189,8 @@ export async function generateColumnsSuggestion(rangeToInsertSuggestion, suggest
|
|
158
189
|
range: rangeToInsertSuggestion,
|
159
190
|
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestColumns')),
|
160
191
|
});
|
161
|
-
}
|
162
|
-
}
|
192
|
+
}
|
193
|
+
});
|
163
194
|
return suggestions;
|
164
195
|
}
|
165
196
|
export function generateColumnAliasesSuggestion(rangeToInsertSuggestion, suggestColumnAliases) {
|
@@ -188,7 +219,36 @@ export function generateKeywordsSuggestion(rangeToInsertSuggestion, suggestKeywo
|
|
188
219
|
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestKeywords')),
|
189
220
|
}));
|
190
221
|
}
|
191
|
-
export async function generateEntitiesSuggestion(
|
222
|
+
export async function generateEntitiesSuggestion(rangeToInsertSuggestion, suggestEntities, database, prefix) {
|
223
|
+
const normalizedPrefix = normalizeEntityPrefix(prefix, database);
|
224
|
+
const data = await window.api.autocomplete({ database, prefix: normalizedPrefix, limit: 1000 });
|
225
|
+
const withBackticks = prefix === null || prefix === void 0 ? void 0 : prefix.startsWith('`');
|
226
|
+
if (data.Success) {
|
227
|
+
const filteredEntities = filterAutocompleteEntities(data.Result.Entities, suggestEntities);
|
228
|
+
return filteredEntities.reduce((acc, { Name, Type }) => {
|
229
|
+
const isDir = Type === 'dir';
|
230
|
+
const label = isDir ? `${Name}/` : Name;
|
231
|
+
let labelAsSnippet;
|
232
|
+
if (isDir && !withBackticks) {
|
233
|
+
labelAsSnippet = `\`${label}$0\``;
|
234
|
+
}
|
235
|
+
acc.push({
|
236
|
+
label,
|
237
|
+
insertText: labelAsSnippet !== null && labelAsSnippet !== void 0 ? labelAsSnippet : label,
|
238
|
+
kind: isDir ? CompletionItemKind.Folder : CompletionItemKind.Text,
|
239
|
+
insertTextRules: labelAsSnippet
|
240
|
+
? monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
|
241
|
+
: monaco.languages.CompletionItemInsertTextRule.None,
|
242
|
+
detail: Type,
|
243
|
+
range: rangeToInsertSuggestion,
|
244
|
+
command: label.endsWith('/')
|
245
|
+
? { id: 'editor.action.triggerSuggest', title: '' }
|
246
|
+
: undefined,
|
247
|
+
sortText: suggestionIndexToWeight(getSuggestionIndex('suggestEntity')),
|
248
|
+
});
|
249
|
+
return acc;
|
250
|
+
}, []);
|
251
|
+
}
|
192
252
|
return [];
|
193
253
|
}
|
194
254
|
export async function generateSimpleFunctionsSuggestion(rangeToInsertSuggestion) {
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare function registerYqlLanguage(): void;
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import * as monaco from 'monaco-editor';
|
2
|
+
import { LANGUAGE_YQL_ID } from './constants';
|
3
|
+
import { conf, getLanguage } from './yql';
|
4
|
+
export function registerYqlLanguage() {
|
5
|
+
monaco.languages.register({ id: LANGUAGE_YQL_ID });
|
6
|
+
monaco.languages.setMonarchTokensProvider(LANGUAGE_YQL_ID, getLanguage());
|
7
|
+
monaco.languages.setLanguageConfiguration(LANGUAGE_YQL_ID, conf);
|
8
|
+
}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import * as monaco from 'monaco-editor';
|
2
|
+
import { LANGUAGE_YQL_ID } from './constants';
|
2
3
|
import { createProvideSuggestionsFunction } from './yqlSuggestions';
|
3
4
|
let completionProvider;
|
4
5
|
function disableCodeSuggestions() {
|
@@ -8,8 +9,8 @@ function disableCodeSuggestions() {
|
|
8
9
|
}
|
9
10
|
export function registerYQLCompletionItemProvider(database) {
|
10
11
|
disableCodeSuggestions();
|
11
|
-
completionProvider = monaco.languages.registerCompletionItemProvider(
|
12
|
-
triggerCharacters: [' ', '
|
12
|
+
completionProvider = monaco.languages.registerCompletionItemProvider(LANGUAGE_YQL_ID, {
|
13
|
+
triggerCharacters: [' ', '', ',', '.', '`', '(', '/'],
|
13
14
|
provideCompletionItems: createProvideSuggestionsFunction(database),
|
14
15
|
});
|
15
16
|
}
|
@@ -0,0 +1,7 @@
|
|
1
|
+
import type * as monaco from 'monaco-editor';
|
2
|
+
export declare const conf: monaco.languages.LanguageConfiguration;
|
3
|
+
interface LanguageOptions {
|
4
|
+
ansi?: boolean;
|
5
|
+
}
|
6
|
+
export declare function getLanguage({ ansi, }?: LanguageOptions): monaco.languages.IMonarchLanguage & Record<string, unknown>;
|
7
|
+
export {};
|
@@ -0,0 +1,180 @@
|
|
1
|
+
import { builtinFunctions, keywords, typeKeywords } from './yql.keywords';
|
2
|
+
export const conf = {
|
3
|
+
comments: {
|
4
|
+
lineComment: '--',
|
5
|
+
blockComment: ['/*', '*/'],
|
6
|
+
},
|
7
|
+
brackets: [
|
8
|
+
['{', '}'],
|
9
|
+
['[', ']'],
|
10
|
+
['(', ')'],
|
11
|
+
],
|
12
|
+
autoClosingPairs: [
|
13
|
+
{ open: '{', close: '}' },
|
14
|
+
{ open: '[', close: ']' },
|
15
|
+
{ open: '(', close: ')' },
|
16
|
+
{ open: '"', close: '"' },
|
17
|
+
{ open: "'", close: "'" },
|
18
|
+
{ open: '`', close: '`' },
|
19
|
+
],
|
20
|
+
surroundingPairs: [
|
21
|
+
{ open: '{', close: '}' },
|
22
|
+
{ open: '[', close: ']' },
|
23
|
+
{ open: '(', close: ')' },
|
24
|
+
{ open: '"', close: '"' },
|
25
|
+
{ open: "'", close: "'" },
|
26
|
+
{ open: '`', close: '`' },
|
27
|
+
],
|
28
|
+
wordPattern: /(-?\d*\.\d\w*)|([^`~!@#%^&*()\-=+[{\]}\\|;:'",./?\s]+)/g,
|
29
|
+
};
|
30
|
+
export function getLanguage({ ansi = false, } = {}) {
|
31
|
+
return {
|
32
|
+
defaultToken: 'text',
|
33
|
+
ignoreCase: true,
|
34
|
+
brackets: [
|
35
|
+
{ open: '[', close: ']', token: 'delimiter.square' },
|
36
|
+
{ open: '(', close: ')', token: 'delimiter.parenthesis' },
|
37
|
+
{ open: '{', close: '}', token: 'delimiter.curly' },
|
38
|
+
],
|
39
|
+
keywords,
|
40
|
+
typeKeywords,
|
41
|
+
constants: ['true', 'false'],
|
42
|
+
builtinFunctions,
|
43
|
+
operators: [
|
44
|
+
'+',
|
45
|
+
'-',
|
46
|
+
'/',
|
47
|
+
'//',
|
48
|
+
'%',
|
49
|
+
'<@>',
|
50
|
+
'@>',
|
51
|
+
'<@',
|
52
|
+
'&',
|
53
|
+
'^',
|
54
|
+
'~',
|
55
|
+
'<',
|
56
|
+
'>',
|
57
|
+
'<=',
|
58
|
+
'>=',
|
59
|
+
'=>',
|
60
|
+
'==',
|
61
|
+
'!=',
|
62
|
+
'<>',
|
63
|
+
'=',
|
64
|
+
],
|
65
|
+
symbols: /[=><!~?:&|+\-*/^%]+/,
|
66
|
+
escapes: /\\(?:[abfnrtv\\"'`]|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
|
67
|
+
variables: /[a-zA-Z_]\w*/,
|
68
|
+
tokenizer: {
|
69
|
+
root: [
|
70
|
+
{ include: '@whitespace' },
|
71
|
+
{ include: '@comments' },
|
72
|
+
{ include: '@numbers' },
|
73
|
+
{ include: '@tablePath' },
|
74
|
+
{ include: '@strings' },
|
75
|
+
// support function
|
76
|
+
[/(@variables)::(@variables)/, 'support.function'],
|
77
|
+
[/[;,.]/, 'delimiter'],
|
78
|
+
[/[(){}[\]]/, '@brackets'],
|
79
|
+
// identifiers and keywords
|
80
|
+
[
|
81
|
+
/@?[a-zA-Z_$]\w*/,
|
82
|
+
{
|
83
|
+
cases: {
|
84
|
+
'@keywords': 'keyword',
|
85
|
+
'@typeKeywords': 'keyword.type',
|
86
|
+
'@constants': 'constant.yql',
|
87
|
+
'@builtinFunctions': 'constant.other.color',
|
88
|
+
'[$@][a-zA-Z_]\\w*': 'variable',
|
89
|
+
'@default': 'identifier',
|
90
|
+
},
|
91
|
+
},
|
92
|
+
],
|
93
|
+
[
|
94
|
+
/@symbols/,
|
95
|
+
{
|
96
|
+
cases: {
|
97
|
+
'@operators': 'operator.sql',
|
98
|
+
'@default': '',
|
99
|
+
},
|
100
|
+
},
|
101
|
+
],
|
102
|
+
],
|
103
|
+
whitespace: [[/\s+/, 'white']],
|
104
|
+
comments: [
|
105
|
+
[/--.*/, 'comment'],
|
106
|
+
[/\/\*/, { token: 'comment.quote', next: ansi ? '@commentAnsi' : '@comment' }],
|
107
|
+
],
|
108
|
+
comment: [
|
109
|
+
[/[^*/]+/, 'comment'],
|
110
|
+
[/\*\//, { token: 'comment.quote', next: '@pop' }],
|
111
|
+
[/./, 'comment'],
|
112
|
+
],
|
113
|
+
commentAnsi: [
|
114
|
+
[/\/\*/, { token: 'comment.quote', next: '@comment' }],
|
115
|
+
[/[^*/]+/, 'comment'],
|
116
|
+
[/\*\//, { token: 'comment.quote', next: '@pop' }],
|
117
|
+
[/./, 'comment'],
|
118
|
+
],
|
119
|
+
numbers: [
|
120
|
+
[/[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?f?\b/, 'number.float'],
|
121
|
+
[/[+-]?(?:\d+|0b[01]+|0o[0-8]+|0x[\da-f]+)(?:u?[lst]?)?\b/, 'number'],
|
122
|
+
],
|
123
|
+
strings: [
|
124
|
+
[/'/, { token: 'string', next: ansi ? '@stringAnsiSingle' : '@stringSingle' }],
|
125
|
+
[/"/, { token: 'string', next: ansi ? '@stringAnsiDouble' : '@stringDouble' }],
|
126
|
+
[/[@]{2}/, { token: 'string', next: '@multilineString' }],
|
127
|
+
],
|
128
|
+
stringSingle: [
|
129
|
+
[/[^\\']+/, 'string'],
|
130
|
+
[/@escapes/, 'string.escape'],
|
131
|
+
[/\\./, 'string.escape.invalid'],
|
132
|
+
[/'[uyj]?/, { token: 'string', next: '@pop' }],
|
133
|
+
],
|
134
|
+
stringAnsiSingle: [
|
135
|
+
[/[^']+/, 'string'],
|
136
|
+
[/''/, 'string'],
|
137
|
+
[/'[uyj]?/, { token: 'string', next: '@pop' }],
|
138
|
+
],
|
139
|
+
stringDouble: [
|
140
|
+
[/[^\\"]+/, 'string'],
|
141
|
+
[/@escapes/, 'string.escape'],
|
142
|
+
[/\\./, 'string.escape.invalid'],
|
143
|
+
[/"[uyj]?/, { token: 'string', next: '@pop' }],
|
144
|
+
],
|
145
|
+
stringAnsiDouble: [
|
146
|
+
[/[^"]+/, 'string'],
|
147
|
+
[/""/, 'string'],
|
148
|
+
[/"[uyj]?/, { token: 'string', next: '@pop' }],
|
149
|
+
],
|
150
|
+
multilineString: [
|
151
|
+
[
|
152
|
+
/#py/,
|
153
|
+
{ token: 'string.python', nextEmbedded: 'python', next: '@embedded', goBack: 3 },
|
154
|
+
],
|
155
|
+
[
|
156
|
+
/\/\/js/,
|
157
|
+
{ token: 'string.js', nextEmbedded: 'javascript', next: '@embedded', goBack: 4 },
|
158
|
+
],
|
159
|
+
[/[^@]+/, 'string'],
|
160
|
+
[/[@]{4}/, 'string'],
|
161
|
+
[/[@]{2}[uyj]?/, { token: 'string', next: '@pop' }],
|
162
|
+
[/./, 'string'],
|
163
|
+
],
|
164
|
+
embedded: [
|
165
|
+
[
|
166
|
+
/([^@]|^)([@]{4})*[@]{2}([@]([^@]|$)|[^@]|$)/,
|
167
|
+
{ token: '@rematch', next: '@pop', nextEmbedded: '@pop' },
|
168
|
+
],
|
169
|
+
],
|
170
|
+
tablePath: [[/((`)?[\w/]+\2\s*\.\s*)?`/, { token: 'string.tablepath', next: '@table' }]],
|
171
|
+
table: [
|
172
|
+
[/[^\\`]+/, 'string.tablepath'],
|
173
|
+
[/``/, 'string.tablepath'],
|
174
|
+
[/@escapes/, 'string.escape.tablepath'],
|
175
|
+
[/\\./, 'string.escape.invalid.tablepath'],
|
176
|
+
[/`/, { token: 'string.tablepath', next: '@pop' }],
|
177
|
+
],
|
178
|
+
},
|
179
|
+
};
|
180
|
+
}
|
@@ -0,0 +1,3 @@
|
|
1
|
+
export const keywords = '$row|$rows|action|all|and|any|as|asc|assume|begin|bernoulli|between|by|case|columns|commit|compact|create|cross|cube|declare|define|delete|desc|dict|discard|distinct|do|drop|else|empty_action|end|erase|evaluate|exclusion|exists|export|flatten|for|from|full|group|grouping|having|if|ignore|ilike|import|in|inner|insert|into|is|join|left|like|limit|list|match|not|null|nulls|offset|on|only|optional|or|order|over|partition|pragma|presort|process|reduce|regexp|repeatable|replace|respect|result|return|right|rlike|rollup|sample|schema|select|semi|set|sets|stream|subquery|table|tablesample|then|truncate|union|update|upsert|use|using|values|view|when|where|window|with|without|xor'.split('|');
|
2
|
+
export const typeKeywords = 'bool|date|datetime|decimal|double|float|int16|int32|int64|int8|interval|json|string|timestamp|tzdate|tzdatetime|tztimestamp|uint16|uint32|uint64|uint8|utf8|uuid|yson'.split('|');
|
3
|
+
export const builtinFunctions = 'abs|aggregate_by|aggregate_list|aggregate_list_distinct|agg_list|agg_list_distinct|as_table|avg|avg_if|adaptivedistancehistogram|adaptivewardhistogram|adaptiveweighthistogram|addmember|addtimezone|aggregateflatten|aggregatetransforminput|aggregatetransformoutput|aggregationfactory|asatom|asdict|asdictstrict|asenum|aslist|asliststrict|asset|assetstrict|asstruct|astagged|astuple|asvariant|atomcode|bitcast|bit_and|bit_or|bit_xor|bool_and|bool_or|bool_xor|bottom|bottom_by|blockwardhistogram|blockweighthistogram|cast|coalesce|concat|concat_strict|correlation|count|count_if|covariance|covariance_population|covariance_sample|callableargument|callableargumenttype|callableresulttype|callabletype|callabletypecomponents|callabletypehandle|choosemembers|combinemembers|countdistinctestimate|currentauthenticateduser|currentoperationid|currentoperationsharedid|currenttzdate|currenttzdatetime|currenttztimestamp|currentutcdate|currentutcdatetime|currentutctimestamp|dense_rank|datatype|datatypecomponents|datatypehandle|dictaggregate|dictcontains|dictcreate|dicthasitems|dictitems|dictkeytype|dictkeys|dictlength|dictlookup|dictpayloadtype|dictpayloads|dicttype|dicttypecomponents|dicttypehandle|each|each_strict|emptydicttype|emptydicttypehandle|emptylisttype|emptylisttypehandle|endswith|ensure|ensureconvertibleto|ensuretype|enum|evaluateatom|evaluatecode|evaluateexpr|evaluatetype|expandstruct|filter|filter_strict|find|first_value|folder|filecontent|filepath|flattenmembers|forceremovemember|forceremovemembers|forcerenamemembers|forcespreadmembers|formatcode|formattype|frombytes|funccode|greatest|grouping|gathermembers|generictype|histogram|hll|hyperloglog|if|if_strict|instanceof|json_exists|json_query|json_value|jointablerow|just|lag|last_value|lead|least|len|length|like|likely|like_strict|lambdaargumentscount|lambdacode|linearhistogram|listaggregate|listall|listany|listavg|listcode|listcollect|listconcat|listcreate|listdistinct|listenumerate|listextend|listextendstrict|listextract|listfilter|listflatmap|listflatten|listfromrange|listhas|listhasitems|listhead|listindexof|listitemtype|listlast|listlength|listmap|listmax|listmin|listnotnull|listreplicate|listreverse|listskip|listskipwhile|listskipwhileinclusive|listsort|listsortasc|listsortdesc|listsum|listtake|listtakewhile|listtakewhileinclusive|listtype|listtypehandle|listunionall|listuniq|listzip|listzipall|loghistogram|logarithmichistogram|max|max_by|max_of|median|min|min_by|min_of|mode|multi_aggregate_by|nanvl|nvl|nothing|nulltype|nulltypehandle|optionalitemtype|optionaltype|optionaltypehandle|percentile|parsefile|parsetype|parsetypehandle|pickle|quotecode|range|range_strict|rank|regexp|regexp_strict|rfind|row_number|random|randomnumber|randomuuid|removemember|removemembers|removetimezone|renamemembers|replacemember|reprcode|resourcetype|resourcetypehandle|resourcetypetag|some|stddev|stddev_population|stddev_sample|substring|sum|sum_if|sessionstart|sessionwindow|setcreate|setdifference|setincludes|setintersection|setisdisjoint|setsymmetricdifference|setunion|spreadmembers|stablepickle|startswith|staticmap|streamitemtype|streamtype|streamtypehandle|structmembertype|structmembers|structtypecomponents|structtypehandle|subqueryextend|subqueryextendfor|subquerymerge|subquerymergefor|subqueryunionall|subqueryunionallfor|subqueryunionmerge|subqueryunionmergefor|top|topfreq|top_by|tablename|tablepath|tablerecordindex|tablerow|taggedtype|taggedtypecomponents|taggedtypehandle|tobytes|todict|tomultidict|toset|tosorteddict|tosortedmultidict|trymember|tupleelementtype|tupletype|tupletypecomponents|tupletypehandle|typehandle|typekind|typeof|udaf|unittype|unpickle|untag|unwrap|variance|variance_population|variance_sample|variant|varianttype|varianttypehandle|variantunderlyingtype|voidtype|voidtypehandle|way|worldcode'.split('|');
|
@@ -1,18 +1,24 @@
|
|
1
1
|
import { generateAggregateFunctionsSuggestion, generateColumnAliasesSuggestion, generateColumnsSuggestion, generateEntitiesSuggestion, generateKeywordsSuggestion, generatePragmasSuggestion, generateSimpleFunctionsSuggestion, generateSimpleTypesSuggestion, generateTableFunctionsSuggestion, generateUdfSuggestion, generateWindowFunctionsSuggestion, } from './generateSuggestions';
|
2
2
|
export function createProvideSuggestionsFunction(database) {
|
3
3
|
return async (model, monacoCursorPosition, _context, _token) => {
|
4
|
-
const cursorPosition = {
|
5
|
-
line: monacoCursorPosition.lineNumber,
|
6
|
-
column: monacoCursorPosition.column,
|
7
|
-
};
|
8
4
|
const rangeToInsertSuggestion = getRangeToInsertSuggestion(model, monacoCursorPosition);
|
9
|
-
const suggestions = await getSuggestions(model,
|
5
|
+
const suggestions = await getSuggestions(model, monacoCursorPosition, rangeToInsertSuggestion, database);
|
10
6
|
return { suggestions };
|
11
7
|
};
|
12
8
|
}
|
9
|
+
function getEntityNameAtCursor(model, cursorPosition) {
|
10
|
+
var _a, _b, _c, _d;
|
11
|
+
const prevWord = model.findPreviousMatch('\\s(`?[^\\s]*)', cursorPosition, true, false, null, true);
|
12
|
+
const nextWord = model.findNextMatch('([^\\s]*)`?', cursorPosition, true, false, null, true);
|
13
|
+
return `${(_b = (_a = prevWord === null || prevWord === void 0 ? void 0 : prevWord.matches) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : ''}${(_d = (_c = nextWord === null || nextWord === void 0 ? void 0 : nextWord.matches) === null || _c === void 0 ? void 0 : _c[1]) !== null && _d !== void 0 ? _d : ''}`;
|
14
|
+
}
|
13
15
|
async function getSuggestions(model, cursorPosition, rangeToInsertSuggestion, database) {
|
14
16
|
const { parseYqlQuery } = await import('@gravity-ui/websql-autocomplete');
|
15
|
-
const
|
17
|
+
const cursorForParsing = {
|
18
|
+
line: cursorPosition.lineNumber,
|
19
|
+
column: cursorPosition.column,
|
20
|
+
};
|
21
|
+
const parseResult = parseYqlQuery(model.getValue(), cursorForParsing);
|
16
22
|
let entitiesSuggestions = [];
|
17
23
|
let functionsSuggestions = [];
|
18
24
|
let aggregateFunctionsSuggestions = [];
|
@@ -22,7 +28,8 @@ async function getSuggestions(model, cursorPosition, rangeToInsertSuggestion, da
|
|
22
28
|
let simpleTypesSuggestions = [];
|
23
29
|
let pragmasSuggestions = [];
|
24
30
|
if (parseResult.suggestEntity) {
|
25
|
-
|
31
|
+
const entityNamePrefix = getEntityNameAtCursor(model, cursorPosition);
|
32
|
+
entitiesSuggestions = await generateEntitiesSuggestion(rangeToInsertSuggestion, parseResult.suggestEntity, database, entityNamePrefix);
|
26
33
|
}
|
27
34
|
if (parseResult.suggestFunctions) {
|
28
35
|
functionsSuggestions = await generateSimpleFunctionsSuggestion(rangeToInsertSuggestion);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "ydb-embedded-ui",
|
3
|
-
"version": "6.0
|
3
|
+
"version": "6.1.0",
|
4
4
|
"files": [
|
5
5
|
"dist"
|
6
6
|
],
|
@@ -21,7 +21,7 @@
|
|
21
21
|
"@gravity-ui/paranoid": "^1.4.1",
|
22
22
|
"@gravity-ui/react-data-table": "^2.0.1",
|
23
23
|
"@gravity-ui/uikit": "^6.10.2",
|
24
|
-
"@gravity-ui/websql-autocomplete": "^8.0
|
24
|
+
"@gravity-ui/websql-autocomplete": "^8.1.0",
|
25
25
|
"@reduxjs/toolkit": "^2.2.3",
|
26
26
|
"axios": "^1.6.8",
|
27
27
|
"colord": "^2.9.3",
|
@@ -70,7 +70,7 @@
|
|
70
70
|
"prepublishOnly": "npm run package",
|
71
71
|
"typecheck": "tsc --noEmit",
|
72
72
|
"prepare": "husky",
|
73
|
-
"test:e2e:install": "npx playwright install --with-deps
|
73
|
+
"test:e2e:install": "npx playwright install --with-deps",
|
74
74
|
"test:e2e": "npx playwright test --config=playwright.config.ts"
|
75
75
|
},
|
76
76
|
"lint-staged": {
|
File without changes
|
File without changes
|