mirror of https://github.com/apache/druid.git
Web-console: gate auto complete on current table and schema (#8322)
* gate auto complete on current table and schema * reset defaults * add static functions * move completions to state
This commit is contained in:
parent
31af4eb9ad
commit
cae1361c32
|
@ -32,6 +32,7 @@ exports[`sql view matches snapshot 1`] = `
|
|||
className="control-pane"
|
||||
>
|
||||
<QueryInput
|
||||
currentSchema="druid"
|
||||
onQueryStringChange={[Function]}
|
||||
queryString="test"
|
||||
runeMode={false}
|
||||
|
|
|
@ -25,7 +25,6 @@ import AceEditor from 'react-ace';
|
|||
import { SQL_DATE_TYPES, SQL_FUNCTIONS, SyntaxDescription } from '../../../../lib/sql-function-doc';
|
||||
import { uniq } from '../../../utils';
|
||||
import { ColumnMetadata } from '../../../utils/column-metadata';
|
||||
import { ColumnTreeProps, ColumnTreeState } from '../column-tree/column-tree';
|
||||
|
||||
import { SQL_CONSTANTS, SQL_DYNAMICS, SQL_EXPRESSION_PARTS, SQL_KEYWORDS } from './keywords';
|
||||
|
||||
|
@ -38,59 +37,22 @@ export interface QueryInputProps {
|
|||
onQueryStringChange: (newQueryString: string) => void;
|
||||
runeMode: boolean;
|
||||
columnMetadata?: ColumnMetadata[];
|
||||
currentSchema?: string;
|
||||
currentTable?: string;
|
||||
}
|
||||
|
||||
export interface QueryInputState {
|
||||
// For reasons (https://github.com/securingsincity/react-ace/issues/415) react ace editor needs an explicit height
|
||||
// Since this component will grown and shrink dynamically we will measure its height and then set it.
|
||||
editorHeight: number;
|
||||
completions: any[];
|
||||
prevColumnMetadata?: ColumnMetadata[];
|
||||
prevCurrentTable?: string;
|
||||
prevCurrentSchema?: string;
|
||||
}
|
||||
|
||||
export class QueryInput extends React.PureComponent<QueryInputProps, QueryInputState> {
|
||||
static getDerivedStateFromProps(props: ColumnTreeProps, state: ColumnTreeState) {
|
||||
const { columnMetadata } = props;
|
||||
|
||||
if (columnMetadata && columnMetadata !== state.prevColumnMetadata) {
|
||||
const completions = ([] as any[]).concat(
|
||||
uniq(columnMetadata.map(d => d.TABLE_SCHEMA)).map(v => ({
|
||||
value: v,
|
||||
score: 10,
|
||||
meta: 'schema',
|
||||
})),
|
||||
uniq(columnMetadata.map(d => d.TABLE_NAME)).map(v => ({
|
||||
value: v,
|
||||
score: 49,
|
||||
meta: 'datasource',
|
||||
})),
|
||||
uniq(columnMetadata.map(d => d.COLUMN_NAME)).map(v => ({
|
||||
value: v,
|
||||
score: 50,
|
||||
meta: 'column',
|
||||
})),
|
||||
);
|
||||
|
||||
langTools.addCompleter({
|
||||
getCompletions: (_editor: any, _session: any, _pos: any, _prefix: any, callback: any) => {
|
||||
callback(null, completions);
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
prevColumnMetadata: columnMetadata,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
constructor(props: QueryInputProps, context: any) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
editorHeight: 200,
|
||||
};
|
||||
}
|
||||
|
||||
private replaceDefaultAutoCompleter = () => {
|
||||
static replaceDefaultAutoCompleter(): void {
|
||||
if (!langTools) return;
|
||||
|
||||
const keywordList = ([] as any[]).concat(
|
||||
|
@ -112,9 +74,9 @@ export class QueryInput extends React.PureComponent<QueryInputProps, QueryInputS
|
|||
langTools.textCompleter,
|
||||
keywordCompleter,
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
||||
private addFunctionAutoCompleter = (): void => {
|
||||
static addFunctionAutoCompleter(): void {
|
||||
if (!langTools) return;
|
||||
|
||||
const functionList: any[] = SQL_FUNCTIONS.map((entry: SyntaxDescription) => {
|
||||
|
@ -161,11 +123,75 @@ export class QueryInput extends React.PureComponent<QueryInputProps, QueryInputS
|
|||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props: QueryInputProps, state: QueryInputState) {
|
||||
const { columnMetadata, currentSchema, currentTable } = props;
|
||||
|
||||
if (
|
||||
columnMetadata &&
|
||||
(columnMetadata !== state.prevColumnMetadata ||
|
||||
currentSchema !== state.prevCurrentSchema ||
|
||||
currentTable !== state.prevCurrentTable)
|
||||
) {
|
||||
const completions = ([] as any[]).concat(
|
||||
uniq(columnMetadata.map(d => d.TABLE_SCHEMA)).map(v => ({
|
||||
value: v,
|
||||
score: 10,
|
||||
meta: 'schema',
|
||||
})),
|
||||
uniq(
|
||||
columnMetadata
|
||||
.filter(d => (currentSchema ? d.TABLE_SCHEMA === currentSchema : true))
|
||||
.map(d => d.TABLE_NAME),
|
||||
).map(v => ({
|
||||
value: v,
|
||||
score: 49,
|
||||
meta: 'datasource',
|
||||
})),
|
||||
uniq(
|
||||
columnMetadata
|
||||
.filter(d =>
|
||||
currentTable && currentSchema
|
||||
? d.TABLE_NAME === currentTable && d.TABLE_SCHEMA === currentSchema
|
||||
: true,
|
||||
)
|
||||
.map(d => d.COLUMN_NAME),
|
||||
).map(v => ({
|
||||
value: v,
|
||||
score: 50,
|
||||
meta: 'column',
|
||||
})),
|
||||
);
|
||||
|
||||
return {
|
||||
completions,
|
||||
prevColumnMetadata: columnMetadata,
|
||||
prevCurrentSchema: currentSchema,
|
||||
prevCurrentTable: currentTable,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
constructor(props: QueryInputProps, context: any) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
editorHeight: 200,
|
||||
completions: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this.replaceDefaultAutoCompleter();
|
||||
this.addFunctionAutoCompleter();
|
||||
QueryInput.replaceDefaultAutoCompleter();
|
||||
QueryInput.addFunctionAutoCompleter();
|
||||
if (langTools) {
|
||||
langTools.addCompleter({
|
||||
getCompletions: (_editor: any, _session: any, _pos: any, _prefix: any, callback: any) => {
|
||||
callback(null, this.state.completions);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private handleAceContainerResize = (entries: IResizeEntry[]) => {
|
||||
|
|
|
@ -477,6 +477,21 @@ export class QueryView extends React.PureComponent<QueryViewProps, QueryViewStat
|
|||
wrapQuery,
|
||||
} = this.state;
|
||||
|
||||
let currentSchema;
|
||||
let currentTable;
|
||||
|
||||
if (result && result.parsedQuery instanceof SqlQuery) {
|
||||
currentSchema = result.parsedQuery.getSchema();
|
||||
currentTable = result.parsedQuery.getTableName();
|
||||
} else if (localStorageGet(LocalStorageKeys.QUERY_KEY)) {
|
||||
const defaultQueryString = localStorageGet(LocalStorageKeys.QUERY_KEY);
|
||||
const tempAst = defaultQueryString ? parser(defaultQueryString) : undefined;
|
||||
if (tempAst) {
|
||||
currentSchema = tempAst.getSchema();
|
||||
currentTable = tempAst.getTableName();
|
||||
}
|
||||
}
|
||||
|
||||
const runeMode = QueryView.isJsonLike(queryString);
|
||||
return (
|
||||
<SplitterLayout
|
||||
|
@ -491,6 +506,8 @@ export class QueryView extends React.PureComponent<QueryViewProps, QueryViewStat
|
|||
>
|
||||
<div className="control-pane">
|
||||
<QueryInput
|
||||
currentSchema={currentSchema ? currentSchema : 'druid'}
|
||||
currentTable={currentTable}
|
||||
queryString={queryString}
|
||||
onQueryStringChange={this.handleQueryStringChange}
|
||||
runeMode={runeMode}
|
||||
|
|
Loading…
Reference in New Issue