Skip to content

Commit

Permalink
[sqllab] run only the part of the query that is selected (#1479)
Browse files Browse the repository at this point in the history
  • Loading branch information
mistercrunch authored Nov 1, 2016
1 parent 4f49cb5 commit 4023f32
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 19 deletions.
5 changes: 5 additions & 0 deletions caravel/assets/javascripts/SqlLab/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const QUERY_EDITOR_SET_SCHEMA = 'QUERY_EDITOR_SET_SCHEMA';
export const QUERY_EDITOR_SET_TITLE = 'QUERY_EDITOR_SET_TITLE';
export const QUERY_EDITOR_SET_AUTORUN = 'QUERY_EDITOR_SET_AUTORUN';
export const QUERY_EDITOR_SET_SQL = 'QUERY_EDITOR_SET_SQL';
export const QUERY_EDITOR_SET_SELECTED_TEXT = 'QUERY_EDITOR_SET_SELECTED_TEXT';
export const SET_DATABASES = 'SET_DATABASES';
export const SET_ACTIVE_QUERY_EDITOR = 'SET_ACTIVE_QUERY_EDITOR';
export const ADD_ALERT = 'ADD_ALERT';
Expand Down Expand Up @@ -193,6 +194,10 @@ export function queryEditorSetSql(queryEditor, sql) {
return { type: QUERY_EDITOR_SET_SQL, queryEditor, sql };
}

export function queryEditorSetSelectedText(queryEditor, sql) {
return { type: QUERY_EDITOR_SET_SELECTED_TEXT, queryEditor, sql };
}

export function mergeTable(table) {
return { type: MERGE_TABLE, table };
}
Expand Down
36 changes: 29 additions & 7 deletions caravel/assets/javascripts/SqlLab/components/AceEditorWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import 'brace/mode/sql';
import 'brace/theme/github';
import 'brace/ext/language_tools';
import ace from 'brace';
import { areArraysShallowEqual } from '../../reduxUtils';

const langTools = ace.acequire('ace/ext/language_tools');

const propTypes = {
actions: React.PropTypes.object.isRequired,
onBlur: React.PropTypes.func,
sql: React.PropTypes.string.isRequired,
tables: React.PropTypes.array,
queryEditor: React.PropTypes.object.isRequired,
};

const defaultProps = {
Expand All @@ -25,29 +28,48 @@ class AceEditorWrapper extends React.PureComponent {
sql: props.sql,
};
}
componentDidMount() {
// Making sure no text is selected from previous mount
this.props.actions.queryEditorSetSelectedText(this.props.queryEditor, null);
this.setAutoCompleter();
}
componentWillReceiveProps(nextProps) {
if (!areArraysShallowEqual(this.props.tables, nextProps.tables)) {
this.setAutoCompleter();
}
}
textChange(text) {
this.setState({ sql: text });
}
onBlur() {
this.props.onBlur(this.state.sql);
}
getCompletions(aceEditor, session, pos, prefix, callback) {
callback(null, this.state.words);
}
onEditorLoad(editor) {
editor.$blockScrolling = Infinity; // eslint-disable-line no-param-reassign
editor.selection.on('changeSelection', () => {
this.props.actions.queryEditorSetSelectedText(
this.props.queryEditor, editor.getSelectedText());
});
}
setAutoCompleter() {
// Loading table and column names as auto-completable words
let words = [];
const columns = {};
const tables = this.props.tables || [];
tables.forEach(t => {
words.push({ name: t.name, value: t.name, score: 55, meta: 'table' });
t.columns.forEach(col => {
const cols = t.columns || [];
cols.forEach(col => {
columns[col.name] = null; // using an object as a unique set
});
});
words = words.concat(Object.keys(columns).map(col => (
{ name: col, value: col, score: 50, meta: 'column' }
)));
callback(null, words);
}
setAutoCompleter() {
// Loading table and column names as auto-completable words
this.setState({ words });
const completer = {
getCompletions: this.getCompletions.bind(this),
};
Expand All @@ -56,19 +78,19 @@ class AceEditorWrapper extends React.PureComponent {
}
}
render() {
this.setAutoCompleter();
return (
<AceEditor
mode="sql"
theme="github"
onLoad={this.onEditorLoad.bind(this)}
onBlur={this.onBlur.bind(this)}
minLines={8}
maxLines={30}
onChange={this.textChange.bind(this)}
height="200px"
width="100%"
editorProps={{ $blockScrolling: true }}
enableBasicAutocompletion
enableLiveAutocompletion
value={this.state.sql}
/>
);
Expand Down
25 changes: 17 additions & 8 deletions caravel/assets/javascripts/SqlLab/components/SqlEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@ class SqlEditor extends React.PureComponent {
this.startQuery(runAsync);
}
startQuery(runAsync = false, ctas = false) {
const qe = this.props.queryEditor;
const query = {
dbId: this.props.queryEditor.dbId,
sql: this.props.queryEditor.sql,
sqlEditorId: this.props.queryEditor.id,
tab: this.props.queryEditor.title,
schema: this.props.queryEditor.schema,
dbId: qe.dbId,
sql: qe.selectedText ? qe.selectedText : qe.sql,
sqlEditorId: qe.id,
tab: qe.title,
schema: qe.schema,
tempTableName: this.state.ctas,
runAsync,
ctas,
Expand Down Expand Up @@ -92,25 +93,31 @@ class SqlEditor extends React.PureComponent {

render() {
let runButtons = [];
let runText = 'Run Query';
let btnStyle = 'primary';
if (this.props.queryEditor.selectedText) {
runText = 'Run Selection';
btnStyle = 'warning';
}
if (this.props.database && this.props.database.allow_run_sync) {
runButtons.push(
<Button
bsSize="small"
bsStyle="primary"
bsStyle={btnStyle}
style={{ width: '100px' }}
onClick={this.runQuery.bind(this, false)}
disabled={!(this.props.queryEditor.dbId)}
key="run-btn"
>
<i className="fa fa-table" /> Run Query
<i className="fa fa-table" /> {runText}
</Button>
);
}
if (this.props.database && this.props.database.allow_run_async) {
runButtons.push(
<Button
bsSize="small"
bsStyle="primary"
bsStyle={btnStyle}
style={{ width: '100px' }}
onClick={this.runQuery.bind(this, true)}
disabled={!(this.props.queryEditor.dbId)}
Expand Down Expand Up @@ -209,6 +216,8 @@ class SqlEditor extends React.PureComponent {
<Col md={9}>
<AceEditorWrapper
tables={this.props.tables}
actions={this.props.actions}
queryEditor={this.props.queryEditor}
sql={this.props.queryEditor.sql}
onBlur={this.setQueryEditorSql.bind(this)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import ModalTrigger from '../../components/ModalTrigger';
const propTypes = {
table: React.PropTypes.object,
actions: React.PropTypes.object,
timeout: React.PropTypes.integer, // used for tests
timeout: React.PropTypes.number, // used for tests
};

const defaultProps = {
Expand Down
4 changes: 4 additions & 0 deletions caravel/assets/javascripts/SqlLab/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const defaultQueryEditor = {
id: shortid.generate(),
title: 'Untitled Query',
sql: 'SELECT *\nFROM\nWHERE',
selectedText: null,
latestQueryId: null,
autorun: false,
dbId: null,
Expand Down Expand Up @@ -171,6 +172,9 @@ export const sqlLabReducer = function (state, action) {
[actions.QUERY_EDITOR_SET_SQL]() {
return alterInArr(state, 'queryEditors', action.queryEditor, { sql: action.sql });
},
[actions.QUERY_EDITOR_SET_SELECTED_TEXT]() {
return alterInArr(state, 'queryEditors', action.queryEditor, { selectedText: action.sql });
},
[actions.QUERY_EDITOR_SET_AUTORUN]() {
return alterInArr(state, 'queryEditors', action.queryEditor, { autorun: action.autorun });
},
Expand Down
7 changes: 4 additions & 3 deletions caravel/assets/spec/javascripts/sqllab/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,12 @@ export const table = {
};
export const defaultQueryEditor = {
id: 'dfsadfs',
title: 'Untitled Query',
sql: 'SELECT *\nFROM\nWHERE',
latestQueryId: null,
autorun: false,
dbId: null,
latestQueryId: null,
selectedText: null,
sql: 'SELECT *\nFROM\nWHERE',
title: 'Untitled Query',
};
export const queries = [
{
Expand Down
7 changes: 7 additions & 0 deletions caravel/assets/spec/javascripts/sqllab/reducers_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ describe('sqlLabReducer', () => {
newState = r.sqlLabReducer(newState, actions.queryEditorSetSql(qe, sql));
expect(newState.queryEditors[1].sql).to.equal(sql);
});
it('should set selectedText', () => {
const selectedText = 'TEST';
expect(newState.queryEditors[0].selectedText).to.equal(null);
newState = r.sqlLabReducer(
newState, actions.queryEditorSetSelectedText(newState.queryEditors[0], 'TEST'));
expect(newState.queryEditors[0].selectedText).to.equal(selectedText);
});
});
describe('Tables', () => {
let newState;
Expand Down

0 comments on commit 4023f32

Please sign in to comment.