Skip to content

Commit 5c6e9a2

Browse files
feat: enable explain-script parsing, remove deprecated code
BREAKING CHANGE: app no longer parses query responses from older ydb versions
1 parent 1a8366c commit 5c6e9a2

File tree

2 files changed

+50
-84
lines changed

2 files changed

+50
-84
lines changed

src/store/reducers/explainQuery.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type {
1111
import type {QueryRequestParams} from '../../types/store/query';
1212

1313
import {preparePlan} from '../../utils/prepareQueryExplain';
14-
import {parseQueryAPIExplainResponse} from '../../utils/query';
14+
import {parseQueryAPIExplainResponse, parseQueryExplainPlan} from '../../utils/query';
1515
import {parseQueryError} from '../../utils/error';
1616

1717
import {createRequestActionTypes, createApiRequest} from '../utils';
@@ -102,19 +102,19 @@ export const getExplainQuery = ({query, database}: QueryRequestParams) => {
102102
request: window.api.getExplainQuery(query, database),
103103
actions: GET_EXPLAIN_QUERY,
104104
dataHandler: (response): PreparedExplainResponse => {
105-
const {plan: result, ast} = parseQueryAPIExplainResponse(response);
105+
const {plan: rawPlan, ast} = parseQueryAPIExplainResponse(response);
106106

107-
if (!result) {
107+
if (!rawPlan) {
108108
return {ast};
109109
}
110110

111-
const {tables, meta, Plan} = result;
111+
const {tables, meta, Plan} = parseQueryExplainPlan(rawPlan);
112112

113113
if (supportedExplainQueryVersions.indexOf(meta.version) === -1) {
114114
// Do not prepare plan for not supported versions
115115
return {
116116
plan: {
117-
pristine: result,
117+
pristine: rawPlan,
118118
version: meta.version,
119119
},
120120
ast,
@@ -136,7 +136,7 @@ export const getExplainQuery = ({query, database}: QueryRequestParams) => {
136136
nodes,
137137
tables,
138138
version: meta.version,
139-
pristine: result,
139+
pristine: rawPlan,
140140
},
141141
ast,
142142
};

src/utils/query.ts

Lines changed: 44 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@ import {YQLType} from '../types';
22
import type {
33
AnyExecuteResponse,
44
AnyExplainResponse,
5-
AnyResponse,
6-
CommonFields,
7-
DeepExecuteResponse,
8-
DeprecatedExecuteResponsePlain,
9-
ExecuteClassicResponsePlain,
105
ExecuteModernResponse,
116
KeyValueRow,
7+
ScanPlan,
8+
ScriptPlan,
129
} from '../types/api/query';
1310
import type {IQueryResult} from '../types/store/query';
1411

@@ -49,6 +46,7 @@ export const getColumnType = (type: string) => {
4946
}
5047
};
5148

49+
/** parse response result field from ArrayRow to KeyValueRow */
5250
const parseExecuteModernResponse = (data: ExecuteModernResponse): IQueryResult => {
5351
const {result, columns, ...restData} = data;
5452

@@ -57,43 +55,17 @@ const parseExecuteModernResponse = (data: ExecuteModernResponse): IQueryResult =
5755
result &&
5856
columns &&
5957
result.map((row) => {
60-
return row.reduce((newRow: KeyValueRow, cellData, columnIndex) => {
58+
return row.reduce((newRow, cellData, columnIndex) => {
6159
const {name} = columns[columnIndex];
6260
newRow[name] = cellData;
6361
return newRow;
64-
}, {});
62+
}, {} as KeyValueRow);
6563
}),
6664
columns,
6765
...restData,
6866
};
6967
};
7068

71-
const parseDeprecatedExecuteResponseValue = (
72-
data?: DeprecatedExecuteResponsePlain | ExecuteClassicResponsePlain,
73-
): KeyValueRow[] | undefined => {
74-
if (!data) {
75-
return undefined;
76-
}
77-
78-
if (typeof data === 'string') {
79-
try {
80-
return JSON.parse(data);
81-
} catch (e) {
82-
return undefined;
83-
}
84-
}
85-
86-
if (Array.isArray(data)) {
87-
return data;
88-
}
89-
90-
// Plan is not a valid response in this case
91-
return undefined;
92-
};
93-
94-
const hasResult = (data: AnyExecuteResponse): data is DeepExecuteResponse =>
95-
Boolean(data && typeof data === 'object' && 'result' in data);
96-
9769
const isModern = (response: AnyExecuteResponse): response is ExecuteModernResponse =>
9870
Boolean(
9971
response &&
@@ -102,70 +74,64 @@ const isModern = (response: AnyExecuteResponse): response is ExecuteModernRespon
10274
Array.isArray((response as ExecuteModernResponse).columns),
10375
);
10476

105-
const hasCommonFields = (data: AnyResponse): data is CommonFields =>
106-
Boolean(
107-
data && typeof data === 'object' && ('ast' in data || 'plan' in data || 'stats' in data),
77+
type UnsupportedQueryResponseFormat =
78+
| Array<unknown>
79+
| string
80+
| null
81+
| undefined
82+
| {result: string | Record<string, unknown>};
83+
84+
const isUnsupportedType = (
85+
data: AnyExecuteResponse | AnyExplainResponse | UnsupportedQueryResponseFormat,
86+
): data is UnsupportedQueryResponseFormat => {
87+
return Boolean(
88+
!data ||
89+
typeof data !== 'object' ||
90+
Array.isArray(data) ||
91+
('result' in data && !Array.isArray(data.result)),
10892
);
93+
};
10994

110-
// complex logic because of the variety of possible responses
111-
// after all backends are updated to the latest version, it can be simplified
112-
export const parseQueryAPIExecuteResponse = (data: AnyExecuteResponse): IQueryResult => {
113-
if (!data) {
95+
export const parseQueryAPIExecuteResponse = (
96+
data: AnyExecuteResponse | UnsupportedQueryResponseFormat,
97+
): IQueryResult => {
98+
if (isUnsupportedType(data)) {
11499
return {};
115100
}
116-
117-
if (hasResult(data)) {
118-
if (isModern(data)) {
119-
return parseExecuteModernResponse(data);
120-
}
121-
122-
return {
123-
...data,
124-
result: parseDeprecatedExecuteResponseValue(data.result),
125-
};
126-
}
127-
128-
if (hasCommonFields(data)) {
129-
return data;
101+
if (isModern(data)) {
102+
return parseExecuteModernResponse(data);
130103
}
131104

132-
return {
133-
result: parseDeprecatedExecuteResponseValue(data),
134-
};
105+
return data;
135106
};
136107

137-
// complex logic because of the variety of possible responses
138-
// after all backends are updated to the latest version, it can be simplified
139-
export const parseQueryAPIExplainResponse = (data: AnyExplainResponse): IQueryResult => {
140-
if (!data) {
108+
export const parseQueryAPIExplainResponse = (
109+
data: AnyExplainResponse | UnsupportedQueryResponseFormat,
110+
): IQueryResult => {
111+
if (isUnsupportedType(data)) {
141112
return {};
142113
}
143114

144-
if ('ast' in data) {
145-
return data;
146-
}
115+
return data;
116+
};
147117

148-
if ('result' in data) {
149-
const {result, ...restData} = data;
118+
const isExplainScriptPlan = (plan: ScriptPlan | ScanPlan): plan is ScriptPlan =>
119+
Boolean(plan && 'queries' in plan);
150120

151-
if ('ast' in data.result) {
152-
return {
153-
ast: result.ast,
154-
...restData,
155-
};
121+
export const parseQueryExplainPlan = (plan: ScriptPlan | ScanPlan): ScanPlan => {
122+
if (isExplainScriptPlan(plan)) {
123+
if (!plan.queries || !plan.queries.length) {
124+
return {meta: plan.meta};
156125
}
157126

158127
return {
159-
plan: data.result,
160-
...restData,
128+
Plan: plan.queries[0].Plan,
129+
tables: plan.queries[0].tables,
130+
meta: plan.meta,
161131
};
162132
}
163133

164-
if (hasCommonFields(data)) {
165-
return data;
166-
}
167-
168-
return {plan: data};
134+
return plan;
169135
};
170136

171137
export const prepareQueryResponse = (data?: KeyValueRow[]) => {

0 commit comments

Comments
 (0)