Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe('getChangedQueryExecutionSettings', () => {
statisticsMode: STATISTICS_MODES.basic,
tracingLevel: TRACING_LEVELS.basic,
pragmas: 'PRAGMA TestPragma;',
resourcePool: DEFAULT_QUERY_SETTINGS.resourcePool,
};
const result = getChangedQueryExecutionSettings(currentSettings, DEFAULT_QUERY_SETTINGS);
expect(result).toEqual([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ describe('getChangedQueryExecutionSettingsDescription', () => {
statisticsMode: STATISTICS_MODES.profile,
tracingLevel: TRACING_LEVELS.diagnostic,
pragmas: 'PRAGMA TestPragma;',
resourcePool: DEFAULT_QUERY_SETTINGS.resourcePool,
};

const result = getChangedQueryExecutionSettingsDescription({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {zodResolver} from '@hookform/resolvers/zod';
import {Controller, useForm} from 'react-hook-form';

import {useTracingLevelOptionAvailable} from '../../../../store/reducers/capabilities/hooks';
import {queryApi} from '../../../../store/reducers/query/query';
import {
selectQueryAction,
setQueryAction,
Expand All @@ -19,7 +20,13 @@ import {
useTypedDispatch,
useTypedSelector,
} from '../../../../utils/hooks';
import {QUERY_MODES, querySettingsValidationSchema} from '../../../../utils/query';
import type {ResourcePoolValue} from '../../../../utils/query';
import {
QUERY_MODES,
RESOURCE_POOL_NO_OVERRIDE_VALUE,
querySettingsValidationSchema,
} from '../../../../utils/query';
import {useCurrentSchema} from '../../TenantContext';

import {QuerySettingsSelect} from './QuerySettingsSelect';
import {QuerySettingsTimeout} from './QuerySettingsTimeout';
Expand Down Expand Up @@ -86,10 +93,49 @@ function QuerySettingsForm({initialValues, onSubmit, onClose}: QuerySettingsForm
const [useShowPlanToSvg] = useSetting<boolean>(SETTING_KEYS.USE_SHOW_PLAN_SVG);
const enableTracingLevel = useTracingLevelOptionAvailable();
const [isQueryStreamingEnabled] = useQueryStreamingSetting();
const {database} = useCurrentSchema();
const {data: resourcePools = [], isLoading: isResourcePoolsLoading} =
queryApi.useGetResourcePoolsQuery(
{database},
{
skip: !database,
},
);

const resourcePoolOptions = React.useMemo(
() => [
{
value: RESOURCE_POOL_NO_OVERRIDE_VALUE,
content: i18n('form.resource-pool.no-override'),
text: i18n('form.resource-pool.no-override'),
},
...resourcePools.map((name) => ({
value: name,
content: name,
text: name,
})),
],
[resourcePools],
);

const timeout = watch('timeout');
const resourcePool = watch('resourcePool');
const queryMode = watch('queryMode');

React.useEffect(() => {
if (isResourcePoolsLoading || !resourcePools.length) {
return;
}

if (!resourcePool || resourcePool === RESOURCE_POOL_NO_OVERRIDE_VALUE) {
return;
}

if (!resourcePools.includes(resourcePool)) {
setValue('resourcePool', RESOURCE_POOL_NO_OVERRIDE_VALUE);
}
}, [isResourcePoolsLoading, resourcePools, resourcePool, setValue]);

return (
<form onSubmit={handleSubmit(onSubmit)}>
<Dialog.Body className={b('dialog-body')}>
Expand All @@ -113,13 +159,44 @@ function QuerySettingsForm({initialValues, onSubmit, onClose}: QuerySettingsForm
} else if (mode === 'query') {
setValue('timeout', null);
}

if (mode === QUERY_MODES.pg) {
setValue(
'resourcePool',
RESOURCE_POOL_NO_OVERRIDE_VALUE,
);
}
}}
settingOptions={QUERY_SETTINGS_FIELD_SETTINGS.queryMode.options}
/>
)}
/>
</div>
</Flex>
<Flex direction="row" alignItems="flex-start" className={b('dialog-row')}>
<label htmlFor="resourcePool" className={b('field-title')}>
{QUERY_SETTINGS_FIELD_SETTINGS.resourcePool.title}
</label>
<div className={b('control-wrapper', {resourcePool: true})}>
<Controller
name="resourcePool"
control={control}
render={({field}) => (
<QuerySettingsSelect<ResourcePoolValue>
id="resourcePool"
setting={field.value ?? RESOURCE_POOL_NO_OVERRIDE_VALUE}
disabled={
isResourcePoolsLoading ||
!resourcePools.length ||
queryMode === QUERY_MODES.pg
}
onUpdateSetting={(value) => field.onChange(value)}
settingOptions={resourcePoolOptions}
/>
)}
/>
</div>
</Flex>
{enableTracingLevel && (
<Flex direction="row" alignItems="flex-start" className={b('dialog-row')}>
<label htmlFor="tracingLevel" className={b('field-title')}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
TransactionMode,
} from '../../../../types/store/query';
import {cn} from '../../../../utils/cn';
import type {ResourcePoolValue} from '../../../../utils/query';

import i18n from './i18n';

Expand All @@ -19,7 +20,7 @@ export const getOptionHeight = () => -1;

const b = cn('ydb-query-settings-select');

type SelectType = QueryMode | TransactionMode | StatisticsMode | TracingLevel;
type SelectType = QueryMode | TransactionMode | StatisticsMode | TracingLevel | ResourcePoolValue;
type QuerySettingSelectOption<T> = SelectOption<T> & {isDefault?: boolean};

interface QuerySettingsSelectProps<T extends SelectType> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,7 @@ export const QUERY_SETTINGS_FIELD_SETTINGS = {
pragmas: {
title: formI18n('form.pragmas'),
},
resourcePool: {
title: formI18n('form.resource-pool'),
},
} as const;
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"form.output.chunk.max.size": "Output chunk max size",
"form.output.chunk.max.size.bytes": "bytes",
"form.pragmas": "Pragmas",
"form.resource-pool": "Resource pool",
"form.resource-pool.no-override": "No pool override",
"button-done": "Save",
"tooltip_plan-to-svg-statistics": "Statistics option is set to \"Full\" due to the enabled \"Execution plan\" experiment.\n To disable it, go to the \"Experiments\" section in the user settings.",
"button-cancel": "Cancel",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"form.output.chunk.max.size": "Максимальный размер чанка",
"form.output.chunk.max.size.bytes": "байт",
"form.pragmas": "Прагмы",
"form.resource-pool": "Пул ресурсов",
"form.resource-pool.no-override": "Без переопределения пула",
"tooltip_plan-to-svg-statistics": "Опция статистики установлена в значение \"Full\" из-за включенного эксперимента \"Execution plan\".\n Чтобы отключить его, перейдите в раздел \"Experiments\" в настройках пользователя.",
"button-done": "Готово",
"button-cancel": "Отменить",
Expand Down
60 changes: 58 additions & 2 deletions src/store/reducers/query/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@ import {TracingLevelNumber} from '../../../types/api/query';
import type {QueryAction, QueryRequestParams, QuerySettings} from '../../../types/store/query';
import type {StreamDataChunk} from '../../../types/store/streaming';
import {loadFromSessionStorage, saveToSessionStorage} from '../../../utils';
import {QUERY_EDITOR_CURRENT_QUERY_KEY, QUERY_EDITOR_DIRTY_KEY} from '../../../utils/constants';
import {isQueryErrorResponse} from '../../../utils/query';
import {
QUERY_EDITOR_CURRENT_QUERY_KEY,
QUERY_EDITOR_DIRTY_KEY,
QUERY_TECHNICAL_MARK,
} from '../../../utils/constants';
import {
RESOURCE_POOL_NO_OVERRIDE_VALUE,
isQueryErrorResponse,
parseQueryAPIResponse,
} from '../../../utils/query';
import {isNumeric} from '../../../utils/utils';
import type {RootState} from '../../defaultStore';
import {api} from '../api';
Expand Down Expand Up @@ -119,6 +127,15 @@ export const {
selectResultTab,
} = slice.selectors;

const getResourcePoolsQueryText = () => {
return `${QUERY_TECHNICAL_MARK}
SELECT
Name
FROM \`.sys/resource_pools\`
ORDER BY Name
`;
};

interface SendQueryParams extends QueryRequestParams {
actionType?: QueryAction;
queryId: string;
Expand Down Expand Up @@ -196,6 +213,11 @@ export const queryApi = api.injectEndpoints({
: undefined,
concurrent_results: DEFAULT_CONCURRENT_RESULTS || undefined,
base64,
resource_pool:
querySettings.resourcePool === RESOURCE_POOL_NO_OVERRIDE_VALUE ||
!querySettings.resourcePool
? undefined
: querySettings.resourcePool,
},
{
signal,
Expand Down Expand Up @@ -300,6 +322,11 @@ export const queryApi = api.injectEndpoints({
: undefined,
query_id: queryId,
base64,
resource_pool:
querySettings.resourcePool === RESOURCE_POOL_NO_OVERRIDE_VALUE ||
!querySettings.resourcePool
? undefined
: querySettings.resourcePool,
},
{signal},
);
Expand Down Expand Up @@ -366,6 +393,35 @@ export const queryApi = api.injectEndpoints({
}
},
}),
getResourcePools: build.query<string[], {database: string}>({
queryFn: async ({database}, {signal}) => {
try {
const response = await window.api.viewer.sendQuery(
{
query: getResourcePoolsQueryText(),
database,
action: 'execute-query',
internal_call: true,
},
{signal, withRetries: true},
);

if (isQueryErrorResponse(response)) {
return {error: response};
}

const data = parseQueryAPIResponse(response);
const rows = data.resultSets?.[0]?.result || [];
const pools = rows
.map((row) => row && row.Name)
.filter((name): name is string => Boolean(name));

return {data: pools};
} catch (error) {
return {error};
}
},
}),
}),
overrideExisting: 'throw',
});
1 change: 1 addition & 0 deletions src/types/api/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ export interface SendQueryParams<Action extends Actions> {
limit_rows?: number;
internal_call?: boolean;
base64?: boolean;
resource_pool?: string;
}

export interface StreamQueryParams<Action extends Actions> extends SendQueryParams<Action> {
Expand Down
8 changes: 8 additions & 0 deletions src/utils/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ export const parseQueryErrorToString = (error: unknown) => {

export const defaultPragma = 'PRAGMA OrderedColumns;';

// Special marker meaning "do not override resource pool in request params"
export const RESOURCE_POOL_NO_OVERRIDE_VALUE = '__no_pool_override__';

export type ResourcePoolValue = typeof RESOURCE_POOL_NO_OVERRIDE_VALUE | string;

export const DEFAULT_QUERY_SETTINGS = {
queryMode: QUERY_MODES.query,
transactionMode: TRANSACTION_MODES.implicit,
Expand All @@ -311,6 +316,7 @@ export const DEFAULT_QUERY_SETTINGS = {
statisticsMode: STATISTICS_MODES.none,
tracingLevel: TRACING_LEVELS.off,
pragmas: defaultPragma,
resourcePool: RESOURCE_POOL_NO_OVERRIDE_VALUE,
};

export const queryModeSchema = z.nativeEnum(QUERY_MODES);
Expand Down Expand Up @@ -339,6 +345,7 @@ export const querySettingsValidationSchema = z.object({
statisticsMode: statisticsModeSchema,
tracingLevel: tracingLevelSchema,
pragmas: z.string(),
resourcePool: z.string(),
});

export const querySettingsRestoreSchema = z
Expand All @@ -360,5 +367,6 @@ export const querySettingsRestoreSchema = z
statisticsMode: statisticsModeSchema.catch(DEFAULT_QUERY_SETTINGS.statisticsMode),
tracingLevel: tracingLevelSchema.catch(DEFAULT_QUERY_SETTINGS.tracingLevel),
pragmas: z.string().catch(DEFAULT_QUERY_SETTINGS.pragmas),
resourcePool: z.string().catch(DEFAULT_QUERY_SETTINGS.resourcePool),
})
.catch(DEFAULT_QUERY_SETTINGS);
44 changes: 44 additions & 0 deletions tests/suites/tenant/queryEditor/models/SettingsDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class SettingsDialog {
private timeoutLabel: Locator;

private queryModeSelect: Locator;
private resourcePoolSelect: Locator;
private transactionModeSelect: Locator;
private statisticsModeSelect: Locator;
private statisticsModeTooltip: Locator;
Expand All @@ -47,6 +48,9 @@ export class SettingsDialog {
this.queryModeSelect = this.dialog.locator(
'.ydb-query-settings-dialog__control-wrapper_queryMode',
);
this.resourcePoolSelect = this.dialog.locator(
'.ydb-query-settings-dialog__control-wrapper_resourcePool',
);
this.transactionModeSelect = this.dialog.locator(
'.ydb-query-settings-dialog__control-wrapper_transactionMode',
);
Expand All @@ -66,6 +70,46 @@ export class SettingsDialog {
await this.page.waitForTimeout(1000);
}

async getResourcePoolOptions() {
await this.resourcePoolSelect.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
await this.resourcePoolSelect.click();
await this.selectPopup.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});

const items = this.selectPopup.locator('.ydb-query-settings-select__item-title');
const count = await items.count();
const options: string[] = [];

for (let index = 0; index < count; index += 1) {
const text = await items.nth(index).textContent();
if (text) {
options.push(text.trim());
}
}

return options;
}

async changeResourcePool(label: string) {
await this.resourcePoolSelect.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
await this.resourcePoolSelect.click();
await this.selectPopup.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
await this.selectPopup.getByText(label, {exact: true}).click();
await this.page.waitForTimeout(1000);
}

async getResourcePoolValue() {
await this.resourcePoolSelect.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
const selectedText = await this.resourcePoolSelect
.locator('.g-select-control__option-text')
.textContent();
return selectedText?.trim() || '';
}

async isResourcePoolDisabled() {
await this.resourcePoolSelect.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
return this.resourcePoolSelect.locator('.g-select-control_disabled').isVisible();
}

async changeTransactionMode(level: (typeof TRANSACTION_MODES)[keyof typeof TRANSACTION_MODES]) {
await this.transactionModeSelect.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
await this.transactionModeSelect.click();
Expand Down
Loading
Loading