This is an automated email from the ASF dual-hosted git repository.
vogievetsky pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new ee06137787 better native json error UX (#14155)
ee06137787 is described below
commit ee06137787af0b090fbee57d2b21d612fe8dbadd
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Tue Apr 25 10:30:42 2023 -0700
better native json error UX (#14155)
---
.../workbench-query/workbench-query-part.ts | 8 +++---
.../workbench-query/workbench-query.spec.ts | 33 ++++++++++++++++++++++
.../workbench-query/workbench-query.ts | 17 +++++++----
.../workbench-view/helper-query/helper-query.tsx | 23 +++++++++++++--
.../views/workbench-view/query-tab/query-tab.tsx | 19 ++++++++++++-
5 files changed, 86 insertions(+), 14 deletions(-)
diff --git
a/web-console/src/druid-models/workbench-query/workbench-query-part.ts
b/web-console/src/druid-models/workbench-query/workbench-query-part.ts
index 680a0780bd..71fe3fa1f3 100644
--- a/web-console/src/druid-models/workbench-query/workbench-query-part.ts
+++ b/web-console/src/druid-models/workbench-query/workbench-query-part.ts
@@ -144,13 +144,13 @@ export class WorkbenchQueryPart {
return this.queryString.trim().startsWith('{');
}
- public validJson(): boolean {
+ public issueWithJson(): string | undefined {
try {
Hjson.parse(this.queryString);
- return true;
- } catch {
- return false;
+ } catch (e) {
+ return e.message;
}
+ return;
}
public isSqlInJson(): boolean {
diff --git
a/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
b/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
index cc57096c43..cef773abb0 100644
--- a/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
+++ b/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
@@ -127,6 +127,24 @@ describe('WorkbenchQuery', () => {
expect(String(WorkbenchQuery.fromString(tabString))).toEqual(tabString);
});
+ describe('.getRowColumnFromIssue', () => {
+ it('works when it can not find at line', () => {
+ expect(WorkbenchQuery.getRowColumnFromIssue(`lol`)).toBeUndefined();
+ });
+
+ it('works when it can find at line', () => {
+ expect(
+ WorkbenchQuery.getRowColumnFromIssue(
+ `End of input while parsing an object (missing '}') at line 40,2
>>>} ...`,
+ ),
+ ).toEqual({
+ match: '',
+ row: 39,
+ column: 1,
+ });
+ });
+ });
+
describe('#makePreview', () => {
it('works', () => {
const workbenchQuery = WorkbenchQuery.blank().changeQueryString(sane`
@@ -640,4 +658,19 @@ describe('WorkbenchQuery', () => {
`);
});
});
+
+ describe('#getIssue', () => {
+ it('works', () => {
+ expect(
+ WorkbenchQuery.blank()
+ .changeQueryString(
+ sane`
+ {
+ lol: 1
+ `,
+ )
+ .getIssue(),
+ ).toEqual("End of input while parsing an object (missing '}') at line
2,9 >>> lol: 1 ...");
+ });
+ });
});
diff --git a/web-console/src/druid-models/workbench-query/workbench-query.ts
b/web-console/src/druid-models/workbench-query/workbench-query.ts
index 1a3d1e98ec..68d2dcd71f 100644
--- a/web-console/src/druid-models/workbench-query/workbench-query.ts
+++ b/web-console/src/druid-models/workbench-query/workbench-query.ts
@@ -34,7 +34,7 @@ import Hjson from 'hjson';
import * as JSONBig from 'json-bigint-native';
import { v4 as uuidv4 } from 'uuid';
-import type { ColumnMetadata } from '../../utils';
+import type { ColumnMetadata, RowColumn } from '../../utils';
import { deleteKeys, generate8HexId } from '../../utils';
import type { DruidEngine } from '../druid-engine/druid-engine';
import { validDruidEngine } from '../druid-engine/druid-engine';
@@ -225,6 +225,12 @@ export class WorkbenchQuery {
return orderByExpressions.length ?
SqlOrderByClause.create(orderByExpressions) : undefined;
}
+ static getRowColumnFromIssue(issue: string): RowColumn | undefined {
+ const m = issue.match(/at line (\d+),(\d+)/);
+ if (!m) return;
+ return { match: '', row: Number(m[1]) - 1, column: Number(m[2]) - 1 };
+ }
+
public readonly queryParts: WorkbenchQueryPart[];
public readonly queryContext: QueryContext;
public readonly engine?: DruidEngine;
@@ -351,13 +357,12 @@ export class WorkbenchQuery {
return this.getLastPart().isEmptyQuery();
}
- public isValid(): boolean {
+ public getIssue(): string | undefined {
const lastPart = this.getLastPart();
- if (lastPart.isJsonLike() && !lastPart.validJson()) {
- return false;
+ if (lastPart.isJsonLike()) {
+ return lastPart.issueWithJson();
}
-
- return true;
+ return;
}
public canPrettify(): boolean {
diff --git a/web-console/src/views/workbench-view/helper-query/helper-query.tsx
b/web-console/src/views/workbench-view/helper-query/helper-query.tsx
index cc7f638c25..f9711ab5cd 100644
--- a/web-console/src/views/workbench-view/helper-query/helper-query.tsx
+++ b/web-console/src/views/workbench-view/helper-query/helper-query.tsx
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-import { Button, ButtonGroup, InputGroup, Menu, MenuItem } from
'@blueprintjs/core';
+import { Button, ButtonGroup, InputGroup, Intent, Menu, MenuItem } from
'@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import { Popover2 } from '@blueprintjs/popover2';
import axios from 'axios';
@@ -40,7 +40,7 @@ import {
submitTaskQuery,
} from '../../../helpers';
import { usePermanentCallback, useQueryManager } from '../../../hooks';
-import { Api } from '../../../singletons';
+import { Api, AppToaster } from '../../../singletons';
import { ExecutionStateCache } from
'../../../singletons/execution-state-cache';
import { WorkbenchHistory } from '../../../singletons/workbench-history';
import type { WorkbenchRunningPromise } from
'../../../singletons/workbench-running-promises';
@@ -251,7 +251,24 @@ export const HelperQuery = React.memo(function
HelperQuery(props: HelperQueryPro
}
const handleRun = usePermanentCallback(async (preview: boolean) => {
- if (!query.isValid()) return;
+ const queryIssue = query.getIssue();
+ if (queryIssue) {
+ const position = WorkbenchQuery.getRowColumnFromIssue(queryIssue);
+
+ AppToaster.show({
+ icon: IconNames.ERROR,
+ intent: Intent.DANGER,
+ timeout: 90000,
+ message: queryIssue,
+ action: position
+ ? {
+ text: 'Go to issue',
+ onClick: () => moveToPosition(position),
+ }
+ : undefined,
+ });
+ return;
+ }
if (query.getEffectiveEngine() !== 'sql-msq-task') {
WorkbenchHistory.addQueryToHistory(query);
diff --git a/web-console/src/views/workbench-view/query-tab/query-tab.tsx
b/web-console/src/views/workbench-view/query-tab/query-tab.tsx
index 3fe362ab48..cc74617910 100644
--- a/web-console/src/views/workbench-view/query-tab/query-tab.tsx
+++ b/web-console/src/views/workbench-view/query-tab/query-tab.tsx
@@ -274,7 +274,24 @@ export const QueryTab = React.memo(function
QueryTab(props: QueryTabProps) {
}
const handleRun = usePermanentCallback(async (preview: boolean) => {
- if (!query.isValid()) return;
+ const queryIssue = query.getIssue();
+ if (queryIssue) {
+ const position = WorkbenchQuery.getRowColumnFromIssue(queryIssue);
+
+ AppToaster.show({
+ icon: IconNames.ERROR,
+ intent: Intent.DANGER,
+ timeout: 90000,
+ message: queryIssue,
+ action: position
+ ? {
+ text: 'Go to issue',
+ onClick: () => moveToPosition(position),
+ }
+ : undefined,
+ });
+ return;
+ }
if (query.getEffectiveEngine() !== 'sql-msq-task') {
WorkbenchHistory.addQueryToHistory(query);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]