Skip to content

Commit c198207

Browse files
committed
feat: snippets for table (under tree dots in navigation tree)
1 parent 830c0a5 commit c198207

File tree

7 files changed

+179
-70
lines changed

7 files changed

+179
-70
lines changed

src/containers/Tenant/Schema/SchemaViewer/SchemaViewer.tsx

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
import React from 'react';
22

3-
import {skipToken} from '@reduxjs/toolkit/query';
4-
53
import {ResizeableDataTable} from '../../../../components/ResizeableDataTable/ResizeableDataTable';
64
import {TableSkeleton} from '../../../../components/TableSkeleton/TableSkeleton';
7-
import {overviewApi} from '../../../../store/reducers/overview/overview';
8-
import {viewSchemaApi} from '../../../../store/reducers/viewSchema/viewSchema';
95
import type {EPathType} from '../../../../types/api/schema';
106
import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
11-
import {useAutoRefreshInterval} from '../../../../utils/hooks';
7+
import {useTableData} from '../../../../utils/hooks';
128
import {
139
isColumnEntityType,
1410
isExternalTableType,
@@ -24,7 +20,6 @@ import {
2420
getRowTableColumns,
2521
getViewColumns,
2622
} from './columns';
27-
import {prepareSchemaData, prepareViewSchema} from './prepareData';
2823
import {b} from './shared';
2924

3025
import './SchemaViewer.scss';
@@ -37,31 +32,11 @@ interface SchemaViewerProps {
3732
}
3833

3934
export const SchemaViewer = ({type, path, tenantName, extended = false}: SchemaViewerProps) => {
40-
const [autoRefreshInterval] = useAutoRefreshInterval();
41-
const {currentData, isLoading: loading} = overviewApi.useGetOverviewQuery(
42-
{
43-
paths: [path],
44-
database: tenantName,
45-
},
46-
{
47-
pollingInterval: autoRefreshInterval,
48-
},
49-
);
50-
51-
const {data: schemaData} = currentData ?? {};
52-
53-
const viewSchemaRequestParams = isViewType(type) ? {path, database: tenantName} : skipToken;
54-
55-
const {data: viewColumnsData, isLoading: isViewSchemaLoading} =
56-
viewSchemaApi.useGetViewSchemaQuery(viewSchemaRequestParams);
57-
58-
const tableData = React.useMemo(() => {
59-
if (isViewType(type)) {
60-
return prepareViewSchema(viewColumnsData);
61-
}
62-
63-
return prepareSchemaData(type, schemaData);
64-
}, [schemaData, type, viewColumnsData]);
35+
const {tableData, isOverviewLoading, isViewSchemaLoading} = useTableData({
36+
type,
37+
path,
38+
tenantName,
39+
});
6540

6641
const hasAutoIncrement = React.useMemo(() => {
6742
return tableData.some((i) => i.autoIncrement);
@@ -88,7 +63,7 @@ export const SchemaViewer = ({type, path, tenantName, extended = false}: SchemaV
8863
return [];
8964
}, [type, extended, hasAutoIncrement, hasDefaultValue]);
9065

91-
if (loading || isViewSchemaLoading) {
66+
if (isOverviewLoading || isViewSchemaLoading) {
9267
return <TableSkeleton />;
9368
}
9469

src/containers/Tenant/utils/schema.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ const pathTypeToNodeType: Record<EPathType, NavigationTreeNodeType | undefined>
4141
[EPathType.EPathTypeReplication]: 'async_replication',
4242
};
4343

44+
export const nodeTableTypeToPathType: Partial<Record<NavigationTreeNodeType, EPathType>> = {
45+
table: EPathType.EPathTypeTable,
46+
index: EPathType.EPathTypeTableIndex,
47+
column_table: EPathType.EPathTypeColumnTable,
48+
external_table: EPathType.EPathTypeExternalTable,
49+
view: EPathType.EPathTypeView,
50+
};
51+
4452
export const mapPathTypeToNavigationTreeType = (
4553
type: EPathType = EPathType.EPathTypeDir,
4654
subType?: EPathSubType,

src/containers/Tenant/utils/schemaActions.ts

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import copy from 'copy-to-clipboard';
22
import type {NavigationTreeNodeType, NavigationTreeProps} from 'ydb-ui-components';
33

4+
import type {AppDispatch} from '../../../store';
45
import {changeUserInput} from '../../../store/reducers/executeQuery';
56
import {TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID} from '../../../store/reducers/tenant/constants';
67
import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
78
import type {QueryMode, QuerySettings} from '../../../types/store/query';
89
import createToast from '../../../utils/createToast';
10+
import {getTableDataPromise} from '../../../utils/hooks';
911
import {transformPath} from '../ObjectSummary/transformPath';
1012
import i18n from '../i18n';
1113

12-
import type {SchemaQueryParams} from './schemaQueryTemplates';
14+
import {nodeTableTypeToPathType} from './schema';
15+
import type {TemplateFn} from './schemaQueryTemplates';
1316
import {
1417
addTableIndex,
1518
alterAsyncReplicationTemplate,
@@ -36,52 +39,74 @@ interface ActionsAdditionalEffects {
3639
showCreateDirectoryDialog?: (path: string) => void;
3740
}
3841

42+
interface AdditionalInputQueryOptions {
43+
mode?: QueryMode;
44+
withTableData?: boolean;
45+
}
46+
47+
interface BindActionParams {
48+
tenantName: string;
49+
type: NavigationTreeNodeType;
50+
path: string;
51+
relativePath: string;
52+
}
53+
3954
const bindActions = (
40-
schemaQueryParams: SchemaQueryParams,
41-
dispatch: React.Dispatch<any>,
55+
params: BindActionParams,
56+
dispatch: AppDispatch,
4257
additionalEffects: ActionsAdditionalEffects,
4358
) => {
4459
const {setActivePath, updateQueryExecutionSettings, showCreateDirectoryDialog} =
4560
additionalEffects;
4661

47-
const inputQuery = (tmpl: (params?: SchemaQueryParams) => string, mode?: QueryMode) => () => {
48-
if (mode) {
49-
updateQueryExecutionSettings({queryMode: mode});
62+
const inputQuery = (tmpl: TemplateFn, options?: AdditionalInputQueryOptions) => () => {
63+
if (options?.mode) {
64+
updateQueryExecutionSettings({queryMode: options.mode});
5065
}
5166

52-
dispatch(changeUserInput({input: tmpl(schemaQueryParams)}));
67+
const pathType = nodeTableTypeToPathType[params.type];
68+
69+
const userInputDataPromise =
70+
options?.withTableData && pathType
71+
? getTableDataPromise(params.path, params.tenantName, pathType, dispatch)
72+
: Promise.resolve(undefined);
73+
74+
userInputDataPromise.then((tableData) => {
75+
dispatch(changeUserInput({input: tmpl({...params, tableData})}));
76+
});
77+
5378
dispatch(setTenantPage(TENANT_PAGES_IDS.query));
5479
dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
55-
setActivePath(schemaQueryParams.path);
80+
setActivePath(params.path);
5681
};
5782

5883
return {
5984
createDirectory: showCreateDirectoryDialog
6085
? () => {
61-
showCreateDirectoryDialog(schemaQueryParams.path);
86+
showCreateDirectoryDialog(params.path);
6287
}
6388
: undefined,
64-
createTable: inputQuery(createTableTemplate, 'script'),
65-
createColumnTable: inputQuery(createColumnTableTemplate, 'script'),
66-
createAsyncReplication: inputQuery(createAsyncReplicationTemplate, 'script'),
67-
alterAsyncReplication: inputQuery(alterAsyncReplicationTemplate, 'script'),
68-
dropAsyncReplication: inputQuery(dropAsyncReplicationTemplate, 'script'),
69-
alterTable: inputQuery(alterTableTemplate, 'script'),
70-
selectQuery: inputQuery(selectQueryTemplate),
71-
upsertQuery: inputQuery(upsertQueryTemplate),
72-
createExternalTable: inputQuery(createExternalTableTemplate, 'script'),
73-
dropExternalTable: inputQuery(dropExternalTableTemplate, 'script'),
74-
selectQueryFromExternalTable: inputQuery(selectQueryTemplate, 'query'),
75-
createTopic: inputQuery(createTopicTemplate, 'script'),
76-
alterTopic: inputQuery(alterTopicTemplate, 'script'),
77-
dropTopic: inputQuery(dropTopicTemplate, 'script'),
78-
createView: inputQuery(createViewTemplate, 'script'),
79-
dropView: inputQuery(dropViewTemplate, 'script'),
80-
dropIndex: inputQuery(dropTableIndex, 'script'),
81-
addTableIndex: inputQuery(addTableIndex, 'script'),
89+
createTable: inputQuery(createTableTemplate, {mode: 'script'}),
90+
createColumnTable: inputQuery(createColumnTableTemplate, {mode: 'script'}),
91+
createAsyncReplication: inputQuery(createAsyncReplicationTemplate, {mode: 'script'}),
92+
alterAsyncReplication: inputQuery(alterAsyncReplicationTemplate, {mode: 'script'}),
93+
dropAsyncReplication: inputQuery(dropAsyncReplicationTemplate, {mode: 'script'}),
94+
alterTable: inputQuery(alterTableTemplate, {mode: 'script'}),
95+
selectQuery: inputQuery(selectQueryTemplate, {withTableData: true}),
96+
upsertQuery: inputQuery(upsertQueryTemplate, {withTableData: true}),
97+
createExternalTable: inputQuery(createExternalTableTemplate, {mode: 'script'}),
98+
dropExternalTable: inputQuery(dropExternalTableTemplate, {mode: 'script'}),
99+
selectQueryFromExternalTable: inputQuery(selectQueryTemplate, {mode: 'query'}),
100+
createTopic: inputQuery(createTopicTemplate, {mode: 'script'}),
101+
alterTopic: inputQuery(alterTopicTemplate, {mode: 'script'}),
102+
dropTopic: inputQuery(dropTopicTemplate, {mode: 'script'}),
103+
createView: inputQuery(createViewTemplate, {mode: 'script'}),
104+
dropView: inputQuery(dropViewTemplate, {mode: 'script'}),
105+
dropIndex: inputQuery(dropTableIndex, {mode: 'script'}),
106+
addTableIndex: inputQuery(addTableIndex, {mode: 'script'}),
82107
copyPath: () => {
83108
try {
84-
copy(schemaQueryParams.relativePath);
109+
copy(params.relativePath);
85110
createToast({
86111
name: 'Copied',
87112
title: i18n('actions.copied'),
@@ -101,10 +126,14 @@ const bindActions = (
101126
type ActionsSet = ReturnType<Required<NavigationTreeProps>['getActions']>;
102127

103128
export const getActions =
104-
(dispatch: React.Dispatch<any>, additionalEffects: ActionsAdditionalEffects, rootPath = '') =>
129+
(dispatch: AppDispatch, additionalEffects: ActionsAdditionalEffects, rootPath = '') =>
105130
(path: string, type: NavigationTreeNodeType) => {
106131
const relativePath = transformPath(path, rootPath);
107-
const actions = bindActions({path, relativePath}, dispatch, additionalEffects);
132+
const actions = bindActions(
133+
{path, relativePath, tenantName: rootPath, type},
134+
dispatch,
135+
additionalEffects,
136+
);
108137
const copyItem = {text: i18n('actions.copyPath'), action: actions.copyPath};
109138

110139
const DIR_SET: ActionsSet = [

src/containers/Tenant/utils/schemaQueryTemplates.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
import type {SchemaData} from '../Schema/SchemaViewer/types';
2+
13
export interface SchemaQueryParams {
24
path: string;
35
relativePath: string;
6+
tableData?: SchemaData[];
47
}
58

9+
export type TemplateFn = (params?: SchemaQueryParams) => string;
10+
611
export const createTableTemplate = (params?: SchemaQueryParams) => {
712
return `-- docs: https://ydb.tech/en/docs/yql/reference/syntax/create_table
813
CREATE TABLE \`${params?.relativePath || '$path'}/ydb_row_table\` (
@@ -67,13 +72,18 @@ export const alterTableTemplate = (params?: SchemaQueryParams) => {
6772
ADD COLUMN numeric_column Int32;`;
6873
};
6974
export const selectQueryTemplate = (params?: SchemaQueryParams) => {
70-
return `SELECT *
75+
const columns = params?.tableData?.map((column) => '`' + column.name + '`').join(', ') || '*';
76+
77+
return `SELECT ${columns}
7178
FROM \`${params?.relativePath || '$path'}\`
7279
LIMIT 10;`;
7380
};
7481
export const upsertQueryTemplate = (params?: SchemaQueryParams) => {
82+
const columns =
83+
params?.tableData?.map((column) => `\`${column.name}\``).join(', ') || `\`id\`, \`name\``;
84+
7585
return `UPSERT INTO \`${params?.relativePath || '$path'}\`
76-
( \`id\`, \`name\` )
86+
( ${columns} )
7787
VALUES ( );`;
7888
};
7989

src/utils/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export * from './useTableSort';
66
export * from './useSearchQuery';
77
export * from './useAutoRefreshInterval';
88
export * from './useEventHandler';
9+
export * from './useTableData';

src/utils/hooks/useTableData.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import React from 'react';
2+
3+
import {skipToken} from '@reduxjs/toolkit/query';
4+
5+
import {isViewType} from '../../containers/Tenant/utils/schema';
6+
import type {AppDispatch} from '../../store';
7+
import {overviewApi} from '../../store/reducers/overview/overview';
8+
import {viewSchemaApi} from '../../store/reducers/viewSchema/viewSchema';
9+
import type {EPathType} from '../../types/api/schema';
10+
import {prepareSchemaData, prepareViewSchema} from '../prepareTableData';
11+
12+
import {useAutoRefreshInterval} from './useAutoRefreshInterval';
13+
14+
interface UseTableDataProps {
15+
type?: EPathType;
16+
path: string;
17+
tenantName: string;
18+
}
19+
20+
const getOverviewData = async (path: string, tenantName: string, dispatch: AppDispatch) => {
21+
const {data: schemaData} = await dispatch(
22+
overviewApi.endpoints.getOverview.initiate({
23+
paths: [path],
24+
database: tenantName,
25+
}),
26+
);
27+
return schemaData;
28+
};
29+
30+
const getViewSchemaData = async (path: string, tenantName: string, dispatch: AppDispatch) => {
31+
const {data: viewColumnsData} = await dispatch(
32+
viewSchemaApi.endpoints.getViewSchema.initiate({path, database: tenantName}),
33+
);
34+
return viewColumnsData;
35+
};
36+
37+
export const getTableDataPromise = async (
38+
path: string,
39+
tenantName: string,
40+
type: EPathType,
41+
dispatch: AppDispatch,
42+
) => {
43+
const schemaData = await getOverviewData(path, tenantName, dispatch);
44+
const viewColumnsData = isViewType(type)
45+
? await getViewSchemaData(path, tenantName, dispatch)
46+
: null;
47+
48+
return isViewType(type) && viewColumnsData
49+
? prepareViewSchema(viewColumnsData)
50+
: prepareSchemaData(type, schemaData?.data);
51+
};
52+
53+
export const useTableData = ({type, path, tenantName}: UseTableDataProps) => {
54+
const [autoRefreshInterval] = useAutoRefreshInterval();
55+
56+
const overviewQuery = overviewApi.useGetOverviewQuery(
57+
{
58+
paths: [path],
59+
database: tenantName,
60+
},
61+
{
62+
pollingInterval: autoRefreshInterval,
63+
},
64+
);
65+
66+
const viewSchemaQuery = viewSchemaApi.useGetViewSchemaQuery(
67+
isViewType(type) ? {path, database: tenantName} : skipToken,
68+
);
69+
70+
const tableData = React.useMemo(() => {
71+
if (isViewType(type)) {
72+
return prepareViewSchema(viewSchemaQuery.data);
73+
}
74+
return prepareSchemaData(type, overviewQuery.currentData?.data);
75+
}, [overviewQuery.currentData?.data, type, viewSchemaQuery.data]);
76+
77+
return {
78+
tableData,
79+
isViewSchemaLoading: viewSchemaQuery.isLoading,
80+
isOverviewLoading: overviewQuery.isLoading,
81+
};
82+
};

src/containers/Tenant/Schema/SchemaViewer/prepareData.ts renamed to src/utils/prepareTableData.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1-
import type {ColumnType} from '../../../../types/api/query';
1+
import type {SchemaData} from '../containers/Tenant/Schema/SchemaViewer/types';
2+
import {
3+
isColumnEntityType,
4+
isExternalTableType,
5+
isRowTableType,
6+
} from '../containers/Tenant/utils/schema';
7+
import type {ColumnType} from '../types/api/query';
28
import type {
39
EPathType,
410
TColumnTableDescription,
511
TEvDescribeSchemeResult,
612
TExternalTableDescription,
713
TFamilyDescription,
814
TTableDescription,
9-
} from '../../../../types/api/schema';
10-
import {EColumnCodec} from '../../../../types/api/schema';
11-
import type {Nullable} from '../../../../utils/typecheckers';
12-
import {isColumnEntityType, isExternalTableType, isRowTableType} from '../../utils/schema';
15+
} from '../types/api/schema';
16+
import {EColumnCodec} from '../types/api/schema';
1317

14-
import type {SchemaData} from './types';
18+
import type {Nullable} from './typecheckers';
1519

1620
function formatColumnCodec(codec?: EColumnCodec) {
1721
if (!codec) {

0 commit comments

Comments
 (0)