diff --git a/README.md b/README.md index 7928904a2..3c03e9ac1 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,7 @@ Here are some of the major database solutions that are supported: oceanbase denodo ydb + TDengine

**A more comprehensive list of supported databases** along with the configuration instructions can be found [here](https://superset.apache.org/docs/configuration/databases). diff --git a/docs/docs/configuration/databases.mdx b/docs/docs/configuration/databases.mdx index 16af4451c..a9cbe0fa7 100644 --- a/docs/docs/configuration/databases.mdx +++ b/docs/docs/configuration/databases.mdx @@ -78,6 +78,7 @@ are compatible with Superset. | [Snowflake](/docs/configuration/databases#snowflake) | `pip install snowflake-sqlalchemy` | `snowflake://{user}:{password}@{account}.{region}/{database}?role={role}&warehouse={warehouse}` | | SQLite | No additional library needed | `sqlite://path/to/file.db?check_same_thread=false` | | [SQL Server](/docs/configuration/databases#sql-server) | `pip install pymssql` | `mssql+pymssql://` | +| [TDengine](/docs/configuration/databases#tdengine) | `pip install taospy` `pip install taos-ws-py` | `taosws://:@:` | | [Teradata](/docs/configuration/databases#teradata) | `pip install teradatasqlalchemy` | `teradatasql://{user}:{password}@{host}` | | [TimescaleDB](/docs/configuration/databases#timescaledb) | `pip install psycopg2` | `postgresql://:@:/` | | [Trino](/docs/configuration/databases#trino) | `pip install trino` | `trino://{username}:{password}@{hostname}:{port}/{catalog}` | @@ -1354,6 +1355,24 @@ starrocks://:@:/. StarRocks maintains their Superset docuementation [here](https://docs.starrocks.io/docs/integrations/BI_integrations/Superset/). ::: +#### TDengine + +[TDengine](https://www.tdengine.com) is a High-Performance, Scalable Time-Series Database for Industrial IoT and provides SQL-like query interface. + +The recommended connector library for TDengine is [taospy](https://pypi.org/project/taospy/) and [taos-ws-py](https://pypi.org/project/taos-ws-py/) + +The expected connection string is formatted as follows: + +``` +taosws://:@: +``` + +For example: + +``` +taosws://root:taosdata@127.0.0.1:6041 +``` + #### Teradata The recommended connector library is diff --git a/docs/static/img/tdengine.png b/docs/static/img/tdengine.png new file mode 100644 index 000000000..9d0088078 Binary files /dev/null and b/docs/static/img/tdengine.png differ diff --git a/pyproject.toml b/pyproject.toml index 0d93f9e96..892a2fea5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -173,6 +173,10 @@ spark = [ "tableschema", "thrift>=0.14.1, <1", ] +tdengine = [ + "taospy>=2.7.21", + "taos-ws-py>=0.3.8" +] teradata = ["teradatasql>=16.20.0.23"] thumbnails = ["Pillow>=10.0.1, <11"] vertica = ["sqlalchemy-vertica-python>=0.5.9, < 0.6"] diff --git a/superset/db_engine_specs/tdengine.py b/superset/db_engine_specs/tdengine.py new file mode 100644 index 000000000..f2910e422 --- /dev/null +++ b/superset/db_engine_specs/tdengine.py @@ -0,0 +1,57 @@ +# 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 __future__ import annotations + +from typing import Any +from urllib import parse + +from sqlalchemy.engine.url import make_url, URL # noqa: F401 + +from superset.db_engine_specs.base import BaseEngineSpec + + +class TDengineEngineSpec(BaseEngineSpec): + engine = "taosws" + engine_name = "TDengine" + max_column_name_length = 64 + default_driver = "taosws" + sqlalchemy_uri_placeholder = ( + "taosws://user:******@host:port/dbname[?key=value&key=value...]" + ) + + # time grain + _time_grain_expressions = { + None: "{col}", + "PT1S": "TIMETRUNCATE({col}, 1s, 0)", + "PT1M": "TIMETRUNCATE({col}, 1m, 0)", + "PT1H": "TIMETRUNCATE({col}, 1h, 0)", + "P1D": "TIMETRUNCATE({col}, 1d, 0)", + "P1W": "TIMETRUNCATE({col}, 1w, 0)", + } + + @classmethod + def get_schema_from_engine_params( + cls, + sqlalchemy_uri: URL, + connect_args: dict[str, Any], + ) -> str | None: + """ + Return the configured schema. + + A TDengine database is a SQLAlchemy schema. + """ + return parse.unquote(sqlalchemy_uri.database) diff --git a/tests/unit_tests/db_engine_specs/test_tdengine.py b/tests/unit_tests/db_engine_specs/test_tdengine.py new file mode 100644 index 000000000..f33cef5d6 --- /dev/null +++ b/tests/unit_tests/db_engine_specs/test_tdengine.py @@ -0,0 +1,34 @@ +# 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 sqlalchemy.engine.url import make_url, URL # noqa: F401 + + +# test get schema +def test_get_schema_from_engine_params() -> None: + """ + Test the ``get_schema_from_engine_params`` method. + """ + from superset.db_engine_specs.tdengine import TDengineEngineSpec + + assert ( + TDengineEngineSpec.get_schema_from_engine_params( + make_url("taosws://root:taosdata@127.0.0.1:6041/dbname"), {} + ) + == "dbname" + )