未验证 提交 0a3b1212 编写于 作者: J John Bodley 提交者: GitHub

[sql] Fixing datetime SQL literal (#8464)

上级 7afda6e4
......@@ -220,19 +220,27 @@ class TableColumn(Model, BaseColumn):
def dttm_sql_literal(self, dttm: DateTime) -> str:
"""Convert datetime object to a SQL expression string"""
sql = (
self.table.database.db_engine_spec.convert_dttm(self.type, dttm)
if self.type
else None
)
if sql:
return sql
tf = self.python_date_format
if tf:
seconds_since_epoch = int(dttm.timestamp())
if tf == "epoch_s":
return str(seconds_since_epoch)
elif tf == "epoch_ms":
if tf in ["epoch_ms", "epoch_s"]:
seconds_since_epoch = int(dttm.timestamp())
if tf == "epoch_s":
return str(seconds_since_epoch)
return str(seconds_since_epoch * 1000)
return "'{}'".format(dttm.strftime(tf))
else:
s = self.table.database.db_engine_spec.convert_dttm(self.type or "", dttm)
return f"'{dttm.strftime(tf)}'"
# TODO(john-bodley): SIP-15 will explicitly require a type conversion.
return s or "'{}'".format(dttm.strftime("%Y-%m-%d %H:%M:%S.%f"))
# TODO(john-bodley): SIP-15 will explicitly require a type conversion.
return f"""'{dttm.strftime("%Y-%m-%d %H:%M:%S.%f")}'"""
class SqlMetric(Model, BaseMetric):
......
......@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
from datetime import datetime
from typing import Optional
from superset.db_engine_specs.base import BaseEngineSpec
......@@ -39,13 +40,13 @@ class AthenaEngineSpec(BaseEngineSpec):
}
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return "from_iso8601_date('{}')".format(dttm.isoformat()[:10])
return f"from_iso8601_date('{dttm.date().isoformat()}')"
if tt == "TIMESTAMP":
return "from_iso8601_timestamp('{}')".format(dttm.isoformat())
return "CAST ('{}' AS TIMESTAMP)".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return f"""from_iso8601_timestamp('{dttm.isoformat(timespec="microseconds")}')""" # pylint: disable=line-too-long
return None
@classmethod
def epoch_to_dttm(cls) -> str:
......
......@@ -439,15 +439,15 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
db.session.commit()
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
"""
Convert DateTime object to sql expression
Convert Python datetime object to a SQL expression
:param target_type: Target type of expression
:param dttm: DateTime object
:return: SQL expression
:param target_type: The target type of expression
:param dttm: The datetime object
:return: The SQL expression
"""
return "'{}'".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return None
@classmethod
def get_all_datasource_names(
......
......@@ -17,7 +17,7 @@
import hashlib
import re
from datetime import datetime
from typing import Any, Dict, List, Tuple
from typing import Any, Dict, List, Optional, Tuple
import pandas as pd
from sqlalchemy import literal_column
......@@ -72,11 +72,15 @@ class BigQueryEngineSpec(BaseEngineSpec):
}
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return "'{}'".format(dttm.strftime("%Y-%m-%d"))
return "'{}'".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return f"CAST('{dttm.date().isoformat()}' AS DATE)"
if tt == "DATETIME":
return f"""CAST('{dttm.isoformat(timespec="microseconds")}' AS DATETIME)"""
if tt == "TIMESTAMP":
return f"""CAST('{dttm.isoformat(timespec="microseconds")}' AS TIMESTAMP)"""
return None
@classmethod
def fetch_data(cls, cursor, limit: int) -> List[Tuple]:
......
......@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
from datetime import datetime
from typing import Optional
from superset.db_engine_specs.base import BaseEngineSpec
......@@ -43,10 +44,10 @@ class ClickHouseEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method
}
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return "toDate('{}')".format(dttm.strftime("%Y-%m-%d"))
return f"toDate('{dttm.date().isoformat()}')"
if tt == "DATETIME":
return "toDateTime('{}')".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return "'{}'".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return f"""toDateTime('{dttm.isoformat(sep=" ", timespec="seconds")}')"""
return None
......@@ -14,8 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from datetime import datetime
from superset.db_engine_specs.base import BaseEngineSpec, LimitMethod
......@@ -51,7 +49,3 @@ class Db2EngineSpec(BaseEngineSpec):
@classmethod
def epoch_to_dttm(cls) -> str:
return "(TIMESTAMP('1970-01-01', '00:00:00') + {col} SECONDS)"
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
return "'{}'".format(dttm.strftime("%Y-%m-%d-%H.%M.%S"))
......@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
from datetime import datetime
from typing import Optional
from urllib import parse
from superset.db_engine_specs.base import BaseEngineSpec
......@@ -49,13 +50,13 @@ class DrillEngineSpec(BaseEngineSpec):
return "TO_DATE({col})"
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return "CAST('{}' AS DATE)".format(dttm.isoformat()[:10])
return f"TO_DATE('{dttm.date().isoformat()}', 'yyyy-MM-dd')"
elif tt == "TIMESTAMP":
return "CAST('{}' AS TIMESTAMP)".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return "'{}'".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return f"""TO_TIMESTAMP('{dttm.isoformat(sep=" ", timespec="seconds")}', 'yyyy-MM-dd HH:mm:ss')""" # pylint: disable=line-too-long
return None
@classmethod
def adjust_database_uri(cls, uri, selected_schema):
......
......@@ -16,7 +16,7 @@
# under the License.
# pylint: disable=C,R,W
from datetime import datetime
from typing import Dict
from typing import Dict, Optional
from superset.db_engine_specs.base import BaseEngineSpec
......@@ -41,7 +41,7 @@ class ElasticSearchEngineSpec(BaseEngineSpec):
type_code_map: Dict[int, str] = {} # loaded from get_datatype only if needed
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
if target_type.upper() in ("DATETIME", "DATE"):
return f"'{dttm.isoformat()}'"
return f"'{dttm.strftime('%Y-%m-%d %H:%M:%S')}'"
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
if target_type.upper() == "DATETIME":
return f"""CAST('{dttm.isoformat(timespec="seconds")}' AS DATETIME)"""
return None
......@@ -179,13 +179,13 @@ class HiveEngineSpec(PrestoEngineSpec):
engine.execute(sql)
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return "CAST('{}' AS DATE)".format(dttm.isoformat()[:10])
return f"CAST('{dttm.date().isoformat()}' AS DATE)"
elif tt == "TIMESTAMP":
return "CAST('{}' AS TIMESTAMP)".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return "'{}'".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return f"""CAST('{dttm.isoformat(sep=" ", timespec="microseconds")}' AS TIMESTAMP)""" # pylint: disable=line-too-long
return None
@classmethod
def adjust_database_uri(cls, uri, selected_schema=None):
......
......@@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.
from datetime import datetime
from typing import List
from typing import List, Optional
from sqlalchemy.engine.reflection import Inspector
......@@ -43,11 +43,13 @@ class ImpalaEngineSpec(BaseEngineSpec):
return "from_unixtime({col})"
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return "'{}'".format(dttm.strftime("%Y-%m-%d"))
return "'{}'".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return f"CAST('{dttm.date().isoformat()}' AS DATE)"
elif tt == "TIMESTAMP":
return f"""CAST('{dttm.isoformat(timespec="microseconds")}' AS TIMESTAMP)"""
return None
@classmethod
def get_schema_names(cls, inspector: Inspector) -> List[str]:
......
......@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
from datetime import datetime
from typing import Optional
from superset.db_engine_specs.base import BaseEngineSpec
......@@ -39,10 +40,10 @@ class KylinEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method
}
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return "CAST('{}' AS DATE)".format(dttm.isoformat()[:10])
return f"CAST('{dttm.date().isoformat()}' AS DATE)"
if tt == "TIMESTAMP":
return "CAST('{}' AS TIMESTAMP)".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return "'{}'".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return f"""CAST('{dttm.isoformat(sep=" ", timespec="seconds")}' AS TIMESTAMP)""" # pylint: disable=line-too-long
return None
......@@ -50,8 +50,15 @@ class MssqlEngineSpec(BaseEngineSpec):
return "dateadd(S, {col}, '1970-01-01')"
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
return "CONVERT(DATETIME, '{}', 126)".format(dttm.isoformat())
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return f"CONVERT(DATE, '{dttm.date().isoformat()}', 23)"
if tt == "DATETIME":
return f"""CONVERT(DATETIME, '{dttm.isoformat(timespec="milliseconds")}', 126)""" # pylint: disable=line-too-long
if tt == "SMALLDATETIME":
return f"""CONVERT(SMALLDATETIME, '{dttm.isoformat(sep=" ", timespec="seconds")}', 20)""" # pylint: disable=line-too-long
return None
@classmethod
def fetch_data(cls, cursor, limit: int) -> List[Tuple]:
......
......@@ -50,12 +50,13 @@ class MySQLEngineSpec(BaseEngineSpec):
type_code_map: Dict[int, str] = {} # loaded from get_datatype only if needed
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
if target_type.upper() in ("DATETIME", "DATE"):
return "STR_TO_DATE('{}', '%Y-%m-%d %H:%i:%s')".format(
dttm.strftime("%Y-%m-%d %H:%M:%S")
)
return "'{}'".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return f"STR_TO_DATE('{dttm.date().isoformat()}', '%Y-%m-%d')"
if tt == "DATETIME":
return f"""STR_TO_DATE('{dttm.isoformat(sep=" ", timespec="microseconds")}', '%Y-%m-%d %H:%i:%s.%f')""" # pylint: disable=line-too-long
return None
@classmethod
def adjust_database_uri(cls, uri, selected_schema=None):
......
......@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
from datetime import datetime
from typing import Optional
from superset.db_engine_specs.base import LimitMethod
from superset.db_engine_specs.postgres import PostgresBaseEngineSpec
......@@ -39,7 +40,10 @@ class OracleEngineSpec(PostgresBaseEngineSpec):
}
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
return ("""TO_TIMESTAMP('{}', 'YYYY-MM-DD"T"HH24:MI:SS.ff6')""").format(
dttm.isoformat()
)
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return f"TO_DATE('{dttm.date().isoformat()}', 'YYYY-MM-DD')"
if tt == "TIMESTAMP":
return f"""TO_TIMESTAMP('{dttm.isoformat(timespec="microseconds")}', 'YYYY-MM-DD"T"HH24:MI:SS.ff6')""" # pylint: disable=line-too-long
return None
......@@ -55,10 +55,6 @@ class PostgresBaseEngineSpec(BaseEngineSpec):
def epoch_to_dttm(cls) -> str:
return "(timestamp 'epoch' + {col} * interval '1 second')"
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
return "'{}'".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
class PostgresEngineSpec(PostgresBaseEngineSpec):
engine = "postgresql"
......@@ -73,3 +69,12 @@ class PostgresEngineSpec(PostgresBaseEngineSpec):
tables = inspector.get_table_names(schema)
tables.extend(inspector.get_foreign_table_names(schema))
return sorted(tables)
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return f"TO_DATE('{dttm.date().isoformat()}', 'YYYY-MM-DD')"
if tt == "TIMESTAMP":
return f"""TO_TIMESTAMP('{dttm.isoformat(sep=" ", timespec="microseconds")}', 'YYYY-MM-DD HH24:MI:SS.US')""" # pylint: disable=line-too-long
return None
......@@ -520,13 +520,13 @@ class PrestoEngineSpec(BaseEngineSpec):
return uri
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
tt = target_type.upper()
if tt == "DATE":
return "from_iso8601_date('{}')".format(dttm.isoformat()[:10])
return f"""from_iso8601_date('{dttm.date().isoformat()}')"""
if tt == "TIMESTAMP":
return "from_iso8601_timestamp('{}')".format(dttm.isoformat())
return "'{}'".format(dttm.strftime("%Y-%m-%d %H:%M:%S"))
return f"""from_iso8601_timestamp('{dttm.isoformat(timespec="microseconds")}')""" # pylint: disable=line-too-long
return None
@classmethod
def epoch_to_dttm(cls) -> str:
......
......@@ -75,11 +75,10 @@ class SqliteEngineSpec(BaseEngineSpec):
raise Exception(f"Unsupported datasource_type: {datasource_type}")
@classmethod
def convert_dttm(cls, target_type: str, dttm: datetime) -> str:
iso = dttm.isoformat().replace("T", " ")
if "." not in iso:
iso += ".000000"
return "'{}'".format(iso)
def convert_dttm(cls, target_type: str, dttm: datetime) -> Optional[str]:
if target_type.upper() == "TEXT":
return f"""'{dttm.isoformat(sep=" ", timespec="microseconds")}'"""
return None
@classmethod
def get_table_names(
......
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from superset.db_engine_specs.athena import AthenaEngineSpec
from tests.db_engine_specs.base_tests import DbEngineSpecTestCase
class AthenaTestCase(DbEngineSpecTestCase):
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
AthenaEngineSpec.convert_dttm("DATE", dttm),
"from_iso8601_date('2019-01-02')",
)
self.assertEqual(
AthenaEngineSpec.convert_dttm("TIMESTAMP", dttm),
"from_iso8601_timestamp('2019-01-02T03:04:05.678900')",
)
......@@ -202,3 +202,7 @@ class DbEngineSpecsTests(DbEngineSpecTestCase):
else:
expected = ["VARCHAR(255)", "VARCHAR(255)", "FLOAT"]
self.assertEqual(col_names, expected)
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertIsNone(BaseEngineSpec.convert_dttm("", dttm))
......@@ -14,6 +14,8 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from datetime import datetime
from superset.db_engine_specs.mysql import MySQLEngineSpec
from superset.models.core import Database
from tests.base_tests import SupersetTestCase
......@@ -26,3 +28,6 @@ class DbEngineSpecTestCase(SupersetTestCase):
main = Database(database_name="test_database", sqlalchemy_uri="sqlite://")
limited = engine_spec_class.apply_limit_to_sql(sql, limit, main)
self.assertEqual(expected_sql, limited)
def get_dttm(self):
return datetime.strptime("2019-01-02 03:04:05.678900", "%Y-%m-%d %H:%M:%S.%f")
......@@ -37,3 +37,20 @@ class BigQueryTestCase(DbEngineSpecTestCase):
label = BigQueryEngineSpec.make_label_compatible(column("12345_col").name)
label_expected = "_12345_col_8d390"
self.assertEqual(label, label_expected)
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
BigQueryEngineSpec.convert_dttm("DATE", dttm), "CAST('2019-01-02' AS DATE)"
)
self.assertEqual(
BigQueryEngineSpec.convert_dttm("DATETIME", dttm),
"CAST('2019-01-02T03:04:05.678900' AS DATETIME)",
)
self.assertEqual(
BigQueryEngineSpec.convert_dttm("TIMESTAMP", dttm),
"CAST('2019-01-02T03:04:05.678900' AS TIMESTAMP)",
)
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from superset.db_engine_specs.clickhouse import ClickHouseEngineSpec
from tests.db_engine_specs.base_tests import DbEngineSpecTestCase
class ClickHouseTestCase(DbEngineSpecTestCase):
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
ClickHouseEngineSpec.convert_dttm("DATE", dttm), "toDate('2019-01-02')"
)
self.assertEqual(
ClickHouseEngineSpec.convert_dttm("DATETIME", dttm),
"toDateTime('2019-01-02 03:04:05')",
)
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from superset.db_engine_specs.drill import DrillEngineSpec
from tests.db_engine_specs.base_tests import DbEngineSpecTestCase
class DrillTestCase(DbEngineSpecTestCase):
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
DrillEngineSpec.convert_dttm("DATE", dttm),
"TO_DATE('2019-01-02', 'yyyy-MM-dd')",
)
self.assertEqual(
DrillEngineSpec.convert_dttm("TIMESTAMP", dttm),
"TO_TIMESTAMP('2019-01-02 03:04:05', 'yyyy-MM-dd HH:mm:ss')",
)
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from superset.db_engine_specs.elasticsearch import ElasticSearchEngineSpec
from tests.db_engine_specs.base_tests import DbEngineSpecTestCase
class ElasticSearchTestCase(DbEngineSpecTestCase):
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
ElasticSearchEngineSpec.convert_dttm("DATETIME", dttm),
"CAST('2019-01-02T03:04:05' AS DATETIME)",
)
......@@ -150,3 +150,15 @@ class HiveTests(DbEngineSpecTestCase):
self.assertEqual(
[], HiveEngineSpec.get_view_names(mock.ANY, mock.ANY, mock.ANY)
)
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
HiveEngineSpec.convert_dttm("DATE", dttm), "CAST('2019-01-02' AS DATE)"
)
self.assertEqual(
HiveEngineSpec.convert_dttm("TIMESTAMP", dttm),
"CAST('2019-01-02 03:04:05.678900' AS TIMESTAMP)",
)
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from superset.db_engine_specs.impala import ImpalaEngineSpec
from tests.db_engine_specs.base_tests import DbEngineSpecTestCase
class ImpalaTestCase(DbEngineSpecTestCase):
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
ImpalaEngineSpec.convert_dttm("DATE", dttm), "CAST('2019-01-02' AS DATE)"
)
self.assertEqual(
ImpalaEngineSpec.convert_dttm("TIMESTAMP", dttm),
"CAST('2019-01-02T03:04:05.678900' AS TIMESTAMP)",
)
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from superset.db_engine_specs.kylin import KylinEngineSpec
from tests.db_engine_specs.base_tests import DbEngineSpecTestCase
class KylinTestCase(DbEngineSpecTestCase):
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
KylinEngineSpec.convert_dttm("DATE", dttm), "CAST('2019-01-02' AS DATE)"
)
self.assertEqual(
KylinEngineSpec.convert_dttm("TIMESTAMP", dttm),
"CAST('2019-01-02 03:04:05' AS TIMESTAMP)",
)
......@@ -69,3 +69,21 @@ class MssqlEngineSpecTest(DbEngineSpecTestCase):
expr = MssqlEngineSpec.get_timestamp_expr(col, None, "P1Y")
result = str(expr.compile(None, dialect=mssql.dialect()))
self.assertEqual(result, "DATEADD(year, DATEDIFF(year, 0, [MixedCase]), 0)")
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
MssqlEngineSpec.convert_dttm("DATE", dttm),
"CONVERT(DATE, '2019-01-02', 23)",
)
self.assertEqual(
MssqlEngineSpec.convert_dttm("DATETIME", dttm),
"CONVERT(DATETIME, '2019-01-02T03:04:05.678', 126)",
)
self.assertEqual(
MssqlEngineSpec.convert_dttm("SMALLDATETIME", dttm),
"CONVERT(SMALLDATETIME, '2019-01-02 03:04:05', 20)",
)
......@@ -28,3 +28,16 @@ class MySQLEngineSpecsTestCase(DbEngineSpecTestCase):
"""Tests related to datatype mapping for MySQL"""
self.assertEqual("TINY", MySQLEngineSpec.get_datatype(1))
self.assertEqual("VARCHAR", MySQLEngineSpec.get_datatype(15))
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
MySQLEngineSpec.convert_dttm("DATE", dttm),
"STR_TO_DATE('2019-01-02', '%Y-%m-%d')",
)
self.assertEqual(
MySQLEngineSpec.convert_dttm("DATETIME", dttm),
"STR_TO_DATE('2019-01-02 03:04:05.678900', '%Y-%m-%d %H:%i:%s.%f')",
)
......@@ -34,3 +34,17 @@ class OracleTestCase(DbEngineSpecTestCase):
expr = OracleEngineSpec.get_timestamp_expr(col, None, "P1M")
result = str(expr.compile(dialect=oracle.dialect()))
self.assertEqual(result, "TRUNC(CAST(\"decimal\" as DATE), 'MONTH')")
dttm = self.get_dttm()
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
OracleEngineSpec.convert_dttm("DATE", dttm),
"TO_DATE('2019-01-02', 'YYYY-MM-DD')",
)
self.assertEqual(
OracleEngineSpec.convert_dttm("TIMESTAMP", dttm),
"""TO_TIMESTAMP('2019-01-02T03:04:05.678900', 'YYYY-MM-DD"T"HH24:MI:SS.ff6')""",
)
......@@ -70,3 +70,16 @@ class PostgresTests(DbEngineSpecTestCase):
expr = PostgresEngineSpec.get_timestamp_expr(col, None, "P1Y")
result = str(expr.compile(None, dialect=postgresql.dialect()))
self.assertEqual(result, "DATE_TRUNC('year', \"MixedCase\")")
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
PostgresEngineSpec.convert_dttm("DATE", dttm),
"TO_DATE('2019-01-02', 'YYYY-MM-DD')",
)
self.assertEqual(
PostgresEngineSpec.convert_dttm("TIMESTAMP", dttm),
"TO_TIMESTAMP('2019-01-02 03:04:05.678900', 'YYYY-MM-DD HH24:MI:SS.US')",
)
......@@ -341,3 +341,16 @@ class PrestoTests(DbEngineSpecTestCase):
)
query_result = str(result.compile(compile_kwargs={"literal_binds": True}))
self.assertEqual("SELECT \nWHERE ds = '01-01-19' AND hour = 1", query_result)
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
PrestoEngineSpec.convert_dttm("DATE", dttm),
"from_iso8601_date('2019-01-02')",
)
self.assertEqual(
PrestoEngineSpec.convert_dttm("TIMESTAMP", dttm),
"from_iso8601_timestamp('2019-01-02T03:04:05.678900')",
)
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from superset.db_engine_specs.sqlite import SqliteEngineSpec
from tests.db_engine_specs.base_tests import DbEngineSpecTestCase
class SQliteTestCase(DbEngineSpecTestCase):
def test_convert_dttm(self):
dttm = self.get_dttm()
self.assertEqual(
SqliteEngineSpec.convert_dttm("TEXT", dttm), "'2019-01-02 03:04:05.678900'"
)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册