diff --git a/web-console/src/components/sql-control.scss b/web-console/src/components/sql-control.scss index 468e91a3310..d5e894d25da 100644 --- a/web-console/src/components/sql-control.scss +++ b/web-console/src/components/sql-control.scss @@ -28,11 +28,16 @@ } .buttons { + position: relative; button{ margin-right: 15px; } + .query-elapsed { + position: absolute; + right: 10px; + } } } diff --git a/web-console/src/components/sql-control.tsx b/web-console/src/components/sql-control.tsx index 99c7c4397e2..6b4de1d56c7 100644 --- a/web-console/src/components/sql-control.tsx +++ b/web-console/src/components/sql-control.tsx @@ -40,6 +40,7 @@ export interface SqlControlProps extends React.Props { initSql: string | null; onRun: (query: string) => void; onExplain: (query: string) => void; + queryElapsed: number | null; } export interface SqlControlState { @@ -166,7 +167,7 @@ export class SqlControl extends React.Component onRun(query)}> {isRune ? 'Rune' : 'Run'} - {!isRune ? SqlControlPopover : null} + {!isRune && SqlControlPopover} + { + queryElapsed && + Last query took {(queryElapsed / 1000).toFixed(2)} seconds + } ; } diff --git a/web-console/src/views/sql-view.tsx b/web-console/src/views/sql-view.tsx index e8f90d72c3e..53712d97a18 100644 --- a/web-console/src/views/sql-view.tsx +++ b/web-console/src/views/sql-view.tsx @@ -29,7 +29,8 @@ import { localStorageGet, LocalStorageKeys, localStorageSet, parseQueryPlan, queryDruidRune, - queryDruidSql, QueryManager, SemiJoinQueryExplanation + queryDruidSql, QueryManager, + SemiJoinQueryExplanation } from '../utils'; import './sql-view.scss'; @@ -46,11 +47,17 @@ export interface SqlViewState { explainResult: BasicQueryExplanation | SemiJoinQueryExplanation | string | null; loadingExplain: boolean; explainError: Error | null; + queryElapsed: number | null; +} + +interface SqlQueryResult { + queryResult: HeaderRows; + queryElapsed: number; } export class SqlView extends React.Component { - private sqlQueryManager: QueryManager; + private sqlQueryManager: QueryManager; private explainQueryManager: QueryManager; constructor(props: SqlViewProps, context: any) { @@ -62,34 +69,42 @@ export class SqlView extends React.Component { explainDialogOpen: false, loadingExplain: false, explainResult: null, - explainError: null + explainError: null, + queryElapsed: null }; } componentDidMount(): void { this.sqlQueryManager = new QueryManager({ processQuery: async (query: string) => { + const startTime = new Date(); if (query.trim().startsWith('{')) { // Secret way to issue a native JSON "rune" query const runeQuery = Hjson.parse(query); - return decodeRune(runeQuery, await queryDruidRune(runeQuery)); - + const result = await queryDruidRune(runeQuery); + return { + queryResult: decodeRune(runeQuery, result), + queryElapsed: new Date().valueOf() - startTime.valueOf() + }; } else { const result = await queryDruidSql({ query, resultFormat: 'array', header: true }); - return { - header: (result && result.length) ? result[0] : [], - rows: (result && result.length) ? result.slice(1) : [] + queryResult: { + header: (result && result.length) ? result[0] : [], + rows: (result && result.length) ? result.slice(1) : [] + }, + queryElapsed: new Date().valueOf() - startTime.valueOf() }; } }, onStateChange: ({ result, loading, error }) => { this.setState({ - result, + result: result ? result.queryResult : null, + queryElapsed: result ? result.queryElapsed : null, loading, error }); @@ -158,6 +173,7 @@ export class SqlView extends React.Component { render() { const { initSql } = this.props; + const { queryElapsed } = this.state; return
{ this.sqlQueryManager.runQuery(q); }} onExplain={(q: string) => this.getExplain(q)} + queryElapsed={queryElapsed} /> {this.renderResultTable()} {this.renderExplainDialog()}