This is an automated email from the ASF dual-hosted git repository.
beto pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push:
new 12fb8e7 Show Presto views as views, not tables (#8243)
12fb8e7 is described below
commit 12fb8e70cce262d8936ff686b6b746494f55fdb3
Author: Beto Dealmeida <[email protected]>
AuthorDate: Wed Sep 18 12:47:10 2019 -0700
Show Presto views as views, not tables (#8243)
* WIP
* Implement views in Presto
* Clean up
* Fix CSS
* Fix unit tests
* Add types to database
* Fix circular import
---
superset/assets/src/components/TableSelector.css | 3 ++
superset/assets/src/components/TableSelector.jsx | 2 +-
superset/db_engine_specs/base.py | 14 +++++++--
superset/db_engine_specs/postgres.py | 8 +++--
superset/db_engine_specs/presto.py | 40 ++++++++++++++++++++++--
superset/db_engine_specs/sqlite.py | 10 ++++--
superset/models/core.py | 4 +--
superset/views/core.py | 1 +
tests/db_engine_specs_test.py | 12 ++++---
9 files changed, 77 insertions(+), 17 deletions(-)
diff --git a/superset/assets/src/components/TableSelector.css
b/superset/assets/src/components/TableSelector.css
index f4098c1..078e57d 100644
--- a/superset/assets/src/components/TableSelector.css
+++ b/superset/assets/src/components/TableSelector.css
@@ -36,3 +36,6 @@
border-bottom: 1px solid #f2f2f2;
margin: 15px 0;
}
+.TableLabel {
+ white-space: nowrap;
+}
diff --git a/superset/assets/src/components/TableSelector.jsx
b/superset/assets/src/components/TableSelector.jsx
index d0785d6..1b83acc 100644
--- a/superset/assets/src/components/TableSelector.jsx
+++ b/superset/assets/src/components/TableSelector.jsx
@@ -221,7 +221,7 @@ export default class TableSelector extends
React.PureComponent {
onMouseEnter={() => focusOption(option)}
style={style}
>
- <span>
+ <span className="TableLabel">
<span className="m-r-5">
<small className="text-muted">
<i className={`fa fa-${option.type === 'view' ? 'eye' :
'table'}`} />
diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py
index b71966c..bd7b1d1 100644
--- a/superset/db_engine_specs/base.py
+++ b/superset/db_engine_specs/base.py
@@ -20,7 +20,7 @@ from datetime import datetime
import hashlib
import os
import re
-from typing import Any, Dict, List, NamedTuple, Optional, Tuple, Union
+from typing import Any, Dict, List, NamedTuple, Optional, Tuple,
TYPE_CHECKING, Union
from flask import g
from flask_babel import lazy_gettext as _
@@ -40,6 +40,10 @@ from werkzeug.utils import secure_filename
from superset import app, db, sql_parse
from superset.utils import core as utils
+if TYPE_CHECKING:
+ # prevent circular imports
+ from superset.models.core import Database
+
class TimeGrain(NamedTuple):
name: str # TODO: redundant field, remove
@@ -538,7 +542,9 @@ class BaseEngineSpec:
return sorted(inspector.get_schema_names())
@classmethod
- def get_table_names(cls, inspector: Inspector, schema: Optional[str]) ->
List[str]:
+ def get_table_names(
+ cls, database: "Database", inspector: Inspector, schema: Optional[str]
+ ) -> List[str]:
"""
Get all tables from schema
@@ -552,7 +558,9 @@ class BaseEngineSpec:
return sorted(tables)
@classmethod
- def get_view_names(cls, inspector: Inspector, schema: Optional[str]) ->
List[str]:
+ def get_view_names(
+ cls, database: "Database", inspector: Inspector, schema: Optional[str]
+ ) -> List[str]:
"""
Get all views from schema
diff --git a/superset/db_engine_specs/postgres.py
b/superset/db_engine_specs/postgres.py
index 4716b07..5b89880 100644
--- a/superset/db_engine_specs/postgres.py
+++ b/superset/db_engine_specs/postgres.py
@@ -16,12 +16,16 @@
# under the License.
# pylint: disable=C,R,W
from datetime import datetime
-from typing import List, Optional, Tuple
+from typing import List, Optional, Tuple, TYPE_CHECKING
from sqlalchemy.dialects.postgresql.base import PGInspector
from superset.db_engine_specs.base import BaseEngineSpec, LimitMethod
+if TYPE_CHECKING:
+ # prevent circular imports
+ from superset.models.core import Database
+
class PostgresBaseEngineSpec(BaseEngineSpec):
""" Abstract class for Postgres 'like' databases """
@@ -64,7 +68,7 @@ class PostgresEngineSpec(PostgresBaseEngineSpec):
@classmethod
def get_table_names(
- cls, inspector: PGInspector, schema: Optional[str]
+ cls, database: "Database", inspector: PGInspector, schema:
Optional[str]
) -> List[str]:
"""Need to consider foreign tables for PostgreSQL"""
tables = inspector.get_table_names(schema)
diff --git a/superset/db_engine_specs/presto.py
b/superset/db_engine_specs/presto.py
index 6e28bd1..ddc6442 100644
--- a/superset/db_engine_specs/presto.py
+++ b/superset/db_engine_specs/presto.py
@@ -23,7 +23,7 @@ import logging
import re
import textwrap
import time
-from typing import Any, cast, Dict, List, Optional, Set, Tuple
+from typing import Any, cast, Dict, List, Optional, Set, Tuple, TYPE_CHECKING
from urllib import parse
import simplejson as json
@@ -40,6 +40,10 @@ from superset.models.sql_types.presto_sql_types import
type_map as presto_type_m
from superset.sql_parse import ParsedQuery
from superset.utils import core as utils
+if TYPE_CHECKING:
+ # prevent circular imports
+ from superset.models.core import Database
+
QueryStatus = utils.QueryStatus
config = app.config
@@ -128,14 +132,44 @@ class PrestoEngineSpec(BaseEngineSpec):
return version is not None and StrictVersion(version) >=
StrictVersion("0.319")
@classmethod
- def get_view_names(cls, inspector: Inspector, schema: Optional[str]) ->
List[str]:
+ def get_table_names(
+ cls, database: "Database", inspector: Inspector, schema: Optional[str]
+ ) -> List[str]:
+ tables = super().get_table_names(database, inspector, schema)
+ if not is_feature_enabled("PRESTO_SPLIT_VIEWS_FROM_TABLES"):
+ return tables
+
+ views = set(cls.get_view_names(database, inspector, schema))
+ actual_tables = set(tables) - views
+ return list(actual_tables)
+
+ @classmethod
+ def get_view_names(
+ cls, database: "Database", inspector: Inspector, schema: Optional[str]
+ ) -> List[str]:
"""Returns an empty list
get_table_names() function returns all table names and view names,
and get_view_names() is not implemented in sqlalchemy_presto.py
https://github.com/dropbox/PyHive/blob/e25fc8440a0686bbb7a5db5de7cb1a77bdb4167a/pyhive/sqlalchemy_presto.py
"""
- return []
+ if not is_feature_enabled("PRESTO_SPLIT_VIEWS_FROM_TABLES"):
+ return []
+
+ if schema:
+ sql = "SELECT table_name FROM information_schema.views WHERE
table_schema=%(schema)s"
+ params = {"schema": schema}
+ else:
+ sql = "SELECT table_name FROM information_schema.views"
+ params = {}
+
+ engine = cls.get_engine(database, schema=schema)
+ with closing(engine.raw_connection()) as conn:
+ with closing(conn.cursor()) as cursor:
+ cursor.execute(sql, params)
+ results = cursor.fetchall()
+
+ return [row[0] for row in results]
@classmethod
def _create_column_info(cls, name: str, data_type: str) -> dict:
diff --git a/superset/db_engine_specs/sqlite.py
b/superset/db_engine_specs/sqlite.py
index 28c8843..ff7074b 100644
--- a/superset/db_engine_specs/sqlite.py
+++ b/superset/db_engine_specs/sqlite.py
@@ -16,13 +16,17 @@
# under the License.
# pylint: disable=C,R,W
from datetime import datetime
-from typing import List
+from typing import List, TYPE_CHECKING
from sqlalchemy.engine.reflection import Inspector
from superset.db_engine_specs.base import BaseEngineSpec
from superset.utils import core as utils
+if TYPE_CHECKING:
+ # prevent circular imports
+ from superset.models.core import Database
+
class SqliteEngineSpec(BaseEngineSpec):
engine = "sqlite"
@@ -79,6 +83,8 @@ class SqliteEngineSpec(BaseEngineSpec):
return "'{}'".format(iso)
@classmethod
- def get_table_names(cls, inspector: Inspector, schema: str) -> List[str]:
+ def get_table_names(
+ cls, database: "Database", inspector: Inspector, schema: str
+ ) -> List[str]:
"""Need to disregard the schema for Sqlite"""
return sorted(inspector.get_table_names())
diff --git a/superset/models/core.py b/superset/models/core.py
index b31fb67..200af49 100755
--- a/superset/models/core.py
+++ b/superset/models/core.py
@@ -1063,7 +1063,7 @@ class Database(Model, AuditMixinNullable, ImportMixin):
"""
try:
tables = self.db_engine_spec.get_table_names(
- inspector=self.inspector, schema=schema
+ database=self, inspector=self.inspector, schema=schema
)
return [
utils.DatasourceName(table=table, schema=schema) for table in
tables
@@ -1097,7 +1097,7 @@ class Database(Model, AuditMixinNullable, ImportMixin):
"""
try:
views = self.db_engine_spec.get_view_names(
- inspector=self.inspector, schema=schema
+ database=self, inspector=self.inspector, schema=schema
)
return [utils.DatasourceName(table=view, schema=schema) for view
in views]
except Exception as e:
diff --git a/superset/views/core.py b/superset/views/core.py
index 36fb3ca..ad6c3ba 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -1572,6 +1572,7 @@ class Superset(BaseSupersetView):
for vn in views[:max_views]
]
)
+ table_options.sort(key=lambda value: value["label"])
payload = {"tableLength": len(tables) + len(views), "options":
table_options}
return json_success(json.dumps(payload))
diff --git a/tests/db_engine_specs_test.py b/tests/db_engine_specs_test.py
index f6354c0..ec6ff24 100644
--- a/tests/db_engine_specs_test.py
+++ b/tests/db_engine_specs_test.py
@@ -342,7 +342,9 @@ class DbEngineSpecsTestCase(SupersetTestCase):
self.assertSetEqual(defined_grains, intersection, engine)
def test_presto_get_view_names_return_empty_list(self):
- self.assertEquals([], PrestoEngineSpec.get_view_names(mock.ANY,
mock.ANY))
+ self.assertEquals(
+ [], PrestoEngineSpec.get_view_names(mock.ANY, mock.ANY, mock.ANY)
+ )
def verify_presto_column(self, column, expected_results):
inspector = mock.Mock()
@@ -877,7 +879,9 @@ class DbEngineSpecsTestCase(SupersetTestCase):
self.assertEqual("SELECT \nWHERE ds = '01-01-19' AND hour = 1",
query_result)
def test_hive_get_view_names_return_empty_list(self):
- self.assertEquals([], HiveEngineSpec.get_view_names(mock.ANY,
mock.ANY))
+ self.assertEquals(
+ [], HiveEngineSpec.get_view_names(mock.ANY, mock.ANY, mock.ANY)
+ )
def test_bigquery_sqla_column_label(self):
label = BigQueryEngineSpec.make_label_compatible(column("Col").name)
@@ -952,7 +956,7 @@ class DbEngineSpecsTestCase(SupersetTestCase):
ie. when try_remove_schema_from_table_name == True. """
base_result_expected = ["table", "table_2"]
base_result = BaseEngineSpec.get_table_names(
- schema="schema", inspector=inspector
+ database=mock.ANY, schema="schema", inspector=inspector
)
self.assertListEqual(base_result_expected, base_result)
@@ -960,7 +964,7 @@ class DbEngineSpecsTestCase(SupersetTestCase):
ie. when try_remove_schema_from_table_name == False. """
pg_result_expected = ["schema.table", "table_2", "table_3"]
pg_result = PostgresEngineSpec.get_table_names(
- schema="schema", inspector=inspector
+ database=mock.ANY, schema="schema", inspector=inspector
)
self.assertListEqual(pg_result_expected, pg_result)