Skip to content

Commit

Permalink
[explore ] templating can now reference query elements (#2388)
Browse files Browse the repository at this point in the history
Second take on
mistercrunch#3
  • Loading branch information
mistercrunch committed Mar 14, 2017
1 parent 08bdcd5 commit 5e43d07
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 7 deletions.
12 changes: 10 additions & 2 deletions superset/connectors/sqla/models.py
Expand Up @@ -340,8 +340,15 @@ def get_query_str( # sqla
extras=None,
columns=None):
"""Querying any sqla table from this common interface"""
template_kwargs = {
'from_dttm': from_dttm,
'groupby': groupby,
'metrics': metrics,
'row_limit': row_limit,
'to_dttm': to_dttm,
}
template_processor = get_template_processor(
table=self, database=self.database)
table=self, database=self.database, **template_kwargs)

# For backward compatibility
if granularity not in self.dttm_cols:
Expand Down Expand Up @@ -430,7 +437,8 @@ def visit_column(element, compiler, **kw):

# Supporting arbitrary SQL statements in place of tables
if self.sql:
tbl = TextAsFrom(sa.text(self.sql), []).alias('expr_qry')
from_sql = template_processor.process_template(self.sql)
tbl = TextAsFrom(sa.text(from_sql), []).alias('expr_qry')

if not columns:
qry = qry.group_by(*groupby_exprs)
Expand Down
12 changes: 7 additions & 5 deletions superset/jinja_context.py
Expand Up @@ -44,7 +44,7 @@ class BaseTemplateProcessor(object):
"""
engine = None

def __init__(self, database=None, query=None, table=None):
def __init__(self, database=None, query=None, table=None, **kwargs):
self.database = database
self.query = query
self.schema = None
Expand All @@ -53,20 +53,22 @@ def __init__(self, database=None, query=None, table=None):
elif table:
self.schema = table.schema
self.context = {}
self.context.update(kwargs)
self.context.update(BASE_CONTEXT)
if self.engine:
self.context[self.engine] = self
self.env = SandboxedEnvironment()

def process_template(self, sql):
def process_template(self, sql, **kwargs):
"""Processes a sql template
>>> sql = "SELECT '{{ datetime(2017, 1, 1).isoformat() }}'"
>>> process_template(sql)
"SELECT '2017-01-01T00:00:00'"
"""
template = self.env.from_string(sql)
return template.render(self.context)
kwargs.update(self.context)
return template.render(kwargs)


class PrestoTemplateProcessor(BaseTemplateProcessor):
Expand Down Expand Up @@ -106,6 +108,6 @@ class HiveTemplateProcessor(PrestoTemplateProcessor):
template_processors[o.engine] = o


def get_template_processor(database, table=None, query=None):
def get_template_processor(database, table=None, query=None, **kwargs):
TP = template_processors.get(database.backend, BaseTemplateProcessor)
return TP(database=database, table=table, query=query)
return TP(database=database, table=table, query=query, **kwargs)
14 changes: 14 additions & 0 deletions tests/core_tests.py
Expand Up @@ -553,6 +553,20 @@ def test_process_template(self):
rendered = tp.process_template(sql)
self.assertEqual("SELECT '2017-01-01T00:00:00'", rendered)

def test_get_template_kwarg(self):
maindb = self.get_main_database(db.session)
s = "{{ foo }}"
tp = jinja_context.get_template_processor(database=maindb, foo='bar')
rendered = tp.process_template(s)
self.assertEqual("bar", rendered)

def test_template_kwarg(self):
maindb = self.get_main_database(db.session)
s = "{{ foo }}"
tp = jinja_context.get_template_processor(database=maindb)
rendered = tp.process_template(s, foo='bar')
self.assertEqual("bar", rendered)

def test_templated_sql_json(self):
self.login('admin')
sql = "SELECT '{{ datetime(2017, 1, 1).isoformat() }}' as test"
Expand Down

0 comments on commit 5e43d07

Please sign in to comment.