Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[sqllab] run only the part of the query that is selected #1479

Merged
merged 1 commit into from
Nov 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be great to move the run buttons out of this component and into it's own component. there's a lot happening in this component and with change, more happening with the run buttons.

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