-
Notifications
You must be signed in to change notification settings - Fork 14.1k
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
fix: create virtual table with exotic type #19714
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,13 +15,11 @@ | |
# specific language governing permissions and limitations | ||
# under the License. | ||
from contextlib import closing | ||
from datetime import date, datetime, time, timedelta | ||
from typing import Callable, Dict, List, Optional, Set, TYPE_CHECKING | ||
from typing import Any, Callable, Dict, List, Optional, Set, TYPE_CHECKING | ||
|
||
import sqlparse | ||
from flask_babel import lazy_gettext as _ | ||
from sqlalchemy import and_, inspect, or_ | ||
from sqlalchemy.engine import Engine | ||
from sqlalchemy import and_, or_ | ||
from sqlalchemy.exc import NoSuchTableError | ||
from sqlalchemy.orm import Session | ||
from sqlalchemy.sql.type_api import TypeEngine | ||
|
@@ -42,14 +40,11 @@ | |
from superset.connectors.sqla.models import SqlaTable | ||
|
||
|
||
TEMPORAL_TYPES = {date, datetime, time, timedelta} | ||
|
||
|
||
def get_physical_table_metadata( | ||
database: Database, | ||
table_name: str, | ||
schema_name: Optional[str] = None, | ||
) -> List[Dict[str, str]]: | ||
) -> List[Dict[str, Any]]: | ||
"""Use SQLAlchemy inspector to get table metadata""" | ||
db_engine_spec = database.db_engine_spec | ||
db_dialect = database.get_dialect() | ||
|
@@ -86,7 +81,7 @@ def get_physical_table_metadata( | |
col.update( | ||
{ | ||
"type": "UNKNOWN", | ||
"generic_type": None, | ||
"type_generic": None, | ||
"is_dttm": None, | ||
} | ||
) | ||
|
@@ -173,20 +168,12 @@ def validate_adhoc_subquery( | |
return ";\n".join(str(statement) for statement in statements) | ||
|
||
|
||
def is_column_type_temporal(column_type: TypeEngine) -> bool: | ||
try: | ||
return column_type.python_type in TEMPORAL_TYPES | ||
except NotImplementedError: | ||
return False | ||
|
||
|
||
def load_or_create_tables( # pylint: disable=too-many-arguments | ||
session: Session, | ||
database_id: int, | ||
database: Database, | ||
default_schema: Optional[str], | ||
tables: Set[Table], | ||
conditional_quote: Callable[[str], str], | ||
engine: Engine, | ||
) -> List[NewTable]: | ||
""" | ||
Load or create new table model instances. | ||
|
@@ -206,7 +193,7 @@ def load_or_create_tables( # pylint: disable=too-many-arguments | |
predicate = or_( | ||
*[ | ||
and_( | ||
NewTable.database_id == database_id, | ||
NewTable.database_id == database.id, | ||
NewTable.schema == table.schema, | ||
NewTable.name == table.table, | ||
) | ||
|
@@ -220,9 +207,10 @@ def load_or_create_tables( # pylint: disable=too-many-arguments | |
for table in tables: | ||
if (table.schema, table.table) not in existing: | ||
try: | ||
inspector = inspect(engine) | ||
column_metadata = inspector.get_columns( | ||
table.table, schema=table.schema | ||
column_metadata = get_physical_table_metadata( | ||
database=database, | ||
table_name=table.table, | ||
schema_name=table.schema, | ||
) | ||
except Exception: # pylint: disable=broad-except | ||
continue | ||
|
@@ -231,7 +219,7 @@ def load_or_create_tables( # pylint: disable=too-many-arguments | |
name=column["name"], | ||
type=str(column["type"]), | ||
expression=conditional_quote(column["name"]), | ||
is_temporal=is_column_type_temporal(column["type"]), | ||
is_temporal=column["is_dttm"], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The previous version checked for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes - this one is actually based on what the db engine spec says is temporal, so it's much more comprehensive (=can be customized per database). |
||
is_aggregation=False, | ||
is_physical=True, | ||
is_spatial=False, | ||
|
@@ -245,7 +233,7 @@ def load_or_create_tables( # pylint: disable=too-many-arguments | |
name=table.table, | ||
schema=table.schema, | ||
catalog=None, | ||
database_id=database_id, | ||
database_id=database.id, | ||
columns=columns, | ||
) | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was a bycatch (see line 79/76 above with the correct key) when I worked on adding proper
TypedDict
s for these objects (opening up separate PR for that one, but I thought it worthwhile to fix this error right away).