From 3b6fc6c8e26c3c5d3c32979eaa8085d7ffe7b26d Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Fri, 15 Nov 2024 11:57:42 +0300 Subject: [PATCH 1/6] feat: use monaco snippets for query templates --- src/containers/Tenant/Query/NewSQL/NewSQL.tsx | 14 +- .../Tenant/Query/QueryEditor/QueryEditor.tsx | 15 +++ src/containers/Tenant/utils/schemaActions.ts | 10 +- .../Tenant/utils/schemaQueryTemplates.ts | 124 +++++++++++------- src/types/window.d.ts | 2 + src/utils/monaco/insertSnippet.ts | 6 + 6 files changed, 112 insertions(+), 59 deletions(-) create mode 100644 src/utils/monaco/insertSnippet.ts diff --git a/src/containers/Tenant/Query/NewSQL/NewSQL.tsx b/src/containers/Tenant/Query/NewSQL/NewSQL.tsx index 51963b2453..f0f248d85f 100644 --- a/src/containers/Tenant/Query/NewSQL/NewSQL.tsx +++ b/src/containers/Tenant/Query/NewSQL/NewSQL.tsx @@ -3,22 +3,16 @@ import React from 'react'; import {ChevronDown} from '@gravity-ui/icons'; import {Button, DropdownMenu} from '@gravity-ui/uikit'; -import {changeUserInput} from '../../../../store/reducers/executeQuery'; -import {useTypedDispatch} from '../../../../utils/hooks'; import {useChangeInputWithConfirmation} from '../../../../utils/hooks/withConfirmation/useChangeInputWithConfirmation'; +import {insertSnipperToEditor} from '../../../../utils/monaco/insertSnippet'; import {bindActions} from '../../utils/newSQLQueryActions'; import i18n from './i18n'; export function NewSQL() { - const dispatch = useTypedDispatch(); - - const insertTemplate = React.useCallback( - (input: string) => { - dispatch(changeUserInput({input})); - }, - [dispatch], - ); + const insertTemplate = React.useCallback((input: string) => { + insertSnipperToEditor(input); + }, []); const onTemplateClick = useChangeInputWithConfirmation(insertTemplate); diff --git a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx index 2e365bf6d9..fbd4a9209c 100644 --- a/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx +++ b/src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx @@ -200,8 +200,22 @@ export default function QueryEditor(props: QueryEditorProps) { } }); + const editorWillUnmount = () => { + window.ydbEditor = undefined; + }; + const editorDidMount = (editor: Monaco.editor.IStandaloneCodeEditor, monaco: typeof Monaco) => { + window.ydbEditor = editor; const keybindings = getKeyBindings(monaco); + monaco.editor.registerCommand('insertSnippetToEditor', (_asessor, input: string) => { + //suggestController is not properly typed yet in monaco-editor package + const contribution = editor.getContribution('snippetController2'); + if (contribution) { + editor.focus(); + editor.setValue(''); + contribution.insert(input); + } + }); initResizeHandler(editor); initUserPrompt(editor, getLastQueryText); editor.focus(); @@ -333,6 +347,7 @@ export default function QueryEditor(props: QueryEditorProps) { onChange={onChange} editorDidMount={editorDidMount} theme={`vs-${theme}`} + editorWillUnmount={editorWillUnmount} /> diff --git a/src/containers/Tenant/utils/schemaActions.ts b/src/containers/Tenant/utils/schemaActions.ts index a798e3b8fb..469b21928f 100644 --- a/src/containers/Tenant/utils/schemaActions.ts +++ b/src/containers/Tenant/utils/schemaActions.ts @@ -2,12 +2,12 @@ import copy from 'copy-to-clipboard'; import type {NavigationTreeNodeType, NavigationTreeProps} from 'ydb-ui-components'; import type {AppDispatch} from '../../../store'; -import {changeUserInput} from '../../../store/reducers/executeQuery'; import type {GetTableSchemaDataParams} from '../../../store/reducers/tableSchemaData'; import {TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID} from '../../../store/reducers/tenant/constants'; import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant'; import type {QuerySettings} from '../../../types/store/query'; import createToast from '../../../utils/createToast'; +import {insertSnipperToEditor} from '../../../utils/monaco/insertSnippet'; import {transformPath} from '../ObjectSummary/transformPath'; import type {SchemaData} from '../Schema/SchemaViewer/types'; import i18n from '../i18n'; @@ -75,13 +75,13 @@ const bindActions = ( }) : Promise.resolve(undefined); - userInputDataPromise.then((tableData) => { - dispatch(changeUserInput({input: tmpl({...params, tableData})})); - }); - + //order is important here: firstly we should open query tab and initialize editor (it will be set to window.ydbEditor), after that it is possible to insert snippet dispatch(setTenantPage(TENANT_PAGES_IDS.query)); dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery)); setActivePath(params.path); + userInputDataPromise.then((tableData) => { + insertSnipperToEditor(tmpl({...params, tableData})); + }); }; if (getConfirmation) { const confirmedPromise = getConfirmation(); diff --git a/src/containers/Tenant/utils/schemaQueryTemplates.ts b/src/containers/Tenant/utils/schemaQueryTemplates.ts index c26b5d8571..79f87822aa 100644 --- a/src/containers/Tenant/utils/schemaQueryTemplates.ts +++ b/src/containers/Tenant/utils/schemaQueryTemplates.ts @@ -9,8 +9,11 @@ export interface SchemaQueryParams { export type TemplateFn = (params?: SchemaQueryParams) => string; export const createTableTemplate = (params?: SchemaQueryParams) => { + const tableName = params?.relativePath + ? `\`${params?.relativePath}/my_row_table\`` + : '${1:my_row_table}'; return `-- docs: https://ydb.tech/en/docs/yql/reference/syntax/create_table -CREATE TABLE \`${params?.relativePath || '$path'}/ydb_row_table\` ( +CREATE TABLE ${tableName} ( category_id Uint64 NOT NULL, id Uint64, expire_at Datetime, @@ -42,8 +45,11 @@ WITH ( )`; }; export const createColumnTableTemplate = (params?: SchemaQueryParams) => { + const tableName = params?.relativePath + ? `\`${params?.relativePath}/my_column_table\`` + : '${1:my_column_table}'; return `-- docs: https://ydb.tech/en/docs/yql/reference/syntax/create_table#olap-tables -CREATE TABLE \`${params?.relativePath || '$path'}/ydb_column_table\` ( +CREATE TABLE ${tableName} ( id Int64 NOT NULL, author Text, title Text, @@ -57,42 +63,47 @@ export const createAsyncReplicationTemplate = () => { return `CREATE OBJECT secret_name (TYPE SECRET) WITH value="secret_value"; CREATE ASYNC REPLICATION my_replication -FOR \`/remote_database/table_name\` AS \`local_table_name\` --[, \`/remote_database/another_table_name\` AS \`another_local_table_name\` ...] +FOR \`/\${1:}/\${2:table_name}\` AS \${3:local_table_name} --[, \`/remote_database/another_table_name\` AS \`another_local_table_name\` ...] WITH ( - CONNECTION_STRING="grpcs://mydb.ydb.tech:2135/?database=/remote_database", + CONNECTION_STRING="grpcs://mydb.ydb.tech:2135/?database=/\${1:remote_database}", TOKEN_SECRET_NAME = "secret_name" -- ENDPOINT="mydb.ydb.tech:2135", - -- DATABASE=\`/remote_database\`, + -- DATABASE=\`\${1:/remote_database}\`, -- USER="user", -- PASSWORD_SECRET_NAME="your_password" );`; }; export const alterTableTemplate = (params?: SchemaQueryParams) => { + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; + return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/alter_table/ -ALTER TABLE \`${params?.relativePath || '$path'}\` +ALTER TABLE ${path} -- RENAME TO new_table_name -- DROP COLUMN some_existing_column ADD COLUMN numeric_column Int32;`; }; export const selectQueryTemplate = (params?: SchemaQueryParams) => { + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; const columns = params?.tableData?.map((column) => '`' + column.name + '`').join(', ') || '*'; return `SELECT ${columns} - FROM \`${params?.relativePath || '$path'}\` + FROM ${path} LIMIT 10;`; }; export const upsertQueryTemplate = (params?: SchemaQueryParams) => { + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; const columns = - params?.tableData?.map((column) => `\`${column.name}\``).join(', ') || `\`id\`, \`name\``; + params?.tableData?.map((column) => `\`${column.name}\``).join(', ') || `id, name`; - return `UPSERT INTO \`${params?.relativePath || '$path'}\` + return `UPSERT INTO ${path} ( ${columns} ) VALUES ( );`; }; export const dropExternalTableTemplate = (params?: SchemaQueryParams) => { - return `DROP EXTERNAL TABLE \`${params?.relativePath || '$path'}\`;`; + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:my_table}'; + return `DROP EXTERNAL TABLE ${path};`; }; export const createExternalTableTemplate = (params?: SchemaQueryParams) => { @@ -100,11 +111,18 @@ export const createExternalTableTemplate = (params?: SchemaQueryParams) => { // to create table in the same folder with data source const targetPath = params?.relativePath.split('/').slice(0, -1).join('/'); - return `CREATE EXTERNAL TABLE \`${targetPath || '$path'}/my_external_table\` ( + const target = targetPath + ? `\`${targetPath}/my_external_table\`` + : '${1:}/${2:my_external_table_name}'; + + const source = params?.relativePath + ? `${params.relativePath}` + : '${1:path_to_table}/${3:data_source_name}'; + return `CREATE EXTERNAL TABLE ${target} ( column1 Int, column2 Int ) WITH ( - DATA_SOURCE="${params?.relativePath || '$path'}", + DATA_SOURCE="${source}", LOCATION="", FORMAT="json_as_string", \`file_pattern\`="" @@ -112,8 +130,9 @@ export const createExternalTableTemplate = (params?: SchemaQueryParams) => { }; export const createTopicTemplate = (params?: SchemaQueryParams) => { + const path = params?.relativePath ? `\`${params?.relativePath}\`/my_topic` : '${1:my_topic}'; return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/create-topic -CREATE TOPIC \`${params?.relativePath || '$path'}/my_topic\` ( +CREATE TOPIC ${path} ( CONSUMER consumer1, CONSUMER consumer2 WITH (read_from = Datetime('1970-01-01T00:00:00Z')) -- Sets up the message write time starting from which the consumer will receive data. -- Value type: Datetime OR Timestamp OR integer (unix-timestamp in the numeric format). @@ -133,8 +152,9 @@ CREATE TOPIC \`${params?.relativePath || '$path'}/my_topic\` ( }; export const alterTopicTemplate = (params?: SchemaQueryParams) => { + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; return `-- docs: https://ydb.tech/en/docs/yql/reference/syntax/alter_topic -ALTER TOPIC \`${params?.relativePath || '$path'}\` +ALTER TOPIC ${path} ADD CONSUMER new_consumer WITH (read_from = Datetime('1970-01-01T00:00:00Z')), -- Sets up the message write time starting from which the consumer will receive data. -- Value type: Datetime OR Timestamp OR integer (unix-timestamp in the numeric format). -- Default value: now @@ -155,43 +175,50 @@ ALTER TOPIC \`${params?.relativePath || '$path'}\` }; export const dropTopicTemplate = (params?: SchemaQueryParams) => { - return `DROP TOPIC \`${params?.relativePath || '$path'}\`;`; + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; + return `DROP TOPIC ${path};`; }; export const createViewTemplate = (params?: SchemaQueryParams) => { - return `CREATE VIEW \`${params?.relativePath || '$path'}/my_view\` WITH (security_invoker = TRUE) AS SELECT 1;`; + const path = params?.relativePath ? `\`${params?.relativePath}\`/my_view` : '${1:my_view}'; + return `CREATE VIEW ${path} WITH (security_invoker = TRUE) AS SELECT 1;`; }; export const dropViewTemplate = (params?: SchemaQueryParams) => { - return `DROP VIEW \`${params?.relativePath || '$path'}\`;`; + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; + return `DROP VIEW ${path};`; }; export const dropAsyncReplicationTemplate = (params?: SchemaQueryParams) => { - return `DROP ASYNC REPLICATION \`${params?.relativePath || '$path'}\`;`; + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; + return `DROP ASYNC REPLICATION ${path};`; }; export const alterAsyncReplicationTemplate = (params?: SchemaQueryParams) => { - return `ALTER ASYNC REPLICATION \`${params?.relativePath || '$path'}\` SET (STATE = "DONE", FAILOVER_MODE = "FORCE");`; + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; + return `ALTER ASYNC REPLICATION ${path} SET (STATE = "DONE", FAILOVER_MODE = "FORCE");`; }; export const addTableIndex = (params?: SchemaQueryParams) => { - return `ALTER TABLE \`${params?.relativePath || '$path'}\` ADD INDEX \`$indexName\` GLOBAL ON (\`$columnName\`);`; + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; + return `ALTER TABLE ${path} ADD INDEX \${2:index_name} GLOBAL ON (\${3:});`; }; export const dropTableIndex = (params?: SchemaQueryParams) => { const indexName = params?.relativePath.split('/').pop(); const path = params?.relativePath.split('/').slice(0, -1).join('/'); - return `ALTER TABLE \`${path || '$path'}\` DROP INDEX \`${indexName || '$indexName'}\`;`; + return `ALTER TABLE \`${path || '${1:}'}\` DROP INDEX ${indexName || '${2:}'};`; }; export const createCdcStreamTemplate = (params?: SchemaQueryParams) => { + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/create_changefeed -ALTER TABLE \`${params?.relativePath || '$path'}\` ADD CHANGEFEED $name WITH ( - MODE = $mode, -- KEYS_ONLY, UPDATES, NEW_IMAGE, OLD_IMAGE, or NEW_AND_OLD_IMAGES - FORMAT = $format, -- JSON or DEBEZIUM_JSON - VIRTUAL_TIMESTAMPS = $virtualTimestamps, -- true or false - RETENTION_PERIOD = $retentionPeriod, -- Interval value, e.g., Interval('PT24H') - TOPIC_MIN_ACTIVE_PARTITIONS = $topicMinActivePartitions, - INITIAL_SCAN = $initialScan -- true or false +ALTER TABLE ${path} ADD CHANGEFEED \${2:changefeed_name} WITH ( + MODE = \${3:mode}, -- KEYS_ONLY, UPDATES, NEW_IMAGE, OLD_IMAGE, or NEW_AND_OLD_IMAGES + FORMAT = \${4:format}, -- JSON or DEBEZIUM_JSON + VIRTUAL_TIMESTAMPS = \${5:virtualTimestamps}, -- true or false + RETENTION_PERIOD = \${6:retentionPeriod}, -- Interval value, e.g., Interval('PT24H') + TOPIC_MIN_ACTIVE_PARTITIONS = \${7:topicMinActivePartitions}, + INITIAL_SCAN = \${8:initialScan} -- true or false ) -- MODE options: @@ -204,13 +231,13 @@ ALTER TABLE \`${params?.relativePath || '$path'}\` ADD CHANGEFEED $name WITH ( export const createGroupTemplate = () => { return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/create-group -CREATE GROUP $group_name +CREATE GROUP \${1:group_name} -- group_name: The name of the group. It may contain lowercase Latin letters and digits.`; }; export const createUserTemplate = () => { return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/create-user -CREATE USER $user_name [option] +CREATE USER \${1:user_name} [option] -- user_name: The name of the user. It may contain lowercase Latin letters and digits. -- option: The password of the user: -- PASSWORD 'password' creates a user with the password password. The ENCRYPTED option is always enabled. @@ -218,14 +245,15 @@ CREATE USER $user_name [option] }; export const deleteRowsTemplate = (params?: SchemaQueryParams) => { + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/delete -DELETE FROM \`${params?.relativePath || '$path'}\` -WHERE Key1 == $key1 AND Key2 >= $key2;`; +DELETE FROM ${path} +WHERE Key1 == \${2:key1} AND Key2 >= \${3:key2};`; }; export const dropGroupTemplate = () => { return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/drop-group -DROP GROUP [ IF EXISTS ] $group_name [, ...] +DROP GROUP [ IF EXISTS ] \${1:} [, ...] -- IF EXISTS: Suppress an error if the group doesn't exist. -- group_name: The name of the group to be deleted.`; @@ -233,17 +261,20 @@ DROP GROUP [ IF EXISTS ] $group_name [, ...] export const dropUserTemplate = () => { return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/drop-user -DROP USER [ IF EXISTS ] $user_name [, ...] +DROP USER [ IF EXISTS ] \${1:} [, ...] -- IF EXISTS: Suppress an error if the user doesn't exist. -- user_name: The name of the user to be deleted.`; }; export const grantPrivilegeTemplate = (params?: SchemaQueryParams) => { + const path = params?.relativePath + ? `\`${params?.relativePath}\`` + : '${2:}'; return ` -GRANT $permission_name [, ...] | ALL [PRIVILEGES] -ON \`${params?.relativePath || '$path_to_scheme_object'}\` [, ...] -TO $role_name [, ...] +GRANT \${1:} [, ...] | ALL [PRIVILEGES] +ON ${path} [, ...] +TO \${3:} [, ...] [WITH GRANT OPTION] -- permission_name: The name of the access right to schema objects that needs to be assigned. @@ -256,10 +287,13 @@ TO $role_name [, ...] }; export const revokePrivilegeTemplate = (params?: SchemaQueryParams) => { + const path = params?.relativePath + ? `\`${params?.relativePath}\`` + : '${2:}'; return ` -REVOKE [GRANT OPTION FOR] $permission_name [, ...] | ALL [PRIVILEGES] -ON \`${params?.relativePath || '$path_to_scheme_object'}\` [, ...] -FROM $role_name [, ...] +REVOKE [GRANT OPTION FOR] \${1:} [, ...] | ALL [PRIVILEGES] +ON ${path} [, ...] +FROM \${3:} [, ...] -- permission_name: The name of the access right to schema objects that needs to be revoked. -- path_to_scheme_object: The path to the schema object from which rights are being revoked. @@ -270,12 +304,14 @@ FROM $role_name [, ...] }; export const updateTableTemplate = (params?: SchemaQueryParams) => { + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/update -UPDATE \`${params?.relativePath || '$path'}\` -SET Value1 = YQL::ToString($value2 + 1), Value2 = $value2 - 1 -WHERE Key1 > $key1;`; +UPDATE ${path} +SET Value1 = YQL::ToString(\${2:value2} + 1), Value2 = \${3:value2} - 1 +WHERE Key1 > \${4:key1};`; }; export const dropTableTemplate = (params?: SchemaQueryParams) => { - return `DROP TABLE \`${params?.relativePath || '$path'}\`;`; + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; + return `DROP TABLE ${path};`; }; diff --git a/src/types/window.d.ts b/src/types/window.d.ts index a100bc79d4..c58bff6bf1 100644 --- a/src/types/window.d.ts +++ b/src/types/window.d.ts @@ -32,6 +32,8 @@ interface Window { Rum?: RumCounter; }; + ydbEditor?: Monaco.editor.IStandaloneCodeEditor; + web_version?: boolean; custom_backend?: string; meta_backend?: string; diff --git a/src/utils/monaco/insertSnippet.ts b/src/utils/monaco/insertSnippet.ts new file mode 100644 index 0000000000..71511ce67b --- /dev/null +++ b/src/utils/monaco/insertSnippet.ts @@ -0,0 +1,6 @@ +export function insertSnipperToEditor(input: string) { + if (!window.ydbEditor) { + console.error('Monaco editor not found'); + } + window.ydbEditor?.trigger(undefined, 'insertSnippetToEditor', input); +} From 32a905a01daca140011b426fa993c542b74f000e Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Fri, 15 Nov 2024 15:22:09 +0300 Subject: [PATCH 2/6] fix: templates --- .../Tenant/utils/schemaQueryTemplates.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/containers/Tenant/utils/schemaQueryTemplates.ts b/src/containers/Tenant/utils/schemaQueryTemplates.ts index 79f87822aa..cb78984476 100644 --- a/src/containers/Tenant/utils/schemaQueryTemplates.ts +++ b/src/containers/Tenant/utils/schemaQueryTemplates.ts @@ -63,12 +63,12 @@ export const createAsyncReplicationTemplate = () => { return `CREATE OBJECT secret_name (TYPE SECRET) WITH value="secret_value"; CREATE ASYNC REPLICATION my_replication -FOR \`/\${1:}/\${2:table_name}\` AS \${3:local_table_name} --[, \`/remote_database/another_table_name\` AS \`another_local_table_name\` ...] +FOR \${1:} AS \${2:local_table_name} --[, \`/remote_database/another_table_name\` AS \`another_local_table_name\` ...] WITH ( - CONNECTION_STRING="grpcs://mydb.ydb.tech:2135/?database=/\${1:remote_database}", + CONNECTION_STRING="grpcs://mydb.ydb.tech:2135/?database=/\${3:}", TOKEN_SECRET_NAME = "secret_name" -- ENDPOINT="mydb.ydb.tech:2135", - -- DATABASE=\`\${1:/remote_database}\`, + -- DATABASE=\`\${3:/remote_database}\`, -- USER="user", -- PASSWORD_SECRET_NAME="your_password" );`; @@ -111,13 +111,9 @@ export const createExternalTableTemplate = (params?: SchemaQueryParams) => { // to create table in the same folder with data source const targetPath = params?.relativePath.split('/').slice(0, -1).join('/'); - const target = targetPath - ? `\`${targetPath}/my_external_table\`` - : '${1:}/${2:my_external_table_name}'; + const target = targetPath ? `\`${targetPath}/my_external_table\`` : '${1:}'; - const source = params?.relativePath - ? `${params.relativePath}` - : '${1:path_to_table}/${3:data_source_name}'; + const source = params?.relativePath ? `${params.relativePath}` : '${2:}'; return `CREATE EXTERNAL TABLE ${target} ( column1 Int, column2 Int From 52148ebbc3bfed35fedf5e03ce4b899628fab525 Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Fri, 15 Nov 2024 15:22:38 +0300 Subject: [PATCH 3/6] fix: "New SQL" button rename --- src/containers/Tenant/Query/NewSQL/i18n/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/Tenant/Query/NewSQL/i18n/en.json b/src/containers/Tenant/Query/NewSQL/i18n/en.json index 3484a226a2..9152293908 100644 --- a/src/containers/Tenant/Query/NewSQL/i18n/en.json +++ b/src/containers/Tenant/Query/NewSQL/i18n/en.json @@ -1,5 +1,5 @@ { - "button.new-sql": "New SQL", + "button.new-sql": "New query", "action.create-row-table": "Create row table", "action.create-column-table": "Create column table", "action.create-external-table": "Create external table", From 278746bdc50b00ef6730759f15fd64e22c7f595d Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Mon, 18 Nov 2024 13:34:31 +0300 Subject: [PATCH 4/6] fix: typo --- src/containers/Tenant/Query/NewSQL/NewSQL.tsx | 4 ++-- src/containers/Tenant/utils/schemaActions.ts | 4 ++-- src/utils/monaco/insertSnippet.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/containers/Tenant/Query/NewSQL/NewSQL.tsx b/src/containers/Tenant/Query/NewSQL/NewSQL.tsx index f0f248d85f..dbcf7ce896 100644 --- a/src/containers/Tenant/Query/NewSQL/NewSQL.tsx +++ b/src/containers/Tenant/Query/NewSQL/NewSQL.tsx @@ -4,14 +4,14 @@ import {ChevronDown} from '@gravity-ui/icons'; import {Button, DropdownMenu} from '@gravity-ui/uikit'; import {useChangeInputWithConfirmation} from '../../../../utils/hooks/withConfirmation/useChangeInputWithConfirmation'; -import {insertSnipperToEditor} from '../../../../utils/monaco/insertSnippet'; +import {insertSnippetToEditor} from '../../../../utils/monaco/insertSnippet'; import {bindActions} from '../../utils/newSQLQueryActions'; import i18n from './i18n'; export function NewSQL() { const insertTemplate = React.useCallback((input: string) => { - insertSnipperToEditor(input); + insertSnippetToEditor(input); }, []); const onTemplateClick = useChangeInputWithConfirmation(insertTemplate); diff --git a/src/containers/Tenant/utils/schemaActions.ts b/src/containers/Tenant/utils/schemaActions.ts index 469b21928f..85d5851e47 100644 --- a/src/containers/Tenant/utils/schemaActions.ts +++ b/src/containers/Tenant/utils/schemaActions.ts @@ -7,7 +7,7 @@ import {TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID} from '../../../store/reducers/te import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant'; import type {QuerySettings} from '../../../types/store/query'; import createToast from '../../../utils/createToast'; -import {insertSnipperToEditor} from '../../../utils/monaco/insertSnippet'; +import {insertSnippetToEditor} from '../../../utils/monaco/insertSnippet'; import {transformPath} from '../ObjectSummary/transformPath'; import type {SchemaData} from '../Schema/SchemaViewer/types'; import i18n from '../i18n'; @@ -80,7 +80,7 @@ const bindActions = ( dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery)); setActivePath(params.path); userInputDataPromise.then((tableData) => { - insertSnipperToEditor(tmpl({...params, tableData})); + insertSnippetToEditor(tmpl({...params, tableData})); }); }; if (getConfirmation) { diff --git a/src/utils/monaco/insertSnippet.ts b/src/utils/monaco/insertSnippet.ts index 71511ce67b..1a84bd2590 100644 --- a/src/utils/monaco/insertSnippet.ts +++ b/src/utils/monaco/insertSnippet.ts @@ -1,4 +1,4 @@ -export function insertSnipperToEditor(input: string) { +export function insertSnippetToEditor(input: string) { if (!window.ydbEditor) { console.error('Monaco editor not found'); } From e1065051e568e5df1f9b9402e7b93357281d86c9 Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Mon, 18 Nov 2024 14:04:14 +0300 Subject: [PATCH 5/6] fix: snippets --- src/containers/Tenant/Query/NewSQL/NewSQL.tsx | 4 - .../Tenant/Query/NewSQL/i18n/en.json | 1 - .../Tenant/utils/newSQLQueryActions.ts | 1 - .../Tenant/utils/schemaQueryTemplates.ts | 73 ++++++++++--------- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/containers/Tenant/Query/NewSQL/NewSQL.tsx b/src/containers/Tenant/Query/NewSQL/NewSQL.tsx index dbcf7ce896..d772ded269 100644 --- a/src/containers/Tenant/Query/NewSQL/NewSQL.tsx +++ b/src/containers/Tenant/Query/NewSQL/NewSQL.tsx @@ -50,10 +50,6 @@ export function NewSQL() { text: i18n('action.select-rows'), action: actions.selectQuery, }, - { - text: i18n('action.select-from-external-table'), - action: actions.selectQueryFromExternalTable, - }, { text: i18n('action.delete-rows'), action: actions.deleteRows, diff --git a/src/containers/Tenant/Query/NewSQL/i18n/en.json b/src/containers/Tenant/Query/NewSQL/i18n/en.json index 9152293908..dface2060e 100644 --- a/src/containers/Tenant/Query/NewSQL/i18n/en.json +++ b/src/containers/Tenant/Query/NewSQL/i18n/en.json @@ -7,7 +7,6 @@ "action.update-table": "Update table", "action.alter-table": "Alter table", "action.select-rows": "Select from a table", - "action.select-from-external-table": "Select from external table", "action.delete-rows": "Delete rows", "action.drop-table": "Drop table", "action.add-index": "Add index", diff --git a/src/containers/Tenant/utils/newSQLQueryActions.ts b/src/containers/Tenant/utils/newSQLQueryActions.ts index 0eb21fd0a6..9baf9dbb3f 100644 --- a/src/containers/Tenant/utils/newSQLQueryActions.ts +++ b/src/containers/Tenant/utils/newSQLQueryActions.ts @@ -43,7 +43,6 @@ export const bindActions = (changeUserInput: (input: string) => void) => { upsertQuery: inputQuery(upsertQueryTemplate), createExternalTable: inputQuery(createExternalTableTemplate), dropExternalTable: inputQuery(dropExternalTableTemplate), - selectQueryFromExternalTable: inputQuery(selectQueryTemplate), createTopic: inputQuery(createTopicTemplate), alterTopic: inputQuery(alterTopicTemplate), dropTopic: inputQuery(dropTopicTemplate), diff --git a/src/containers/Tenant/utils/schemaQueryTemplates.ts b/src/containers/Tenant/utils/schemaQueryTemplates.ts index cb78984476..3fc174719c 100644 --- a/src/containers/Tenant/utils/schemaQueryTemplates.ts +++ b/src/containers/Tenant/utils/schemaQueryTemplates.ts @@ -60,10 +60,11 @@ PARTITION BY HASH(id) WITH (STORE = COLUMN)`; }; export const createAsyncReplicationTemplate = () => { - return `CREATE OBJECT secret_name (TYPE SECRET) WITH value="secret_value"; + return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/create-async-replication +CREATE OBJECT secret_name (TYPE SECRET) WITH value="secret_value"; CREATE ASYNC REPLICATION my_replication -FOR \${1:} AS \${2:local_table_name} --[, \`/remote_database/another_table_name\` AS \`another_local_table_name\` ...] +FOR \${1:} AS \${2:replica_table} --[, \`/remote_database/another_table_name\` AS \`another_local_table_name\` ...] WITH ( CONNECTION_STRING="grpcs://mydb.ydb.tech:2135/?database=/\${3:}", TOKEN_SECRET_NAME = "secret_name" @@ -81,24 +82,27 @@ export const alterTableTemplate = (params?: SchemaQueryParams) => { ALTER TABLE ${path} -- RENAME TO new_table_name -- DROP COLUMN some_existing_column - ADD COLUMN numeric_column Int32;`; +\${2:ADD COLUMN numeric_column Int32};`; }; export const selectQueryTemplate = (params?: SchemaQueryParams) => { - const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; - const columns = params?.tableData?.map((column) => '`' + column.name + '`').join(', ') || '*'; + const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${2:}'; + const columns = + params?.tableData?.map((column) => '`' + column.name + '`').join(', ') || '${1:*}'; return `SELECT ${columns} - FROM ${path} - LIMIT 10;`; +FROM ${path} +WHERE \${3:Key1 = 1} +ORDER BY \${4:Key1} +LIMIT \${5:10};`; }; export const upsertQueryTemplate = (params?: SchemaQueryParams) => { const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; const columns = - params?.tableData?.map((column) => `\`${column.name}\``).join(', ') || `id, name`; - + params?.tableData?.map((column) => `\`${column.name}\``).join(', ') || '${2:id, name}'; + const values = params?.tableData ? '${3: }' : '${3:1, "foo"}'; return `UPSERT INTO ${path} - ( ${columns} ) -VALUES ( );`; +( ${columns} ) +VALUES ( ${values} );`; }; export const dropExternalTableTemplate = (params?: SchemaQueryParams) => { @@ -191,7 +195,8 @@ export const dropAsyncReplicationTemplate = (params?: SchemaQueryParams) => { export const alterAsyncReplicationTemplate = (params?: SchemaQueryParams) => { const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; - return `ALTER ASYNC REPLICATION ${path} SET (STATE = "DONE", FAILOVER_MODE = "FORCE");`; + return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/alter-async-replication +ALTER ASYNC REPLICATION ${path} SET (STATE = "DONE", FAILOVER_MODE = "FORCE");`; }; export const addTableIndex = (params?: SchemaQueryParams) => { @@ -202,19 +207,20 @@ export const addTableIndex = (params?: SchemaQueryParams) => { export const dropTableIndex = (params?: SchemaQueryParams) => { const indexName = params?.relativePath.split('/').pop(); const path = params?.relativePath.split('/').slice(0, -1).join('/'); - return `ALTER TABLE \`${path || '${1:}'}\` DROP INDEX ${indexName || '${2:}'};`; + const pathSnippet = path ? `\`${path}\`` : '${1:}'; + return `ALTER TABLE ${pathSnippet} DROP INDEX ${indexName || '${2:}'};`; }; export const createCdcStreamTemplate = (params?: SchemaQueryParams) => { const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; - return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/create_changefeed + return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/alter_table/changefeed ALTER TABLE ${path} ADD CHANGEFEED \${2:changefeed_name} WITH ( - MODE = \${3:mode}, -- KEYS_ONLY, UPDATES, NEW_IMAGE, OLD_IMAGE, or NEW_AND_OLD_IMAGES - FORMAT = \${4:format}, -- JSON or DEBEZIUM_JSON - VIRTUAL_TIMESTAMPS = \${5:virtualTimestamps}, -- true or false - RETENTION_PERIOD = \${6:retentionPeriod}, -- Interval value, e.g., Interval('PT24H') - TOPIC_MIN_ACTIVE_PARTITIONS = \${7:topicMinActivePartitions}, - INITIAL_SCAN = \${8:initialScan} -- true or false + MODE = \${3:'UPDATES'}, -- KEYS_ONLY, UPDATES, NEW_IMAGE, OLD_IMAGE, or NEW_AND_OLD_IMAGES + FORMAT = \${4:'JSON'}, -- JSON or DEBEZIUM_JSON + VIRTUAL_TIMESTAMPS = \${5:TRUE}, -- true or false + RETENTION_PERIOD = \${6:Interval('PT12H')}, -- Interval value, e.g., Interval('PT24H') + -- TOPIC_MIN_ACTIVE_PARTITIONS: The number of topic partitions. By default, the number of topic partitions is equal to the number of table partitions + INITIAL_SCAN = \${8:TRUE} -- true or false ) -- MODE options: @@ -233,7 +239,7 @@ CREATE GROUP \${1:group_name} export const createUserTemplate = () => { return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/create-user -CREATE USER \${1:user_name} [option] +CREATE USER \${1:user_name} PASSWORD \${2:'password'} -- user_name: The name of the user. It may contain lowercase Latin letters and digits. -- option: The password of the user: -- PASSWORD 'password' creates a user with the password password. The ENCRYPTED option is always enabled. @@ -244,12 +250,12 @@ export const deleteRowsTemplate = (params?: SchemaQueryParams) => { const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/delete DELETE FROM ${path} -WHERE Key1 == \${2:key1} AND Key2 >= \${3:key2};`; +WHERE \${2:Key1 = 1};`; }; export const dropGroupTemplate = () => { return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/drop-group -DROP GROUP [ IF EXISTS ] \${1:} [, ...] +DROP GROUP \${1:} -- IF EXISTS: Suppress an error if the group doesn't exist. -- group_name: The name of the group to be deleted.`; @@ -257,7 +263,7 @@ DROP GROUP [ IF EXISTS ] \${1:} [, ...] export const dropUserTemplate = () => { return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/drop-user -DROP USER [ IF EXISTS ] \${1:} [, ...] +DROP USER \${1:} -- IF EXISTS: Suppress an error if the user doesn't exist. -- user_name: The name of the user to be deleted.`; @@ -267,11 +273,9 @@ export const grantPrivilegeTemplate = (params?: SchemaQueryParams) => { const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${2:}'; - return ` -GRANT \${1:} [, ...] | ALL [PRIVILEGES] -ON ${path} [, ...] -TO \${3:} [, ...] -[WITH GRANT OPTION] + return `GRANT \${1:} +ON ${path} +TO \${3:} -- permission_name: The name of the access right to schema objects that needs to be assigned. -- path_to_scheme_object: The path to the schema object for which rights are being granted. @@ -286,10 +290,9 @@ export const revokePrivilegeTemplate = (params?: SchemaQueryParams) => { const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${2:}'; - return ` -REVOKE [GRANT OPTION FOR] \${1:} [, ...] | ALL [PRIVILEGES] -ON ${path} [, ...] -FROM \${3:} [, ...] + return `REVOKE \${1:} +ON ${path} +FROM \${3:} -- permission_name: The name of the access right to schema objects that needs to be revoked. -- path_to_scheme_object: The path to the schema object from which rights are being revoked. @@ -303,8 +306,8 @@ export const updateTableTemplate = (params?: SchemaQueryParams) => { const path = params?.relativePath ? `\`${params?.relativePath}\`` : '${1:}'; return `-- docs: https://ydb.tech/docs/en/yql/reference/syntax/update UPDATE ${path} -SET Value1 = YQL::ToString(\${2:value2} + 1), Value2 = \${3:value2} - 1 -WHERE Key1 > \${4:key1};`; +SET \${2:Column1 = 'foo', Column2 = 'bar'} +WHERE \${3:Key1 = 1};`; }; export const dropTableTemplate = (params?: SchemaQueryParams) => { From a22d8795cf1fc427ef8e886c0e8e2c7f32c1b8ea Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Mon, 18 Nov 2024 16:11:34 +0300 Subject: [PATCH 6/6] fix: review --- src/containers/Tenant/utils/schemaQueryTemplates.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/containers/Tenant/utils/schemaQueryTemplates.ts b/src/containers/Tenant/utils/schemaQueryTemplates.ts index 3fc174719c..05b085fb4c 100644 --- a/src/containers/Tenant/utils/schemaQueryTemplates.ts +++ b/src/containers/Tenant/utils/schemaQueryTemplates.ts @@ -66,10 +66,10 @@ CREATE OBJECT secret_name (TYPE SECRET) WITH value="secret_value"; CREATE ASYNC REPLICATION my_replication FOR \${1:} AS \${2:replica_table} --[, \`/remote_database/another_table_name\` AS \`another_local_table_name\` ...] WITH ( - CONNECTION_STRING="grpcs://mydb.ydb.tech:2135/?database=/\${3:}", + CONNECTION_STRING="\${3:grpcs://mydb.ydb.tech:2135/?database=/remote_database}", TOKEN_SECRET_NAME = "secret_name" -- ENDPOINT="mydb.ydb.tech:2135", - -- DATABASE=\`\${3:/remote_database}\`, + -- DATABASE=\`/remote_database\`, -- USER="user", -- PASSWORD_SECRET_NAME="your_password" );`;