From 7bf19b12327504aec2be2c2fd36404efb1faec05 Mon Sep 17 00:00:00 2001 From: Maxime Beauchemin Date: Fri, 24 Mar 2017 09:23:25 -0700 Subject: [PATCH] [WiP] making doubling '%' not required (#2459) * Making doubling '%' not required Now passing the sqlalchemy query object to pandas's read_sql_query * Fix test/lint --- superset/connectors/druid/models.py | 5 +++-- superset/connectors/sqla/models.py | 30 ++++++++++++++--------------- superset/db_engine_specs.py | 4 ---- superset/views/core.py | 5 +---- 4 files changed, 19 insertions(+), 25 deletions(-) diff --git a/superset/connectors/druid/models.py b/superset/connectors/druid/models.py index 09c03c268..6f7473203 100644 --- a/superset/connectors/druid/models.py +++ b/superset/connectors/druid/models.py @@ -722,7 +722,7 @@ class DruidDatasource(Model, BaseDatasource): return [row[0] for row in df.to_records(index=False)] def get_query_str( # noqa / druid - self, client, qry_start_dttm, + self, groupby, metrics, granularity, from_dttm, to_dttm, @@ -741,6 +741,7 @@ class DruidDatasource(Model, BaseDatasource): This query interface is common to SqlAlchemy and Druid """ # TODO refactor into using a TBD Query object + client = self.cluster.get_pydruid_client() if not is_timeseries: granularity = 'all' inner_from_dttm = inner_from_dttm or from_dttm @@ -941,7 +942,7 @@ class DruidDatasource(Model, BaseDatasource): def query(self, query_obj): qry_start_dttm = datetime.now() client = self.cluster.get_pydruid_client() - query_str = self.get_query_str(client, qry_start_dttm, **query_obj) + query_str = self.get_query_str(**query_obj) df = client.export_pandas() if df is None or df.size == 0: diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index 7d213c142..1e1e28da7 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -322,8 +322,16 @@ class SqlaTable(Model, BaseDatasource): return get_template_processor( table=self, database=self.database, **kwargs) - def get_query_str( # sqla - self, engine, qry_start_dttm, + def get_query_str(self, **kwargs): + qry = self.get_sqla_query(**kwargs) + sql = str(qry.compile(kwargs['engine'])) + logging.info(sql) + sql = sqlparse.format(sql, reindent=True) + sql = self.database.db_engine_spec.sql_preprocessor(sql) + return sql + + def get_sqla_query( # sqla + self, groupby, metrics, granularity, from_dttm, to_dttm, @@ -472,8 +480,7 @@ class SqlaTable(Model, BaseDatasource): elif op == '<=': where_clause_and.append(col_obj.sqla_col <= eq) elif op == 'LIKE': - where_clause_and.append( - col_obj.sqla_col.like(eq.replace('%', '%%'))) + where_clause_and.append(col_obj.sqla_col.like(eq)) if extras: where = extras.get('where') if where: @@ -523,25 +530,18 @@ class SqlaTable(Model, BaseDatasource): tbl = tbl.join(subq.alias(), and_(*on_clause)) - qry = qry.select_from(tbl) - - sql = "{}".format( - qry.compile( - engine, compile_kwargs={"literal_binds": True},), - ) - logging.info(sql) - sql = sqlparse.format(sql, reindent=True) - return sql + return qry.select_from(tbl) def query(self, query_obj): qry_start_dttm = datetime.now() engine = self.database.get_sqla_engine() - sql = self.get_query_str(engine, qry_start_dttm, **query_obj) + qry = self.get_sqla_query(**query_obj) + sql = str(qry) status = QueryStatus.SUCCESS error_message = None df = None try: - df = pd.read_sql_query(sql, con=engine) + df = pd.read_sql_query(qry, con=engine) except Exception as e: status = QueryStatus.FAILED error_message = str(e) diff --git a/superset/db_engine_specs.py b/superset/db_engine_specs.py index 4370de7e4..203e67f82 100644 --- a/superset/db_engine_specs.py +++ b/superset/db_engine_specs.py @@ -279,10 +279,6 @@ class PrestoEngineSpec(BaseEngineSpec): from superset.db_engines import presto as patched_presto presto.Cursor.cancel = patched_presto.cancel - @classmethod - def sql_preprocessor(cls, sql): - return sql.replace('%', '%%') - @classmethod def convert_dttm(cls, target_type, dttm): tt = target_type.upper() diff --git a/superset/views/core.py b/superset/views/core.py index 2673b2024..f077e481c 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -983,14 +983,11 @@ class Superset(BaseSupersetView): if request.args.get("query") == "true": try: query_obj = viz_obj.query_obj() - engine = viz_obj.datasource.database.get_sqla_engine() \ - if datasource_type == 'table' \ - else viz_obj.datasource.cluster.get_pydruid_client() if datasource_type == 'druid': # only retrive first phase query for druid query_obj['phase'] = 1 query = viz_obj.datasource.get_query_str( - engine, datetime.now(), **query_obj) + datetime.now(), **query_obj) except Exception as e: return json_error_response(e) return Response(