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] add support for Jinja templating #1426

Merged
merged 5 commits into from
Oct 26, 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
1 change: 1 addition & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ exclude_paths:
- "caravel/assets/node_modules/"
- "caravel/assets/javascripts/dist/"
- "caravel/migrations"
- "docs/"
109 changes: 79 additions & 30 deletions caravel/assets/javascripts/SqlLab/components/HighlightedSql.jsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,93 @@
import React from 'react';
import { Well } from 'react-bootstrap';
import SyntaxHighlighter from 'react-syntax-highlighter';
import { github } from 'react-syntax-highlighter/dist/styles';
import ModalTrigger from '../../components/ModalTrigger';

const HighlightedSql = (props) => {
const sql = props.sql || '';
let lines = sql.split('\n');
if (lines.length >= props.maxLines) {
lines = lines.slice(0, props.maxLines);
lines.push('{...}');
const defaultProps = {
maxWidth: 50,
maxLines: 5,
shrink: false,
};

const propTypes = {
sql: React.PropTypes.string.isRequired,
rawSql: React.PropTypes.string,
maxWidth: React.PropTypes.number,
maxLines: React.PropTypes.number,
shrink: React.PropTypes.bool,
};

class HighlightedSql extends React.Component {
constructor(props) {
super(props);
this.state = {
modalBody: null,
};
}
let shownSql = sql;
if (props.shrink) {
shownSql = lines.map((line) => {
shrinkSql() {
const props = this.props;
const sql = props.sql || '';
let lines = sql.split('\n');
if (lines.length >= props.maxLines) {
lines = lines.slice(0, props.maxLines);
lines.push('{...}');
}
return lines.map((line) => {
if (line.length > props.maxWidth) {
return line.slice(0, props.maxWidth) + '{...}';
}
return line;
})
.join('\n');
}
return (
<div>
<SyntaxHighlighter language="sql" style={github}>
{shownSql}
</SyntaxHighlighter>
</div>
);
};

HighlightedSql.defaultProps = {
maxWidth: 60,
maxLines: 6,
shrink: false,
};

HighlightedSql.propTypes = {
sql: React.PropTypes.string,
maxWidth: React.PropTypes.number,
maxLines: React.PropTypes.number,
shrink: React.PropTypes.bool,
};
triggerNode() {
const props = this.props;
let shownSql = props.shrink ? this.shrinkSql(props.sql) : props.sql;
return (
<Well>
<SyntaxHighlighter language="sql" style={github}>
{shownSql}
</SyntaxHighlighter>
</Well>);
}
generateModal() {
const props = this.props;
let rawSql;
if (props.rawSql && props.rawSql !== this.props.sql) {
rawSql = (
<div>
<h4>Raw SQL</h4>
<SyntaxHighlighter language="sql" style={github}>
{props.rawSql}
</SyntaxHighlighter>
</div>
);
}
this.setState({
modalBody: (
<div>
<h4>Source SQL</h4>
<SyntaxHighlighter language="sql" style={github}>
{this.props.sql}
</SyntaxHighlighter>
{rawSql}
</div>
),
});
}
render() {
return (
<ModalTrigger
modalTitle="SQL"
triggerNode={this.triggerNode()}
modalBody={this.state.modalBody}
beforeOpen={this.generateModal.bind(this)}
/>
);
}
}
HighlightedSql.propTypes = propTypes;
HighlightedSql.defaultProps = defaultProps;

export default HighlightedSql;
5 changes: 2 additions & 3 deletions caravel/assets/javascripts/SqlLab/components/QueryTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,8 @@ class QueryTable extends React.Component {
</button>
);
q.started = moment(q.startDttm).format('HH:mm:ss');
const source = (q.ctas) ? q.executedSql : q.sql;
q.sql = (
<HighlightedSql sql={source} shrink maxWidth={100} />
<HighlightedSql sql={q.sql} rawSql={q.executedSql} shrink maxWidth={60} />
);
if (q.resultsKey) {
q.output = (
Expand Down Expand Up @@ -169,7 +168,7 @@ class QueryTable extends React.Component {
q.querylink = (
<div style={{ width: '100px' }}>
<a
href={this.getQueryLink(q.dbId, source)}
href={this.getQueryLink(q.dbId, q.sql)}
className="btn btn-primary btn-xs"
>
<i className="fa fa-external-link" />Open in SQL Editor
Expand Down
1 change: 1 addition & 0 deletions caravel/assets/javascripts/SqlLab/components/SqlEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class SqlEditor extends React.Component {
sql: this.props.queryEditor.sql,
sqlEditorId: this.props.queryEditor.id,
tab: this.props.queryEditor.title,
schema: this.props.queryEditor.schema,
tempTableName: this.state.ctas,
runAsync,
ctas,
Expand Down
4 changes: 4 additions & 0 deletions caravel/assets/javascripts/SqlLab/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,7 @@ div.tablePopover:hover {
a.Link {
cursor: pointer;
}
.QueryTable .well {
padding: 3px 5px;
margin: 3px 5px;
}
8 changes: 4 additions & 4 deletions caravel/assets/javascripts/components/ModalTrigger.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import cx from 'classnames';
const propTypes = {
triggerNode: PropTypes.node.isRequired,
modalTitle: PropTypes.node.isRequired,
modalBody: PropTypes.node.isRequired,
modalBody: PropTypes.node, // not required because it can be generated by beforeOpen
beforeOpen: PropTypes.func,
onExit: PropTypes.func,
isButton: PropTypes.bool,
Expand Down Expand Up @@ -46,8 +46,8 @@ export default class ModalTrigger extends React.Component {
'btn btn-default btn-sm': this.props.isButton,
});
return (
<a href="#" className={classNames} onClick={this.open}>
{this.props.triggerNode}
<span className={classNames} onClick={this.open} style={{ cursor: 'pointer' }}>
{this.props.triggerNode}
<Modal
show={this.state.showModal}
onHide={this.close}
Expand All @@ -62,7 +62,7 @@ export default class ModalTrigger extends React.Component {
{this.props.modalBody}
</Modal.Body>
</Modal>
</a>
</span>
);
}
}
Expand Down
23 changes: 15 additions & 8 deletions caravel/assets/spec/javascripts/sqllab/HighlightedSql_spec.jsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
import React from 'react';
import HighlightedSql from '../../../javascripts/SqlLab/components/HighlightedSql';
import ModalTrigger from '../../../javascripts/components/ModalTrigger';
import SyntaxHighlighter from 'react-syntax-highlighter';
import { shallow } from 'enzyme';
import { mount, shallow } from 'enzyme';
import { describe, it } from 'mocha';
import { expect } from 'chai';


describe('HighlightedSql', () => {
const sql = "SELECT * FROM test WHERE something='fkldasjfklajdslfkjadlskfjkldasjfkladsjfkdjsa'";
it('renders', () => {
expect(React.isValidElement(<HighlightedSql />)).to.equal(true);
});
it('renders with props', () => {
expect(React.isValidElement(<HighlightedSql sql={sql} />))
.to.equal(true);
});
it('renders a SyntaxHighlighter', () => {
it('renders a ModalTrigger', () => {
const wrapper = shallow(<HighlightedSql sql={sql} />);
expect(wrapper.find(SyntaxHighlighter)).to.have.length(1);
expect(wrapper.find(ModalTrigger)).to.have.length(1);
});
it('renders a SyntaxHighlighter while using shrink', () => {
it('renders a ModalTrigger while using shrink', () => {
const wrapper = shallow(<HighlightedSql sql={sql} shrink maxWidth={20} />);
expect(wrapper.find(SyntaxHighlighter)).to.have.length(1);
expect(wrapper.find(ModalTrigger)).to.have.length(1);
});
it('renders two SyntaxHighlighter in modal', () => {
const wrapper = mount(
<HighlightedSql sql={sql} rawSql="SELECT * FORM foo" shrink maxWidth={5} />);
const well = wrapper.find('.well');
expect(well).to.have.length(1);
well.simulate('click');
const modalBody = mount(wrapper.state().modalBody);
expect(modalBody.find(SyntaxHighlighter)).to.have.length(2);
});
});
6 changes: 6 additions & 0 deletions caravel/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ class CeleryConfig(object):
# in SQL Lab by using the "Run Async" button/feature
RESULTS_BACKEND = None

# A dictionary of items that gets merged into the Jinja context for
# SQL Lab. The existing context gets updated with this dictionary,
# meaning values for existing keys get overwritten by the content of this
# dictionary.
JINJA_CONTEXT_ADDONS = {}

try:
from caravel_config import * # noqa
except ImportError:
Expand Down
7 changes: 3 additions & 4 deletions caravel/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
INFER_COL_TYPES_SAMPLE_SIZE = 100


# http://pandas.pydata.org/pandas-docs/stable/internals.html#
# subclassing-pandas-data-structures
class CaravelDataFrame(object):
def __init__(self, df):
self.__df = df.where((pd.notnull(df)), None)
Expand Down Expand Up @@ -91,13 +89,14 @@ def datetime_conversion_rate(data_series):


def is_date(dtype):
return dtype.name.startswith('datetime')
if dtype.name:
return dtype.name.startswith('datetime')


def is_dimension(dtype, column_name):
if is_id(column_name):
return False
return dtype == np.object or dtype == np.bool
return dtype.name in ('object', 'bool')


def is_id(column_name):
Expand Down
Loading