From 1728e6162e5be9c5fdc0954595b562873ad6fb9b Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Mon, 23 Sep 2024 16:26:17 +0300 Subject: [PATCH] feat: add rows limit to query settings (#1291) --- package-lock.json | 10 ++++ package.json | 1 + .../getChangedQueryExecutionSettings.test.ts | 15 ++---- .../utils/getChangedQueryExecutionSettings.ts | 5 +- ...dQueryExecutionSettingsDescription.test.ts | 16 +++---- ...hangedQueryExecutionSettingsDescription.ts | 15 +++--- .../QuerySettingsDialog.scss | 1 + .../QuerySettingsDialog.tsx | 42 ++++++++++++++++- .../QuerySettingsSelect.tsx | 2 + .../Query/QuerySettingsDialog/constants.ts | 3 ++ .../Query/QuerySettingsDialog/i18n/en.json | 3 ++ .../Query/QuerySettingsDialog/i18n/ru.json | 3 ++ src/services/api.ts | 1 + src/services/settings.ts | 3 +- src/store/reducers/executeQuery.ts | 3 ++ src/types/store/query.ts | 11 ++--- src/utils/constants.ts | 11 ----- src/utils/hooks/useChangedQuerySettings.ts | 7 +-- .../hooks/useLastQueryExecutionSettings.ts | 16 +++---- src/utils/hooks/useQueryExecutionSettings.ts | 12 ++--- src/utils/query.ts | 47 +++++++++++++++++++ tests/suites/tenant/queryEditor/constants.ts | 31 ++---------- 22 files changed, 162 insertions(+), 96 deletions(-) diff --git a/package-lock.json b/package-lock.json index a3452e73d..c65012a1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@gravity-ui/table": "^0.5.0", "@gravity-ui/uikit": "^6.20.1", "@gravity-ui/websql-autocomplete": "^9.1.0", + "@hookform/resolvers": "^3.9.0", "@reduxjs/toolkit": "^2.2.3", "@tanstack/react-table": "^8.19.3", "axios": "^1.7.3", @@ -4085,6 +4086,15 @@ "node": ">=16.0.0" } }, + "node_modules/@hookform/resolvers": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.0.tgz", + "integrity": "sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg==", + "license": "MIT", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", diff --git a/package.json b/package.json index 081b06ff7..ffb483b02 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@gravity-ui/table": "^0.5.0", "@gravity-ui/uikit": "^6.20.1", "@gravity-ui/websql-autocomplete": "^9.1.0", + "@hookform/resolvers": "^3.9.0", "@reduxjs/toolkit": "^2.2.3", "@tanstack/react-table": "^8.19.3", "axios": "^1.7.3", diff --git a/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.test.ts b/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.test.ts index 3b4d6bd08..086a7b1ba 100644 --- a/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.test.ts +++ b/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.test.ts @@ -1,19 +1,12 @@ import type {QuerySettings} from '../../../../../types/store/query'; import { + DEFAULT_QUERY_SETTINGS, QUERY_MODES, STATISTICS_MODES, TRACING_LEVELS, TRANSACTION_MODES, } from '../../../../../utils/query'; -const DEFAULT_QUERY_SETTINGS: QuerySettings = { - queryMode: QUERY_MODES.query, - transactionMode: TRANSACTION_MODES.implicit, - timeout: '60', - statisticsMode: STATISTICS_MODES.none, - tracingLevel: TRACING_LEVELS.detailed, -}; - import getChangedQueryExecutionSettings from './getChangedQueryExecutionSettings'; describe('getChangedQueryExecutionSettings', () => { @@ -27,7 +20,8 @@ describe('getChangedQueryExecutionSettings', () => { const currentSettings: QuerySettings = { ...DEFAULT_QUERY_SETTINGS, queryMode: QUERY_MODES.data, - timeout: '30', + timeout: 30, + limitRows: undefined, }; const result = getChangedQueryExecutionSettings(currentSettings, DEFAULT_QUERY_SETTINGS); expect(result).toEqual(['queryMode', 'timeout']); @@ -37,7 +31,8 @@ describe('getChangedQueryExecutionSettings', () => { const currentSettings: QuerySettings = { queryMode: QUERY_MODES.data, transactionMode: TRANSACTION_MODES.onlinero, - timeout: '90', + timeout: 90, + limitRows: DEFAULT_QUERY_SETTINGS.limitRows, statisticsMode: STATISTICS_MODES.basic, tracingLevel: TRACING_LEVELS.basic, }; diff --git a/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.ts b/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.ts index a456a2e5b..a0b292952 100644 --- a/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.ts +++ b/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings.ts @@ -8,6 +8,9 @@ export default function getChangedQueryExecutionSettings( const defaultMap = new Map(Object.entries(defaultSettings)); return Array.from(currentMap.keys()).filter( - (key) => currentMap.get(key) !== defaultMap.get(key), + (key) => + currentMap.has(key) && + currentMap.get(key) !== undefined && + currentMap.get(key) !== defaultMap.get(key), ) as (keyof QuerySettings)[]; } diff --git a/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.test.ts b/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.test.ts index dec1fa5a8..d8e23f126 100644 --- a/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.test.ts +++ b/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.test.ts @@ -1,5 +1,6 @@ import type {QuerySettings} from '../../../../../types/store/query'; import { + DEFAULT_QUERY_SETTINGS, QUERY_MODES, QUERY_MODES_TITLES, STATISTICS_MODES, @@ -13,14 +14,6 @@ import {QUERY_SETTINGS_FIELD_SETTINGS} from '../../QuerySettingsDialog/constants import getChangedQueryExecutionSettingsDescription from './getChangedQueryExecutionSettingsDescription'; -const DEFAULT_QUERY_SETTINGS: QuerySettings = { - queryMode: QUERY_MODES.query, - transactionMode: TRANSACTION_MODES.implicit, - timeout: '60', - statisticsMode: STATISTICS_MODES.none, - tracingLevel: TRACING_LEVELS.detailed, -}; - describe('getChangedQueryExecutionSettingsDescription', () => { it('should return an empty object if no settings changed', () => { const currentSettings: QuerySettings = {...DEFAULT_QUERY_SETTINGS}; @@ -37,7 +30,8 @@ describe('getChangedQueryExecutionSettingsDescription', () => { const currentSettings: QuerySettings = { ...DEFAULT_QUERY_SETTINGS, queryMode: QUERY_MODES.pg, - timeout: '63', + timeout: 63, + limitRows: 100, }; const result = getChangedQueryExecutionSettingsDescription({ @@ -51,6 +45,7 @@ describe('getChangedQueryExecutionSettingsDescription', () => { (option) => option.value === QUERY_MODES.pg, )?.content, [QUERY_SETTINGS_FIELD_SETTINGS.timeout.title]: '63', + [QUERY_SETTINGS_FIELD_SETTINGS.limitRows.title]: '100', }); }); @@ -58,7 +53,8 @@ describe('getChangedQueryExecutionSettingsDescription', () => { const currentSettings: QuerySettings = { queryMode: QUERY_MODES.data, transactionMode: TRANSACTION_MODES.snapshot, - timeout: '120', + timeout: 120, + limitRows: DEFAULT_QUERY_SETTINGS.limitRows, statisticsMode: STATISTICS_MODES.profile, tracingLevel: TRACING_LEVELS.diagnostic, }; diff --git a/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.ts b/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.ts index cbd97c29b..7ed4f987a 100644 --- a/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.ts +++ b/src/containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription.ts @@ -15,15 +15,18 @@ export default function getChangedQueryExecutionSettingsDescription({ keys.forEach((key) => { const settings = QUERY_SETTINGS_FIELD_SETTINGS[key]; - const currentValue = currentSettings[key] as string; + const currentValue = currentSettings[key]; if ('options' in settings) { - const content = settings.options.find((option) => option.value === currentValue) - ?.content as string; + const content = settings.options.find( + (option) => option.value === currentValue, + )?.content; - result[settings.title] = content; - } else { - result[settings.title] = currentValue; + if (content) { + result[settings.title] = content; + } + } else if (currentValue) { + result[settings.title] = String(currentValue); } }); diff --git a/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.scss b/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.scss index 0eae7fc89..7a2b9ddfe 100644 --- a/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.scss +++ b/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.scss @@ -28,6 +28,7 @@ flex: 6; } + &__limit-rows, &__timeout { width: 33.3%; margin-right: var(--g-spacing-2); diff --git a/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx b/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx index 6789c19f2..a34fe13a8 100644 --- a/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx +++ b/src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx @@ -1,6 +1,7 @@ import React from 'react'; import {Dialog, Link as ExternalLink, Flex, TextInput} from '@gravity-ui/uikit'; +import {zodResolver} from '@hookform/resolvers/zod'; import {Controller, useForm} from 'react-hook-form'; import {useTracingLevelOptionAvailable} from '../../../../store/reducers/capabilities/hooks'; @@ -15,6 +16,7 @@ import { useTypedDispatch, useTypedSelector, } from '../../../../utils/hooks'; +import {querySettingsValidationSchema} from '../../../../utils/query'; import {QuerySettingsSelect} from './QuerySettingsSelect'; import {QUERY_SETTINGS_FIELD_SETTINGS} from './constants'; @@ -66,8 +68,13 @@ interface QuerySettingsFormProps { } function QuerySettingsForm({initialValues, onSubmit, onClose}: QuerySettingsFormProps) { - const {control, handleSubmit} = useForm({ + const { + control, + handleSubmit, + formState: {errors}, + } = useForm({ defaultValues: initialValues, + resolver: zodResolver(querySettingsValidationSchema), }); const enableTracingLevel = useTracingLevelOptionAvailable(); @@ -85,6 +92,7 @@ function QuerySettingsForm({initialValues, onSubmit, onClose}: QuerySettingsForm control={control} render={({field}) => ( ( {i18n('form.timeout.seconds')} @@ -128,6 +141,7 @@ function QuerySettingsForm({initialValues, onSubmit, onClose}: QuerySettingsForm control={control} render={({field}) => ( ( ( + + +
+ ( + + )} + /> +
+
= SelectOption & {isDefault?: boolean}; interface QuerySettingsSelectProps { + id?: string; setting: T; settingOptions: QuerySettingSelectOption[]; onUpdateSetting: (mode: T) => void; @@ -32,6 +33,7 @@ export function QuerySettingsSelect(props: QuerySettingsSe return (
+ id={props.id} options={props.settingOptions} value={[props.setting]} onUpdate={(value) => { diff --git a/src/containers/Tenant/Query/QuerySettingsDialog/constants.ts b/src/containers/Tenant/Query/QuerySettingsDialog/constants.ts index d6aed7094..7866c9ad6 100644 --- a/src/containers/Tenant/Query/QuerySettingsDialog/constants.ts +++ b/src/containers/Tenant/Query/QuerySettingsDialog/constants.ts @@ -148,4 +148,7 @@ export const QUERY_SETTINGS_FIELD_SETTINGS = { timeout: { title: formI18n('form.timeout'), }, + limitRows: { + title: formI18n('form.limit-rows'), + }, } as const; diff --git a/src/containers/Tenant/Query/QuerySettingsDialog/i18n/en.json b/src/containers/Tenant/Query/QuerySettingsDialog/i18n/en.json index 19a1fb52f..55b7c2398 100644 --- a/src/containers/Tenant/Query/QuerySettingsDialog/i18n/en.json +++ b/src/containers/Tenant/Query/QuerySettingsDialog/i18n/en.json @@ -5,9 +5,12 @@ "form.transaction-mode": "Transaction mode", "form.statistics-mode": "Statistics collection mode", "form.tracing-level": "Tracing level", + "form.limit-rows": "Limit rows", "button-done": "Save", "button-cancel": "Cancel", "form.timeout.seconds": "sec", + "form.validation.timeout": "Must be positive", + "form.validation.limitRows": "Must be between 1 and 100000", "description.default": " (default)", "docs": "Documentation" } diff --git a/src/containers/Tenant/Query/QuerySettingsDialog/i18n/ru.json b/src/containers/Tenant/Query/QuerySettingsDialog/i18n/ru.json index 5bd0dadbd..ca93e2d75 100644 --- a/src/containers/Tenant/Query/QuerySettingsDialog/i18n/ru.json +++ b/src/containers/Tenant/Query/QuerySettingsDialog/i18n/ru.json @@ -5,9 +5,12 @@ "form.transaction-mode": "Уровень изоляции", "form.statistics-mode": "Режим сбора статистики", "form.tracing-level": "Tracing level", + "form.limit-rows": "Лимит строк", "button-done": "Готово", "button-cancel": "Отменить", "form.timeout.seconds": "сек", + "form.validation.timeout": "Таймаут должен быть положительным", + "form.validation.limitRows": "Лимит строк должен быть между 1 и 100000", "description.default": " (default)", "docs": "Документация" } diff --git a/src/services/api.ts b/src/services/api.ts index 6148a55ad..6b18ec304 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -540,6 +540,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper { transaction_mode?: TransactionMode; timeout?: Timeout; query_id?: string; + limit_rows?: number; }, {concurrentId, signal, withRetries}: AxiosOptions = {}, ) { diff --git a/src/services/settings.ts b/src/services/settings.ts index feed25697..222100415 100644 --- a/src/services/settings.ts +++ b/src/services/settings.ts @@ -4,7 +4,6 @@ import { AUTOCOMPLETE_ON_ENTER, AUTO_REFRESH_INTERVAL, BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, - DEFAULT_QUERY_SETTINGS, ENABLE_AUTOCOMPLETE, INVERTED_DISKS_KEY, IS_HOTKEYS_HELP_HIDDEN_KEY, @@ -23,7 +22,7 @@ import { USE_CLUSTER_BALANCER_AS_BACKEND_KEY, USE_PAGINATED_TABLES_KEY, } from '../utils/constants'; -import {QUERY_ACTIONS} from '../utils/query'; +import {DEFAULT_QUERY_SETTINGS, QUERY_ACTIONS} from '../utils/query'; import {parseJson} from '../utils/utils'; export type SettingsObject = Record; diff --git a/src/store/reducers/executeQuery.ts b/src/store/reducers/executeQuery.ts index 1810324bb..c197ae858 100644 --- a/src/store/reducers/executeQuery.ts +++ b/src/store/reducers/executeQuery.ts @@ -233,6 +233,9 @@ export const executeQueryApi = api.injectEndpoints({ querySettings.tracingLevel && enableTracingLevel ? TracingLevelNumber[querySettings.tracingLevel] : undefined, + limit_rows: isNumeric(querySettings.limitRows) + ? Number(querySettings.limitRows) + : undefined, transaction_mode: querySettings.transactionMode === 'implicit' ? undefined diff --git a/src/types/store/query.ts b/src/types/store/query.ts index ab48de03c..31a7312ff 100644 --- a/src/types/store/query.ts +++ b/src/types/store/query.ts @@ -1,3 +1,5 @@ +import type {z} from 'zod'; + import type { QUERY_ACTIONS, QUERY_MODES, @@ -5,6 +7,7 @@ import type { STATISTICS_MODES, TRACING_LEVELS, TRANSACTION_MODES, + querySettingsValidationSchema, } from '../../utils/query'; import type {IResponseError, NetworkError} from '../api/error'; import type { @@ -39,13 +42,7 @@ export interface QueryRequestParams { query: string; } -export interface QuerySettings { - queryMode: QueryMode; - transactionMode: TransactionMode; - timeout?: string; - statisticsMode?: StatisticsMode; - tracingLevel?: TracingLevel; -} +export type QuerySettings = z.infer; export type QueryErrorResponse = IResponseError; export type QueryError = NetworkError | QueryErrorResponse; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 92cbea3b3..a5dc07c15 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -2,9 +2,6 @@ import DataTable from '@gravity-ui/react-data-table'; import type {Settings} from '@gravity-ui/react-data-table'; import {EType} from '../types/api/tablet'; -import type {QuerySettings} from '../types/store/query'; - -import {QUERY_MODES, STATISTICS_MODES, TRACING_LEVELS, TRANSACTION_MODES} from './query'; const SECOND = 1000; @@ -122,14 +119,6 @@ export const TENANT_OVERVIEW_TABLES_SETTINGS = { dynamicRender: false, } as const; -export const DEFAULT_QUERY_SETTINGS = { - queryMode: QUERY_MODES.query, - transactionMode: TRANSACTION_MODES.implicit, - timeout: '60', - statisticsMode: STATISTICS_MODES.none, - tracingLevel: TRACING_LEVELS.detailed, -} satisfies QuerySettings; - export const QUERY_EXECUTION_SETTINGS_KEY = 'queryExecutionSettings'; export const LAST_QUERY_EXECUTION_SETTINGS_KEY = 'last_query_execution_settings'; export const QUERY_SETTINGS_BANNER_LAST_CLOSED_KEY = 'querySettingsBannerLastClosed'; diff --git a/src/utils/hooks/useChangedQuerySettings.ts b/src/utils/hooks/useChangedQuerySettings.ts index 869fc0814..b6e05d2e2 100644 --- a/src/utils/hooks/useChangedQuerySettings.ts +++ b/src/utils/hooks/useChangedQuerySettings.ts @@ -1,10 +1,7 @@ import getChangedQueryExecutionSettings from '../../containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettings'; import getChangedQueryExecutionSettingsDescription from '../../containers/Tenant/Query/QueryEditorControls/utils/getChangedQueryExecutionSettingsDescription'; -import { - DEFAULT_QUERY_SETTINGS, - QUERY_SETTINGS_BANNER_LAST_CLOSED_KEY, - WEEK_IN_SECONDS, -} from '../constants'; +import {QUERY_SETTINGS_BANNER_LAST_CLOSED_KEY, WEEK_IN_SECONDS} from '../constants'; +import {DEFAULT_QUERY_SETTINGS} from '../query'; import {useLastQueryExecutionSettings} from './useLastQueryExecutionSettings'; import {useQueryExecutionSettings} from './useQueryExecutionSettings'; diff --git a/src/utils/hooks/useLastQueryExecutionSettings.ts b/src/utils/hooks/useLastQueryExecutionSettings.ts index 01a80614c..b69e53794 100644 --- a/src/utils/hooks/useLastQueryExecutionSettings.ts +++ b/src/utils/hooks/useLastQueryExecutionSettings.ts @@ -1,5 +1,6 @@ import type {QuerySettings} from '../../types/store/query'; import {LAST_QUERY_EXECUTION_SETTINGS_KEY} from '../constants'; +import {querySettingsValidationSchema} from '../query'; import {useSetting} from './useSetting'; @@ -7,16 +8,13 @@ export const useLastQueryExecutionSettings = () => { const [lastStorageSettings, setLastSettings] = useSetting( LAST_QUERY_EXECUTION_SETTINGS_KEY, ); + let lastSettings: QuerySettings | undefined; - const lastSettings: QuerySettings | undefined = lastStorageSettings - ? { - transactionMode: lastStorageSettings.transactionMode, - queryMode: lastStorageSettings.queryMode, - statisticsMode: lastStorageSettings.statisticsMode, - tracingLevel: lastStorageSettings.tracingLevel, - timeout: lastStorageSettings.timeout, - } - : undefined; + try { + lastSettings = querySettingsValidationSchema.parse(lastStorageSettings); + } catch (error) { + lastSettings = undefined; + } return [lastSettings, setLastSettings] as const; }; diff --git a/src/utils/hooks/useQueryExecutionSettings.ts b/src/utils/hooks/useQueryExecutionSettings.ts index 1325b67de..4b4dce6c2 100644 --- a/src/utils/hooks/useQueryExecutionSettings.ts +++ b/src/utils/hooks/useQueryExecutionSettings.ts @@ -1,6 +1,7 @@ import {useTracingLevelOptionAvailable} from '../../store/reducers/capabilities/hooks'; import type {QuerySettings} from '../../types/store/query'; -import {DEFAULT_QUERY_SETTINGS, QUERY_EXECUTION_SETTINGS_KEY} from '../constants'; +import {QUERY_EXECUTION_SETTINGS_KEY} from '../constants'; +import {DEFAULT_QUERY_SETTINGS, querySettingsRestoreSchema} from '../query'; import {useSetting} from './useSetting'; @@ -8,13 +9,12 @@ export const useQueryExecutionSettings = () => { const enableTracingLevel = useTracingLevelOptionAvailable(); const [storageSettings, setSettings] = useSetting(QUERY_EXECUTION_SETTINGS_KEY); + const validatedSettings = querySettingsRestoreSchema.parse(storageSettings); + const settings: QuerySettings = { - queryMode: storageSettings.queryMode ?? DEFAULT_QUERY_SETTINGS.queryMode, - timeout: storageSettings.timeout ?? DEFAULT_QUERY_SETTINGS.timeout, - statisticsMode: storageSettings.statisticsMode ?? DEFAULT_QUERY_SETTINGS.statisticsMode, - transactionMode: storageSettings.transactionMode ?? DEFAULT_QUERY_SETTINGS.transactionMode, + ...validatedSettings, tracingLevel: enableTracingLevel - ? storageSettings.tracingLevel + ? validatedSettings.tracingLevel : DEFAULT_QUERY_SETTINGS.tracingLevel, }; diff --git a/src/utils/query.ts b/src/utils/query.ts index 307110fdf..4da0f4044 100644 --- a/src/utils/query.ts +++ b/src/utils/query.ts @@ -1,3 +1,5 @@ +import {z} from 'zod'; + import {YQLType} from '../types'; import type { AnyExecuteResponse, @@ -331,3 +333,48 @@ export const parseQueryErrorToString = (error: unknown) => { return parsedError?.error?.message; }; + +export const DEFAULT_QUERY_SETTINGS = { + queryMode: QUERY_MODES.query, + transactionMode: TRANSACTION_MODES.implicit, + timeout: 60, + limitRows: 10000, + statisticsMode: STATISTICS_MODES.none, + tracingLevel: TRACING_LEVELS.detailed, +}; + +export const queryModeSchema = z.nativeEnum(QUERY_MODES); +export const transactionModeSchema = z.nativeEnum(TRANSACTION_MODES); +export const statisticsModeSchema = z.nativeEnum(STATISTICS_MODES); +export const tracingLevelSchema = z.nativeEnum(TRACING_LEVELS); +export const querySettingsValidationSchema = z.object({ + timeout: z.preprocess( + (val) => (val === '' ? undefined : val), + z.coerce.number().positive().or(z.undefined()), + ), + limitRows: z.preprocess( + (val) => (val === '' ? undefined : val), + z.coerce.number().gt(0).lte(10_000).or(z.undefined()), + ), + queryMode: queryModeSchema, + transactionMode: transactionModeSchema, + statisticsMode: statisticsModeSchema, + tracingLevel: tracingLevelSchema, +}); + +export const querySettingsRestoreSchema = z + .object({ + timeout: z.preprocess( + (val) => (val === '' ? undefined : val), + z.coerce.number().positive().optional().catch(DEFAULT_QUERY_SETTINGS.timeout), + ), + limitRows: z.preprocess( + (val) => (val === '' ? undefined : val), + z.coerce.number().gt(0).lte(10_000).optional().catch(DEFAULT_QUERY_SETTINGS.limitRows), + ), + queryMode: queryModeSchema.catch(DEFAULT_QUERY_SETTINGS.queryMode), + transactionMode: transactionModeSchema.catch(DEFAULT_QUERY_SETTINGS.transactionMode), + statisticsMode: statisticsModeSchema.catch(DEFAULT_QUERY_SETTINGS.statisticsMode), + tracingLevel: tracingLevelSchema.catch(DEFAULT_QUERY_SETTINGS.tracingLevel), + }) + .catch(DEFAULT_QUERY_SETTINGS); diff --git a/tests/suites/tenant/queryEditor/constants.ts b/tests/suites/tenant/queryEditor/constants.ts index 3238b159c..be9ca373c 100644 --- a/tests/suites/tenant/queryEditor/constants.ts +++ b/tests/suites/tenant/queryEditor/constants.ts @@ -1,32 +1,7 @@ // Long running query for tests // May cause Memory exceed on real database -export const longRunningQuery = ` -PRAGMA TablePathPrefix(""); +const simpleQuery = 'SELECT 1;'; -SELECT COUNT(*) AS total_count -FROM ( - SELECT 1 AS dummy - FROM - (SELECT 1 AS d UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL - SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t1 - CROSS JOIN - (SELECT 1 AS d UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL - SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t2 - CROSS JOIN - (SELECT 1 AS d UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL - SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t3 - CROSS JOIN - (SELECT 1 AS d UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL - SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t4 - CROSS JOIN - (SELECT 1 AS d UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL - SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t5 - CROSS JOIN - (SELECT 1 AS d UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL - SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t6 - CROSS JOIN - (SELECT 1 AS d UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL - SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t7 -) AS large_table - `; +// 400 is pretty enough +export const longRunningQuery = new Array(400).fill(simpleQuery).join('');