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

[Bugfix] Remove prequery properties from query_obj #7896

Merged
merged 6 commits into from
Jul 23, 2019
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
6 changes: 0 additions & 6 deletions superset/common/query_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ def __init__(
timeseries_limit_metric: Optional[Dict] = None,
order_desc: bool = True,
extras: Optional[Dict] = None,
prequeries: Optional[List[Dict]] = None,
is_prequery: bool = False,
columns: List[str] = None,
orderby: List[List] = None,
relative_start: str = app.config.get("DEFAULT_RELATIVE_START_TIME", "today"),
Expand Down Expand Up @@ -78,8 +76,6 @@ def __init__(
self.timeseries_limit = timeseries_limit
self.timeseries_limit_metric = timeseries_limit_metric
self.order_desc = order_desc
self.prequeries = prequeries if prequeries is not None else []
self.is_prequery = is_prequery
self.extras = extras if extras is not None else {}
self.columns = columns if columns is not None else []
self.orderby = orderby if orderby is not None else []
Expand All @@ -97,8 +93,6 @@ def to_dict(self):
"timeseries_limit": self.timeseries_limit,
"timeseries_limit_metric": self.timeseries_limit_metric,
"order_desc": self.order_desc,
"prequeries": self.prequeries,
"is_prequery": self.is_prequery,
"extras": self.extras,
"columns": self.columns,
"orderby": self.orderby,
Expand Down
2 changes: 0 additions & 2 deletions superset/connectors/druid/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1120,8 +1120,6 @@ def run_query( # noqa / druid
phase=2,
client=None,
order_desc=True,
prequeries=None,
is_prequery=False,
):
"""Runs a query against Druid and returns a dataframe.
"""
Expand Down
61 changes: 32 additions & 29 deletions superset/connectors/sqla/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
# specific language governing permissions and limitations
# under the License.
# pylint: disable=C,R,W
from collections import namedtuple, OrderedDict
from collections import OrderedDict
from datetime import datetime
import logging
from typing import Any, List, Optional, Union
from typing import Any, List, NamedTuple, Optional, Union

from flask import escape, Markup
from flask_appbuilder import Model
Expand All @@ -45,7 +45,7 @@
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.schema import UniqueConstraint
from sqlalchemy.sql import column, literal_column, table, text
from sqlalchemy.sql.expression import Label, TextAsFrom
from sqlalchemy.sql.expression import Label, Select, TextAsFrom
import sqlparse

from superset import app, db, security_manager
Expand All @@ -61,10 +61,18 @@
config = app.config
metadata = Model.metadata # pylint: disable=no-member

SqlaQuery = namedtuple(
"SqlaQuery", ["sqla_query", "labels_expected", "extra_cache_keys"]
)
QueryStringExtended = namedtuple("QueryStringExtended", ["sql", "labels_expected"])

class SqlaQuery(NamedTuple):
Copy link
Member

Choose a reason for hiding this comment

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

Oh wow, the new NamedTuple are so much better, always hated the way the old ones were delcared...

extra_cache_keys: List[Any]
labels_expected: List[str]
prequeries: List[str]
sqla_query: Select


class QueryStringExtended(NamedTuple):
labels_expected: List[str]
prequeries: List[str]
sql: str


class AnnotationDatasource(BaseDatasource):
Expand Down Expand Up @@ -351,7 +359,7 @@ def make_sqla_column_compatible(self, sqla_col, label=None):
"""
label_expected = label or sqla_col.name
db_engine_spec = self.database.db_engine_spec
if db_engine_spec.supports_column_aliases:
if db_engine_spec.allows_column_aliases:
label = db_engine_spec.make_label_compatible(label_expected)
sqla_col = sqla_col.label(label)
sqla_col._df_label_expected = label_expected
Expand Down Expand Up @@ -532,18 +540,20 @@ def mutate_query_from_config(self, sql):
def get_template_processor(self, **kwargs):
return get_template_processor(table=self, database=self.database, **kwargs)

def get_query_str_extended(self, query_obj):
def get_query_str_extended(self, query_obj) -> QueryStringExtended:
sqlaq = self.get_sqla_query(**query_obj)
sql = self.database.compile_sqla_query(sqlaq.sqla_query)
logging.info(sql)
sql = sqlparse.format(sql, reindent=True)
if query_obj["is_prequery"]:
query_obj["prequeries"].append(sql)
sql = self.mutate_query_from_config(sql)
return QueryStringExtended(labels_expected=sqlaq.labels_expected, sql=sql)
return QueryStringExtended(
labels_expected=sqlaq.labels_expected, sql=sql, prequeries=sqlaq.prequeries
)

def get_query_str(self, query_obj):
return self.get_query_str_extended(query_obj).sql
query_str_ext = self.get_query_str_extended(query_obj)
all_queries = query_str_ext.prequeries + [query_str_ext.sql]
return ";\n\n".join(all_queries) + ";"

def get_sqla_table(self):
tbl = table(self.table_name)
Expand Down Expand Up @@ -606,8 +616,6 @@ def get_sqla_query( # sqla
extras=None,
columns=None,
order_desc=True,
prequeries=None,
is_prequery=False,
):
"""Querying any sqla table from this common interface"""
template_kwargs = {
Expand All @@ -624,6 +632,7 @@ def get_sqla_query( # sqla
template_kwargs["extra_cache_keys"] = extra_cache_keys
template_processor = self.get_template_processor(**template_kwargs)
db_engine_spec = self.database.db_engine_spec
prequeries: List[str] = []

orderby = orderby or []

Expand Down Expand Up @@ -793,7 +802,7 @@ def get_sqla_query( # sqla
qry = qry.limit(row_limit)

if is_timeseries and timeseries_limit and groupby and not time_groupby_inline:
if self.database.db_engine_spec.inner_joins:
if self.database.db_engine_spec.allows_joins:
# some sql dialects require for order by expressions
# to also be in the select clause -- others, e.g. vertica,
# require a unique inner alias
Expand Down Expand Up @@ -844,10 +853,8 @@ def get_sqla_query( # sqla
)
]

# run subquery to get top groups
subquery_obj = {
"prequeries": prequeries,
"is_prequery": True,
# run prequery to get top groups
prequery_obj = {
"is_timeseries": False,
"row_limit": timeseries_limit,
"groupby": groupby,
Expand All @@ -861,7 +868,8 @@ def get_sqla_query( # sqla
"columns": columns,
"order_desc": True,
}
result = self.query(subquery_obj)
result = self.query(prequery_obj)
prequeries.append(result.query)
dimensions = [
c
for c in result.df.columns
Expand All @@ -873,9 +881,10 @@ def get_sqla_query( # sqla
qry = qry.where(top_groups)

return SqlaQuery(
sqla_query=qry.select_from(tbl),
labels_expected=labels_expected,
extra_cache_keys=extra_cache_keys,
labels_expected=labels_expected,
sqla_query=qry.select_from(tbl),
prequeries=prequeries,
)

def _get_timeseries_orderby(self, timeseries_limit_metric, metrics_dict, cols):
Expand Down Expand Up @@ -929,12 +938,6 @@ def mutator(df):
db_engine_spec = self.database.db_engine_spec
error_message = db_engine_spec.extract_error_message(e)

# if this is a main query with prequeries, combine them together
if not query_obj["is_prequery"]:
query_obj["prequeries"].append(sql)
sql = ";\n\n".join(query_obj["prequeries"])
sql += ";"

return QueryResult(
status=status,
df=df,
Expand Down
6 changes: 3 additions & 3 deletions superset/db_engine_specs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ class BaseEngineSpec(object):
time_groupby_inline = False
limit_method = LimitMethod.FORCE_LIMIT
time_secondary_columns = False
inner_joins = True
allows_subquery = True
supports_column_aliases = True
allows_joins = True
allows_subqueries = True
allows_column_aliases = True
force_column_alias_quotes = False
arraysize = 0
max_column_name_length = 0
Expand Down
4 changes: 2 additions & 2 deletions superset/db_engine_specs/druid.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class DruidEngineSpec(BaseEngineSpec):
"""Engine spec for Druid.io"""

engine = "druid"
inner_joins = False
allows_subquery = True
allows_joins = False
allows_subqueries = True

time_grain_functions = {
None: "{col}",
Expand Down
4 changes: 2 additions & 2 deletions superset/db_engine_specs/gsheets.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ class GSheetsEngineSpec(SqliteEngineSpec):
"""Engine for Google spreadsheets"""

engine = "gsheets"
inner_joins = False
allows_subquery = False
allows_joins = False
allows_subqueries = False
6 changes: 3 additions & 3 deletions superset/db_engine_specs/pinot.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@

class PinotEngineSpec(BaseEngineSpec):
engine = "pinot"
allows_subquery = False
inner_joins = False
supports_column_aliases = False
allows_subqueries = False
allows_joins = False
allows_column_aliases = False

# Pinot does its own conversion below
time_grain_functions: Dict[Optional[str], str] = {
Expand Down
2 changes: 1 addition & 1 deletion superset/models/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,7 @@ def name(self):

@property
def allows_subquery(self):
return self.db_engine_spec.allows_subquery
return self.db_engine_spec.allows_subqueries

@property
def data(self):
Expand Down
7 changes: 1 addition & 6 deletions superset/views/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1350,12 +1350,7 @@ def get_query_string_response(self, viz_obj):
logging.exception(e)
return json_error_response(e)

if query_obj and query_obj["prequeries"]:
query_obj["prequeries"].append(query)
query = ";\n\n".join(query_obj["prequeries"])
if query:
query += ";"
else:
if not query:
query = "No query."

return self.json_response(
Expand Down
2 changes: 0 additions & 2 deletions superset/viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,6 @@ def query_obj(self):
"extras": extras,
"timeseries_limit_metric": timeseries_limit_metric,
"order_desc": order_desc,
"prequeries": [],
"is_prequery": False,
}
return d

Expand Down
13 changes: 4 additions & 9 deletions tests/model_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,11 @@ def query_with_expr_helper(self, is_timeseries, inner_join=True):
ds_col.expression = None
ds_col.python_date_format = None
spec = self.get_database_by_id(tbl.database_id).db_engine_spec
if not spec.inner_joins and inner_join:
if not spec.allows_joins and inner_join:
# if the db does not support inner joins, we cannot force it so
return None
old_inner_join = spec.inner_joins
spec.inner_joins = inner_join
old_inner_join = spec.allows_joins
spec.allows_joins = inner_join
arbitrary_gby = "state || gender || '_test'"
arbitrary_metric = dict(
label="arbitrary", expressionType="SQL", sqlExpression="COUNT(1)"
Expand All @@ -209,12 +209,10 @@ def query_with_expr_helper(self, is_timeseries, inner_join=True):
metrics=[arbitrary_metric],
filter=[],
is_timeseries=is_timeseries,
prequeries=[],
columns=[],
granularity="ds",
from_dttm=None,
to_dttm=None,
is_prequery=False,
extras=dict(time_grain_sqla="P1Y"),
)
qr = tbl.query(query_obj)
Expand All @@ -226,7 +224,7 @@ def query_with_expr_helper(self, is_timeseries, inner_join=True):
self.assertIn("JOIN", sql.upper())
else:
self.assertNotIn("JOIN", sql.upper())
spec.inner_joins = old_inner_join
spec.allows_joins = old_inner_join
self.assertIsNotNone(qr.df)
return qr.df

Expand Down Expand Up @@ -258,7 +256,6 @@ def test_sql_mutator(self):
granularity=None,
from_dttm=None,
to_dttm=None,
is_prequery=False,
extras={},
)
sql = tbl.get_query_str(query_obj)
Expand All @@ -285,7 +282,6 @@ def test_query_with_non_existent_metrics(self):
granularity=None,
from_dttm=None,
to_dttm=None,
is_prequery=False,
extras={},
)

Expand All @@ -306,7 +302,6 @@ def test_query_with_non_existent_filter_columns(self):
granularity=None,
from_dttm=None,
to_dttm=None,
is_prequery=False,
extras={},
)

Expand Down
1 change: 0 additions & 1 deletion tests/sqla_models_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ def test_cache_key_wrapper(self):
"metrics": [],
"is_timeseries": False,
"filter": [],
"is_prequery": False,
"extras": {"where": "(user != '{{ cache_key_wrapper('user_2') }}')"},
}
extra_cache_keys = table.get_extra_cache_keys(query_obj)
Expand Down