Add time taken by last query in SQL view (#7421)

* Add time taken by query

* Fix time to 2 dp; set state in on state change; hide time taken at first

* Refactored code: defined query result interface; more concise shorthand expression

* Use single quote
This commit is contained in:
Qi Shu 2019-04-10 23:35:47 -07:00 committed by Clint Wylie
parent bbb620125d
commit 4ea37e2614
3 changed files with 38 additions and 11 deletions

View File

@ -28,11 +28,16 @@
} }
.buttons { .buttons {
position: relative;
button{ button{
margin-right: 15px; margin-right: 15px;
} }
.query-elapsed {
position: absolute;
right: 10px;
}
} }
} }

View File

@ -40,6 +40,7 @@ export interface SqlControlProps extends React.Props<any> {
initSql: string | null; initSql: string | null;
onRun: (query: string) => void; onRun: (query: string) => void;
onExplain: (query: string) => void; onExplain: (query: string) => void;
queryElapsed: number | null;
} }
export interface SqlControlState { export interface SqlControlState {
@ -166,7 +167,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
} }
render() { render() {
const { onRun, onExplain } = this.props; const { onRun, onExplain, queryElapsed } = this.props;
const { query, autoCompleteOn } = this.state; const { query, autoCompleteOn } = this.state;
const isRune = query.trim().startsWith('{'); const isRune = query.trim().startsWith('{');
@ -217,7 +218,11 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
<Button rightIcon={IconNames.CARET_RIGHT} onClick={() => onRun(query)}> <Button rightIcon={IconNames.CARET_RIGHT} onClick={() => onRun(query)}>
{isRune ? 'Rune' : 'Run'} {isRune ? 'Rune' : 'Run'}
</Button> </Button>
{!isRune ? SqlControlPopover : null} {!isRune && SqlControlPopover}
{
queryElapsed &&
<span className={'query-elapsed'}> Last query took {(queryElapsed / 1000).toFixed(2)} seconds</span>
}
</div> </div>
</div>; </div>;
} }

View File

@ -29,7 +29,8 @@ import {
localStorageGet, LocalStorageKeys, localStorageGet, LocalStorageKeys,
localStorageSet, parseQueryPlan, localStorageSet, parseQueryPlan,
queryDruidRune, queryDruidRune,
queryDruidSql, QueryManager, SemiJoinQueryExplanation queryDruidSql, QueryManager,
SemiJoinQueryExplanation
} from '../utils'; } from '../utils';
import './sql-view.scss'; import './sql-view.scss';
@ -46,11 +47,17 @@ export interface SqlViewState {
explainResult: BasicQueryExplanation | SemiJoinQueryExplanation | string | null; explainResult: BasicQueryExplanation | SemiJoinQueryExplanation | string | null;
loadingExplain: boolean; loadingExplain: boolean;
explainError: Error | null; explainError: Error | null;
queryElapsed: number | null;
}
interface SqlQueryResult {
queryResult: HeaderRows;
queryElapsed: number;
} }
export class SqlView extends React.Component<SqlViewProps, SqlViewState> { export class SqlView extends React.Component<SqlViewProps, SqlViewState> {
private sqlQueryManager: QueryManager<string, HeaderRows>; private sqlQueryManager: QueryManager<string, SqlQueryResult>;
private explainQueryManager: QueryManager<string, any>; private explainQueryManager: QueryManager<string, any>;
constructor(props: SqlViewProps, context: any) { constructor(props: SqlViewProps, context: any) {
@ -62,34 +69,42 @@ export class SqlView extends React.Component<SqlViewProps, SqlViewState> {
explainDialogOpen: false, explainDialogOpen: false,
loadingExplain: false, loadingExplain: false,
explainResult: null, explainResult: null,
explainError: null explainError: null,
queryElapsed: null
}; };
} }
componentDidMount(): void { componentDidMount(): void {
this.sqlQueryManager = new QueryManager({ this.sqlQueryManager = new QueryManager({
processQuery: async (query: string) => { processQuery: async (query: string) => {
const startTime = new Date();
if (query.trim().startsWith('{')) { if (query.trim().startsWith('{')) {
// Secret way to issue a native JSON "rune" query // Secret way to issue a native JSON "rune" query
const runeQuery = Hjson.parse(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 { } else {
const result = await queryDruidSql({ const result = await queryDruidSql({
query, query,
resultFormat: 'array', resultFormat: 'array',
header: true header: true
}); });
return { return {
header: (result && result.length) ? result[0] : [], queryResult: {
rows: (result && result.length) ? result.slice(1) : [] header: (result && result.length) ? result[0] : [],
rows: (result && result.length) ? result.slice(1) : []
},
queryElapsed: new Date().valueOf() - startTime.valueOf()
}; };
} }
}, },
onStateChange: ({ result, loading, error }) => { onStateChange: ({ result, loading, error }) => {
this.setState({ this.setState({
result, result: result ? result.queryResult : null,
queryElapsed: result ? result.queryElapsed : null,
loading, loading,
error error
}); });
@ -158,6 +173,7 @@ export class SqlView extends React.Component<SqlViewProps, SqlViewState> {
render() { render() {
const { initSql } = this.props; const { initSql } = this.props;
const { queryElapsed } = this.state;
return <div className="sql-view app-view"> return <div className="sql-view app-view">
<SqlControl <SqlControl
@ -167,6 +183,7 @@ export class SqlView extends React.Component<SqlViewProps, SqlViewState> {
this.sqlQueryManager.runQuery(q); this.sqlQueryManager.runQuery(q);
}} }}
onExplain={(q: string) => this.getExplain(q)} onExplain={(q: string) => this.getExplain(q)}
queryElapsed={queryElapsed}
/> />
{this.renderResultTable()} {this.renderResultTable()}
{this.renderExplainDialog()} {this.renderExplainDialog()}